diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..125a163 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +vendor/quickjs-patches/series/*.patch whitespace=-blank-at-eol,-blank-at-eof,-space-before-tab diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 29e83aa..56bbab9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,6 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 - submodules: recursive - uses: pnpm/action-setup@v4 name: Install pnpm @@ -45,20 +44,88 @@ jobs: - run: pnpm install --frozen-lockfile + - name: Validate docs links + uses: lycheeverse/lychee-action@v2 + with: + args: > + --root-dir . + --offline + --no-progress + README.md + 'docs/**/*.md' + examples/README.md + fail: true + + - name: Run release evidence unit tests + run: pnpm release-evidence:test + - name: Install emsdk (pinned 3.1.56) run: bash tools/scripts/setup-emsdk.sh + - name: Verify QuickJS source reconstruction + run: | + pnpm quickjs-source:test + bash tools/scripts/check-quickjs-source-prep.sh + + - name: Verify generated gas schedule docs are in sync + run: | + pnpm gas-spec:test + node tools/gas-spec/render-gas-artifacts.mjs --check + - name: Reset Nx state (just in case) run: pnpm exec nx reset + - name: Clear TypeScript build state + run: | + find libs apps tools -name '*.tsbuildinfo' -delete + rm -rf libs/*/out-tsc apps/*/out-tsc tools/*/out-tsc + - uses: nrwl/nx-set-shas@v4 # Prepend any command with "nx-cloud record --" to record its logs to Nx Cloud # - run: pnpm exec nx-cloud record -- echo Hello World - - run: pnpm exec nx affected -t lint test build typecheck + - run: NX_DAEMON=false NX_NO_CLOUD=true pnpm exec nx affected -t lint test build typecheck --skip-nx-cache --output-style=stream + + - name: Run critical coverage threshold gate + run: NX_DAEMON=false NX_NO_CLOUD=true pnpm test:coverage:critical --skip-nx-cache --output-style=stream - - name: Install Playwright browsers (Chromium) - run: pnpm exec playwright install --with-deps chromium + - name: Upload critical coverage artifacts + if: always() + uses: actions/upload-artifact@v4 + with: + name: critical-vitest-coverage + path: | + libs/quickjs-runtime/test-output/vitest/coverage + libs/deterministic-bundler/test-output/vitest/coverage + libs/deterministic-builder/test-output/vitest/coverage + libs/abi-manifest/test-output/vitest/coverage + tools/blue-quickjs-cli/test-output/vitest/coverage + apps/ecosystem-certifier/test-output/vitest/coverage + if-no-files-found: ignore + + - name: Run native harness suites + run: | + pnpm nx test quickjs-native-harness + pnpm nx run quickjs-native-harness:test-legacy + + - name: Verify generated playground data is fresh + run: pnpm playground:check-generated + + - name: Install Playwright browsers (Chromium + Firefox) + run: pnpm exec playwright install --with-deps chromium firefox - name: Run smoke-web e2e run: pnpm nx run smoke-web:e2e + + - name: Run ecosystem certifier e2e + run: pnpm nx run ecosystem-certifier:e2e + + - name: Run BlueQuickjs playground e2e + run: pnpm nx run bluequickjs-playground:e2e + + - name: Generate workload certification sanity artifacts + run: | + node apps/ecosystem-certifier/scripts/check-builder-determinism.mjs --out-dir artifacts/workload-certification-ci + node apps/ecosystem-certifier/scripts/archive-workload-certification-report.mjs --out-dir artifacts/workload-certification-ci + node apps/ecosystem-certifier/scripts/run-oog-boundary-certification.mjs --out-dir artifacts/workload-certification-ci --fixtures green-semver,green-markdown-it + node apps/ecosystem-certifier/scripts/run-seeded-property-corpus.mjs --out-dir artifacts/workload-certification-ci --seed-count 12 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 69a412f..d058b59 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -26,14 +26,12 @@ jobs: with: ref: refs/tags/${{ inputs.tag }} fetch-depth: 0 - submodules: recursive - name: 'Checkout repository (push: current ref)' if: ${{ github.event_name != 'workflow_dispatch' }} uses: actions/checkout@v4 with: fetch-depth: 0 - submodules: recursive - uses: pnpm/action-setup@v4 name: Install pnpm diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f178e05..7f557cd 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,13 +17,12 @@ jobs: release: name: Release runs-on: ubuntu-latest - timeout-minutes: 10 + timeout-minutes: 45 steps: - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 - submodules: recursive ref: ${{ github.ref }} token: ${{ secrets.RELEASE_PAT }} @@ -51,9 +50,169 @@ jobs: - name: Install emsdk (pinned 3.1.56) run: bash tools/scripts/setup-emsdk.sh + - name: Verify QuickJS source reconstruction + run: | + pnpm quickjs-source:test + bash tools/scripts/check-quickjs-source-prep.sh + + - name: Verify generated gas schedule docs are in sync + run: node tools/gas-spec/render-gas-artifacts.mjs --check + + - name: Generate SBOM and dependency license reports + run: | + pnpm release-evidence:sbom -- --out-dir artifacts/security + pnpm release-evidence:licenses -- --out-dir artifacts/security + + - name: Install Playwright browsers (Chromium + Firefox) + run: pnpm exec playwright install --with-deps chromium firefox + - name: Print Environment Info run: pnpm exec nx report + - name: Run strict parity release gates (consensus executors) + run: | + pnpm nx test quickjs-runtime + pnpm nx test smoke-node + pnpm nx test test-harness + pnpm nx test bluequickjs-playground + pnpm nx run smoke-web:e2e + pnpm nx test ecosystem-certifier + pnpm nx run ecosystem-certifier:e2e + pnpm nx run bluequickjs-playground:e2e + + - name: Generate consensus reproducibility report artifacts (Chromium + Firefox) + run: | + node tools/consensus-parity/scripts/archive-consensus-reproducibility-report.mjs --out-dir artifacts/reproducibility-consensus/chromium --browser chromium + node tools/consensus-parity/scripts/archive-consensus-reproducibility-report.mjs --out-dir artifacts/reproducibility-consensus/firefox --browser firefox + + - name: Generate workload certification artifacts + run: | + node apps/ecosystem-certifier/scripts/check-builder-determinism.mjs --out-dir artifacts/workload-certification + node apps/ecosystem-certifier/scripts/archive-workload-certification-report.mjs --out-dir artifacts/workload-certification + node apps/ecosystem-certifier/scripts/generate-compatibility-delta-report.mjs --current-dir artifacts/workload-certification --out-dir artifacts/workload-certification + node apps/ecosystem-certifier/scripts/run-oog-boundary-certification.mjs --out-dir artifacts/workload-certification + node apps/ecosystem-certifier/scripts/run-seeded-property-corpus.mjs --out-dir artifacts/workload-certification --seed-count 80 + node apps/ecosystem-certifier/scripts/run-repeatability-certification.mjs --out-dir artifacts/workload-certification --iterations 100 --flagship-iterations 40 + + - name: Build public packages for packaging checks + run: pnpm nx run-many -t build --projects abi-manifest,dv,execution-profiles,quickjs-wasm-constants,quickjs-wasm,quickjs-runtime,deterministic-bundler,deterministic-builder + + - name: Validate public package release alignment + run: | + pnpm workload:check-public-package-coverage + pnpm workload:check-public-package-versions + pnpm workload:check-pack-manifests -- --out-dir artifacts/consumer-proof/pack-manifests + + - name: Run Verdaccio publish/install rehearsal (primary) + run: pnpm publish-rehearsal:verdaccio -- --out-dir artifacts/consumer-proof/verdaccio + + - name: Generate downstream tarball reproducibility artifacts (secondary) + run: | + node tools/workload-certification/pack-public-tarballs.mjs --out-dir artifacts/consumer-proof/tarballs + pnpm --dir e2e/consumer-proof-app run install:tarballs -- --tarball-dir ../../artifacts/consumer-proof/tarballs + node e2e/consumer-proof-app/node_modules/playwright/cli.js install --with-deps chromium + node e2e/consumer-proof-app/scripts/reproducibility-report.mjs + + - name: Run native diagnostics (non-blocking) + continue-on-error: true + run: | + pnpm nx build quickjs-native-harness + pnpm nx test quickjs-native-harness + pnpm nx run quickjs-native-harness:test-legacy + + - name: Generate native diagnostic reproducibility report artifact (non-blocking) + continue-on-error: true + run: node tools/quickjs-native-harness/scripts/archive-reproducibility-report.mjs + + - name: Synthesize release evidence bundle + run: pnpm release-evidence:synthesize -- --out-dir artifacts/release-evidence + + - name: Validate docs links + uses: lycheeverse/lychee-action@v2 + with: + args: > + --root-dir . + --offline + --no-progress + README.md + 'docs/**/*.md' + examples/README.md + fail: true + + - name: Validate generated release evidence and docs freshness + run: | + EXPECTED_DATE=$(node -e "const fs=require('fs');console.log(JSON.parse(fs.readFileSync('artifacts/release-evidence/release-evidence-manifest.json','utf8')).date)") + pnpm docs:check-freshness -- --expected-branch "${GITHUB_REF_NAME}" --expected-date "${EXPECTED_DATE}" + pnpm playground:check-generated + pnpm release-evidence:synthesize -- --out-dir artifacts/release-evidence --check + pnpm release-evidence:verify -- --evidence-dir artifacts/release-evidence --expected-branch "${GITHUB_REF_NAME}" --expected-date "${EXPECTED_DATE}" + + - name: Upload reproducibility artifacts + uses: actions/upload-artifact@v4 + with: + name: consensus-reproducibility-report + path: | + artifacts/reproducibility-consensus/**/*.json* + artifacts/reproducibility-consensus/**/*.md* + artifacts/reproducibility-consensus/**/*.sig + if-no-files-found: error + + - name: Upload native diagnostic reproducibility artifacts + uses: actions/upload-artifact@v4 + with: + name: native-diagnostic-reproducibility-report + path: | + artifacts/reproducibility/*.json* + artifacts/reproducibility/*.md* + artifacts/reproducibility/*.sig + if-no-files-found: warn + + - name: Upload workload certification artifacts + uses: actions/upload-artifact@v4 + with: + name: workload-certification-artifacts + path: artifacts/workload-certification/* + if-no-files-found: error + + - name: Upload consumer-proof artifacts + uses: actions/upload-artifact@v4 + with: + name: consumer-proof-artifacts + path: | + artifacts/consumer-proof/tarballs/tarball-manifest.json + artifacts/consumer-proof/pack-manifests/pack-manifest.json + artifacts/consumer-proof/verdaccio/*.json + artifacts/consumer-proof/verdaccio/*.log + e2e/consumer-proof-app/reports/*.json* + if-no-files-found: error + + - name: Upload release evidence bundle + uses: actions/upload-artifact@v4 + with: + name: release-evidence-bundle + path: | + artifacts/release-evidence/release-evidence-summary.json + artifacts/release-evidence/release-evidence-summary.json.sha256 + artifacts/release-evidence/release-evidence-summary.json.sig + artifacts/release-evidence/release-evidence-summary.md + artifacts/release-evidence/release-evidence-summary.md.sha256 + artifacts/release-evidence/release-evidence-summary.md.sig + artifacts/release-evidence/release-evidence-manifest.json + artifacts/release-evidence/release-evidence-manifest.json.sha256 + artifacts/release-evidence/release-evidence-manifest.json.sig + artifacts/release-evidence/inputs/* + if-no-files-found: error + + - name: Upload security artifacts + uses: actions/upload-artifact@v4 + with: + name: release-security-artifacts + path: | + artifacts/security/sbom.cdx.json + artifacts/security/license-report.json + artifacts/security/license-report.md + if-no-files-found: error + - name: Configure Git run: | git config --global user.email "github-actions[bot]@users.noreply.github.com" @@ -63,3 +222,47 @@ jobs: - name: Release run: pnpm exec nx release --skip-publish --first-release shell: bash + + verify-release-evidence: + name: Verify release evidence bundle + runs-on: ubuntu-latest + needs: + - release + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: pnpm/action-setup@v4 + with: + version: 9.8.0 + run_install: false + + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + cache: 'pnpm' + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Download release evidence bundle + uses: actions/download-artifact@v4 + with: + name: release-evidence-bundle + path: artifacts/release-evidence + + - name: Verify evidence checksums and signatures + run: | + EXPECTED_DATE=$(node -e "const fs=require('fs');console.log(JSON.parse(fs.readFileSync('artifacts/release-evidence/release-evidence-manifest.json','utf8')).date)") + pnpm release-evidence:verify -- --evidence-dir artifacts/release-evidence --expected-branch "${GITHUB_REF_NAME}" --expected-date "${EXPECTED_DATE}" + + - name: Assert tamper detection fails verification + run: | + cp -R artifacts/release-evidence artifacts/release-evidence-tampered + node -e "const fs=require('fs');fs.appendFileSync('artifacts/release-evidence-tampered/inputs/consumer-reproducibility.json','\n')" + EXPECTED_DATE=$(node -e "const fs=require('fs');console.log(JSON.parse(fs.readFileSync('artifacts/release-evidence-tampered/release-evidence-manifest.json','utf8')).date)") + if pnpm release-evidence:verify -- --evidence-dir artifacts/release-evidence-tampered --expected-branch "${GITHUB_REF_NAME}" --expected-date "${EXPECTED_DATE}"; then + echo "tamper verification unexpectedly passed" + exit 1 + fi diff --git a/.github/workflows/workload-certification.yml b/.github/workflows/workload-certification.yml new file mode 100644 index 0000000..5822ab9 --- /dev/null +++ b/.github/workflows/workload-certification.yml @@ -0,0 +1,331 @@ +name: Workload Certification + +on: + pull_request: + workflow_dispatch: + schedule: + - cron: '0 5 * * *' + +permissions: + actions: read + contents: read + +jobs: + certifier-browser-matrix: + name: Certifier (Linux parity, ${{ matrix.browser }}) + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + browser: + - chromium + - firefox + timeout-minutes: 45 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: pnpm/action-setup@v4 + with: + version: 9.8.0 + run_install: false + + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + cache: 'pnpm' + + - name: Cache emsdk + uses: actions/cache@v4 + with: + path: tools/emsdk + key: emsdk-${{ runner.os }}-${{ hashFiles('tools/scripts/emsdk-version.txt') }} + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Install emsdk + run: bash tools/scripts/setup-emsdk.sh + + - name: Install Playwright browser + run: pnpm exec playwright install --with-deps ${{ matrix.browser }} + + - name: Run ecosystem certifier tests + env: + PLAYWRIGHT_BROWSER: ${{ matrix.browser }} + run: | + pnpm nx test ecosystem-certifier + pnpm nx run ecosystem-certifier:e2e + + - name: Generate workload certification artifacts + run: | + ITERATIONS=50 + FLAGSHIP_ITERATIONS=20 + SEED_COUNT=40 + if [ "${{ github.event_name }}" = "schedule" ] && [ "${{ matrix.browser }}" = "chromium" ]; then + ITERATIONS=100 + FLAGSHIP_ITERATIONS=40 + SEED_COUNT=120 + fi + node apps/ecosystem-certifier/scripts/check-builder-determinism.mjs --out-dir artifacts/workload-certification + node apps/ecosystem-certifier/scripts/archive-workload-certification-report.mjs --out-dir artifacts/workload-certification --browser ${{ matrix.browser }} + node apps/ecosystem-certifier/scripts/generate-compatibility-delta-report.mjs --current-dir artifacts/workload-certification --out-dir artifacts/workload-certification + node apps/ecosystem-certifier/scripts/run-oog-boundary-certification.mjs --out-dir artifacts/workload-certification --browser ${{ matrix.browser }} + node apps/ecosystem-certifier/scripts/run-seeded-property-corpus.mjs --out-dir artifacts/workload-certification --seed-count "${SEED_COUNT}" --browser ${{ matrix.browser }} + node apps/ecosystem-certifier/scripts/run-repeatability-certification.mjs --out-dir artifacts/workload-certification --iterations "${ITERATIONS}" --flagship-iterations "${FLAGSHIP_ITERATIONS}" --browser ${{ matrix.browser }} + + - name: Upload workload certification artifacts + uses: actions/upload-artifact@v4 + with: + name: workload-certification-${{ matrix.browser }}-artifacts + path: artifacts/workload-certification/* + if-no-files-found: error + + certifier-webkit-diagnostic: + name: Certifier (Linux diagnostic, webkit) + if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' + runs-on: ubuntu-latest + timeout-minutes: 45 + continue-on-error: true + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: pnpm/action-setup@v4 + with: + version: 9.8.0 + run_install: false + + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + cache: 'pnpm' + + - name: Cache emsdk + uses: actions/cache@v4 + with: + path: tools/emsdk + key: emsdk-${{ runner.os }}-${{ hashFiles('tools/scripts/emsdk-version.txt') }} + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Install emsdk + run: bash tools/scripts/setup-emsdk.sh + + - name: Install Playwright browser (WebKit) + run: pnpm exec playwright install --with-deps webkit + + - name: Run webkit diagnostic workload report + run: node apps/ecosystem-certifier/scripts/archive-workload-certification-report.mjs --out-dir artifacts/workload-certification-webkit --browser webkit + + - name: Upload webkit diagnostic artifacts + uses: actions/upload-artifact@v4 + with: + name: workload-certification-webkit-diagnostic-artifacts + path: artifacts/workload-certification-webkit/* + if-no-files-found: warn + + consumer-proof-matrix: + name: Consumer proof (${{ matrix.os }}, node${{ matrix.node }}) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: + - ubuntu-latest + - windows-latest + node: + - 22 + timeout-minutes: 35 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: pnpm/action-setup@v4 + with: + version: 9.8.0 + run_install: false + + - uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node }} + cache: 'pnpm' + + - name: Cache emsdk + if: matrix.os == 'ubuntu-latest' + uses: actions/cache@v4 + with: + path: tools/emsdk + key: emsdk-${{ runner.os }}-${{ hashFiles('tools/scripts/emsdk-version.txt') }} + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Install emsdk + if: matrix.os == 'ubuntu-latest' + run: bash tools/scripts/setup-emsdk.sh + + - name: Build public packages for consumer proof (Linux) + if: matrix.os == 'ubuntu-latest' + run: pnpm nx run-many -t build --projects abi-manifest,dv,execution-profiles,quickjs-wasm-constants,quickjs-wasm,quickjs-runtime,deterministic-bundler,deterministic-builder + + - name: Build public packages for consumer proof (Windows) + if: matrix.os == 'windows-latest' + run: | + pnpm nx build quickjs-wasm-build + pnpm nx run-many -t build --projects abi-manifest,dv,execution-profiles,quickjs-wasm-constants,deterministic-bundler,deterministic-builder + pnpm nx build quickjs-wasm --excludeTaskDependencies + pnpm nx build quickjs-runtime --excludeTaskDependencies + + - name: Pack public tarballs + run: node tools/workload-certification/pack-public-tarballs.mjs --out-dir artifacts/consumer-proof/tarballs + + - name: Validate public package version alignment + run: | + pnpm workload:check-public-package-coverage + pnpm workload:check-public-package-versions + + - name: Validate npm pack manifests + run: pnpm workload:check-pack-manifests -- --out-dir artifacts/consumer-proof/pack-manifests + + - name: Install tarballs in consumer app + run: pnpm --dir e2e/consumer-proof-app run install:tarballs -- --tarball-dir ../../artifacts/consumer-proof/tarballs + + - name: Install Playwright browser (Linux) + if: matrix.os == 'ubuntu-latest' + run: node e2e/consumer-proof-app/node_modules/playwright/cli.js install --with-deps chromium + + - name: Install Playwright browser (non-Linux) + if: matrix.os != 'ubuntu-latest' + run: node e2e/consumer-proof-app/node_modules/playwright/cli.js install chromium + + - name: Run consumer reproducibility proof + run: node e2e/consumer-proof-app/scripts/reproducibility-report.mjs + + - name: Upload consumer-proof matrix artifacts + uses: actions/upload-artifact@v4 + with: + name: consumer-proof-${{ matrix.os }}-node${{ matrix.node }}-artifacts + path: | + artifacts/consumer-proof/tarballs/tarball-manifest.json + artifacts/consumer-proof/pack-manifests/pack-manifest.json + e2e/consumer-proof-app/reports/*.json* + if-no-files-found: error + + publish-rehearsal-verdaccio: + name: Publish rehearsal (Verdaccio) + runs-on: ubuntu-latest + timeout-minutes: 45 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: pnpm/action-setup@v4 + with: + version: 9.8.0 + run_install: false + + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: 'pnpm' + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Run Verdaccio publish/install rehearsal + run: pnpm publish-rehearsal:verdaccio -- --out-dir artifacts/consumer-proof/verdaccio + + - name: Upload Verdaccio rehearsal artifacts + uses: actions/upload-artifact@v4 + with: + name: consumer-proof-verdaccio-rehearsal-artifacts + path: | + artifacts/consumer-proof/verdaccio/*.json + artifacts/consumer-proof/verdaccio/*.log + e2e/consumer-proof-app/reports/*.json* + if-no-files-found: error + + builder-determinism-matrix: + name: Builder determinism (${{ matrix.os }}) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: + - ubuntu-latest + - macos-latest + - windows-latest + timeout-minutes: 20 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: pnpm/action-setup@v4 + with: + version: 9.8.0 + run_install: false + + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + cache: 'pnpm' + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build builder determinism dependencies + run: pnpm nx run-many -t build --projects execution-profiles,deterministic-bundler,deterministic-builder,abi-manifest + + - name: Run builder path determinism check + run: node apps/ecosystem-certifier/scripts/check-builder-determinism.mjs --out-dir artifacts/workload-certification-matrix + + - name: Upload builder determinism artifact + uses: actions/upload-artifact@v4 + with: + name: builder-determinism-${{ matrix.os }}-artifacts + path: artifacts/workload-certification-matrix/* + if-no-files-found: error + + builder-determinism-compare: + name: Compare builder determinism matrix + runs-on: ubuntu-latest + needs: + - builder-determinism-matrix + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: actions/download-artifact@v4 + with: + pattern: builder-determinism-* + path: artifacts/workload-certification-matrix + merge-multiple: false + + - name: Compare matrix reports + run: | + set +e + node tools/workload-certification/compare-builder-determinism-matrix.mjs --input-dir artifacts/workload-certification-matrix > artifacts/workload-certification-matrix-comparison.json + status=$? + echo "BUILDER_DETERMINISM_COMPARE_EXIT_CODE=${status}" >> "$GITHUB_ENV" + exit 0 + + - name: Upload matrix comparison artifact + uses: actions/upload-artifact@v4 + with: + name: builder-determinism-matrix-comparison + path: artifacts/workload-certification-matrix-comparison.json + if-no-files-found: error + + - name: Fail on matrix mismatches + if: env.BUILDER_DETERMINISM_COMPARE_EXIT_CODE != '0' + run: | + cat artifacts/workload-certification-matrix-comparison.json + exit 1 diff --git a/.gitignore b/.gitignore index 19e2874..fd5e1b1 100644 --- a/.gitignore +++ b/.gitignore @@ -48,4 +48,18 @@ Thumbs.db vite.config.*.timestamp* vitest.config.*.timestamp* -.repomix \ No newline at end of file +.repomix + +# Playwright outputs +test-results +playwright-report + +# Downstream consumer proof outputs +e2e/consumer-proof-app/node_modules/ +e2e/consumer-proof-app/.npm-cache/ +e2e/consumer-proof-app/reports/ +e2e/consumer-proof-app/package-lock.json +artifacts/ +vendor/.quickjs-cache/ +vendor/quickjs/ +test-output/ \ No newline at end of file diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 97c05d1..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "vendor/quickjs"] - path = vendor/quickjs - url = git@github.com:bluecontract/quickjs.git diff --git a/.verdaccio/config.yml b/.verdaccio/config.yml index f74420f..96049fa 100644 --- a/.verdaccio/config.yml +++ b/.verdaccio/config.yml @@ -8,6 +8,11 @@ uplinks: maxage: 60m packages: + '@blue-quickjs/*': + access: $all + publish: $all + unpublish: $all + '**': # give all users (including non-authenticated users) full access # because it is a local registry diff --git a/AGENTS.md b/AGENTS.md index a834e91..caa1074 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -13,7 +13,7 @@ Key locations: - **Apps**: `apps/*` (e.g. browser and node smoke projects) - **Libraries**: `libs/*` (e.g. DV, wasm runtime/build, test harness) - **Tooling**: `tools/*` (e.g. native harness, emsdk bootstrap scripts) -- **QuickJS fork pin**: `vendor/quickjs` (git submodule) +- **QuickJS fork patches**: `vendor/quickjs-patches` (applied onto clean upstream source) - **Specs/docs**: `docs/*` (determinism profile, gas schedule, DV wire format, host ABI) ## Environment expectations diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b14f8b..8b48e53 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,29 @@ +## 0.5.0-rc.0 (2026-03-19) + +### 🚀 Features + +- **release-policy:** promote strict gas/OOG parity to release-critical + consensus contract for `wasm-node` vs `wasm-browser`. +- **ecosystem-certifier:** add flagship workload certification, deterministic + green/red compatibility matrix, builder determinism evidence, and downstream + consumer-proof integration. +- **ecosystem-certifier:** expand green corpus to 25 fixtures, add + compatibility delta reporting, and raise repeatability/seeded workload + intensity for release/nightly runs. +- **release-workflow:** run strict consensus parity gates and archive workload + + consumer evidence artifacts in release workflow. +- **playground:** add an in-repo BlueQuickjs playground backed by generated + certified examples, red fixtures, and OOG boundary data. + +### 📚 Documentation + +- Promote README into a product/release landing page with consensus-safe scope, + execution profiles, and quickstart. +- Add architecture overview, guided learning path, glossary/FAQ/support pages, + and playground docs. +- Refresh docs index, head verification note, and release-facing checklists for + release-readiness and verification-oriented navigation. + ## 0.4.1 (2026-03-13) ### 🚀 Features diff --git a/README.md b/README.md index dc9a1d5..a9d5634 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,98 @@ # BlueQuickjs -Deterministic QuickJS-in-Wasm evaluator monorepo (Nx + pnpm), tracking a hardened QuickJS fork and SDK/tooling to run it. +BlueQuickjs is a deterministic JavaScript execution stack for +consensus-critical workloads. It runs a hardened QuickJS engine compiled to +Wasm and is designed so independent runtimes produce the same observable result +for the same input: + +- returned value or error, +- gas used and gas remaining, +- host-call tape, +- exact out-of-gas boundary. + +## Quick Start + +1. **Install dependencies and the pinned Wasm toolchain** + + ```bash + pnpm run setup + ``` + +2. **Run the current consensus smoke checks** + + ```bash + pnpm verify + ``` + +3. **Generate parity and certification evidence** + + ```bash + pnpm evidence + ``` + +4. **Verify the release evidence bundle** + + ```bash + pnpm evidence:verify + ``` + +5. **Open the in-repo browser playground** + + ```bash + pnpm run playground + ``` + +## Read Next + +- [Docs index](docs/README.md) +- [Core concepts](docs/concepts.md) +- [TypeScript SDK usage](docs/sdk.md) +- [Production embedder checklist](docs/production-embedder-checklist.md) +- [Examples corpus](examples/README.md) + +## Consensus Scope + +The current release makes a narrow, explicit consensus guarantee: + +- `wasm-node` and `wasm-browser` must agree. +- Only the canonical `wasm32` release build is consensus-safe. +- Native builds are diagnostic-only unless release policy explicitly promotes + them. + +The consensus result includes returned value or error, gas used and remaining, +host-call tape, and the exact out-of-gas boundary. + +## Execution Profiles + +| Profile | Use when | +| --- | --- | +| `baseline-v1` | You need the smallest deterministic JS surface. | +| `compat-general-v1` | You need deterministic RegExp, Promise jobs, console output, or stable sort. | +| `compat-binary-v1` | You need typed arrays, `ArrayBuffer`, `DataView`, or DV2 byte boundaries. | + +Details: [Execution profiles](docs/execution-profiles.md). + +## Consumer and operator proof paths + +BlueQuickjs exercises two public-consumer rehearsal flows: + +- **tarball flow**: pack public tarballs and install them into the consumer + proof app. +- **registry/Verdaccio rehearsal flow**: publish to a local registry and run the + same consumer proof against that path. + +See [Workload certification](docs/workload-certification.md) and +[Release checklist](docs/release-checklist.md). ## QuickJS fork -- Submodule at `vendor/quickjs` (origin `git@blue.github.com:mjwebblue/quickjs.git`). -- Fresh checkout: `git submodule update --init --recursive`. -- Update the pin after landing changes in the fork: `cd vendor/quickjs && git fetch origin && git checkout ` then `cd .. && git add vendor/quickjs && git commit -m "chore: bump quickjs submodule"`. -- Do QuickJS edits in the fork repository and only commit the pinned SHA here. +- Patch series lives in `vendor/quickjs-patches/series`. +- `vendor/quickjs` is generated from upstream QuickJS base + `e5fd3918c1c4a2ee39016e71b66a9eeda85ce716` plus that patch series. +- Fresh checkout: run `pnpm setup` or + `bash tools/scripts/prepare-quickjs-source.sh`. +- Update fork behavior by exporting a new patch series and regenerating + `vendor/quickjs`; do not commit generated QuickJS source. ## Workspace basics @@ -18,25 +103,22 @@ Deterministic QuickJS-in-Wasm evaluator monorepo (Nx + pnpm), tracking a hardene ## Toolchain -- Emscripten is pinned to `3.1.56`; install via `tools/scripts/setup-emsdk.sh`, then `source tools/emsdk/emsdk_env.sh`. See `docs/toolchain.md` for details and CI cache notes. +Emscripten is pinned to `3.1.56`. For normal local setup, run `pnpm setup`; it +installs the pinned SDK and loads it for the setup flow. For manual shell usage, +source `tools/emsdk/emsdk_env.sh` before running Wasm build commands, or wrap a +one-off command with `tools/scripts/with-emsdk.sh`, for example: -## Docs +```bash +tools/scripts/with-emsdk.sh pnpm nx build quickjs-wasm-build +``` -- Baselines (start here): - - Baseline #1 — Deterministic execution + canonical gas: `docs/baseline-1.md` - - Baseline #2 — Host ABI (manifest-locked) + DV wire format: `docs/baseline-2.md` -- Determinism profile: `docs/determinism-profile.md` -- Gas schedule: `docs/gas-schedule.md` -- DV wire format: `docs/dv-wire-format.md` -- ABI manifest: `docs/abi-manifest.md` -- Host call ABI: `docs/host-call-abi.md` -- Release policy: `docs/release-policy.md` -- Release checklist: `docs/release-checklist.md` +See [Toolchain](docs/toolchain.md) for details and CI cache notes. ## Determinism checklist -- Same `(P, I, G)` yields identical result bytes, gas used/remaining, and host-call tape hashes across Node and browser. -- Deterministic capability profile: time/random/async/IO/typed arrays/WebAssembly disabled; use `Host.v1` for IO (`docs/determinism-profile.md`). -- Canonical gas: opcode/builtin/allocation/GC charges plus two-phase host-call gas (`docs/gas-schedule.md`). -- DV and manifest: canonical DV encoding, safe numeric range, sorted keys, size caps, manifest hash pinning (`docs/dv-wire-format.md`, `docs/abi-manifest.md`). -- Host ABI: `host_call` envelope, deterministic error mapping, and reentrancy rules (`docs/host-call-abi.md`). +- Same `(P, I, G)` yields identical result bytes, gas used and remaining, and + host-call tape hashes across Node and browser. +- Deterministic capability profiles enforce explicit contracts per profile. +- Canonical gas is metered inside the engine, including host-call gas. +- DV and manifest hashes pin the host boundary contract. +- Release evidence is generated and verified, not hand-maintained. diff --git a/apps/bluequickjs-playground/eslint.config.mjs b/apps/bluequickjs-playground/eslint.config.mjs new file mode 100644 index 0000000..0232736 --- /dev/null +++ b/apps/bluequickjs-playground/eslint.config.mjs @@ -0,0 +1,8 @@ +import baseConfig from '../../eslint.config.mjs'; + +export default [ + ...baseConfig, + { + ignores: ['**/out-tsc'], + }, +]; diff --git a/apps/bluequickjs-playground/index.html b/apps/bluequickjs-playground/index.html new file mode 100644 index 0000000..0f552ce --- /dev/null +++ b/apps/bluequickjs-playground/index.html @@ -0,0 +1,12 @@ + + + + + + BlueQuickjs Playground + + +
Loading BlueQuickjs Playground…
+ + + diff --git a/apps/bluequickjs-playground/package.json b/apps/bluequickjs-playground/package.json new file mode 100644 index 0000000..50f7d50 --- /dev/null +++ b/apps/bluequickjs-playground/package.json @@ -0,0 +1,46 @@ +{ + "name": "@blue-quickjs/bluequickjs-playground", + "version": "0.0.1", + "type": "module", + "private": true, + "dependencies": { + "@blue-quickjs/abi-manifest": "workspace:*", + "@blue-quickjs/deterministic-builder": "workspace:*", + "@blue-quickjs/dv": "workspace:*", + "@blue-quickjs/execution-profiles": "workspace:*", + "@blue-quickjs/quickjs-runtime": "workspace:*", + "@blue-quickjs/quickjs-wasm": "workspace:*", + "@blue-quickjs/test-harness": "workspace:*", + "monaco-editor": "^0.55.1", + "tslib": "^2.3.0" + }, + "nx": { + "name": "bluequickjs-playground", + "targets": { + "e2e": { + "dependsOn": [ + "^build" + ], + "executor": "nx:run-commands", + "options": { + "command": "pnpm playwright test apps/bluequickjs-playground/tests --config apps/bluequickjs-playground/playwright.config.cts", + "cwd": "." + } + }, + "generate-data": { + "executor": "nx:run-commands", + "options": { + "command": "node apps/bluequickjs-playground/scripts/generate-playground-data.mjs", + "cwd": "." + } + }, + "check-generated": { + "executor": "nx:run-commands", + "options": { + "command": "node apps/bluequickjs-playground/scripts/generate-playground-data.mjs --check", + "cwd": "." + } + } + } + } +} diff --git a/apps/bluequickjs-playground/playwright.config.cts b/apps/bluequickjs-playground/playwright.config.cts new file mode 100644 index 0000000..3f80282 --- /dev/null +++ b/apps/bluequickjs-playground/playwright.config.cts @@ -0,0 +1,30 @@ +import { defineConfig } from '@playwright/test'; + +const projectRoot = __dirname; + +export default defineConfig({ + testDir: './tests', + fullyParallel: false, + timeout: 120000, + use: { + headless: true, + baseURL: 'http://localhost:4325', + }, + projects: [ + { + name: 'chromium', + use: { browserName: 'chromium' }, + }, + { + name: 'firefox', + use: { browserName: 'firefox' }, + }, + ], + webServer: { + command: 'pnpm vite --host --port 4325 --config vite.config.mts', + cwd: projectRoot, + url: 'http://localhost:4325', + reuseExistingServer: !process.env.CI, + timeout: 120000, + }, +}); diff --git a/apps/bluequickjs-playground/public/generated/playground-evidence.json b/apps/bluequickjs-playground/public/generated/playground-evidence.json new file mode 100644 index 0000000..fbaf827 --- /dev/null +++ b/apps/bluequickjs-playground/public/generated/playground-evidence.json @@ -0,0 +1,287 @@ +{ + "generatedAt": "current-worktree", + "metadata": { + "engineBuildHash": "f91091cb7feb788df340305a877a9cadb0c6f4d13aea8a7da4040b6367d178ea", + "gasVersion": 8 + }, + "evidence": { + "example-basic-script": { + "stage": "success", + "resultHash": "4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a", + "errorCode": null, + "errorTag": null, + "gasUsed": "74", + "gasRemaining": "999926", + "tapeHash": null, + "tapeLength": 0, + "certified": true, + "reportSource": "examples/01-basic-script", + "fixtureCoverage": [ + { + "suite": "gas-sample", + "fixtureName": "return-1" + } + ] + }, + "example-module-pack": { + "stage": "success", + "resultHash": "ca358758f6d27e6cf45272937977a748fd88391db679ceda7dc7bf1f005ee879", + "errorCode": null, + "errorTag": null, + "gasUsed": "147", + "gasRemaining": "49853", + "tapeHash": null, + "tapeLength": 0, + "certified": true, + "reportSource": "examples/02-module-pack", + "fixtureCoverage": [ + { + "suite": "module-pack", + "fixtureName": "module-pack-default-export" + } + ] + }, + "example-library-reuse": { + "stage": "success", + "resultHash": "2017ff3461395672aa0aa4f64894fd2f95a4b120e2690e8951656d79adc2eed2", + "errorCode": null, + "errorTag": null, + "gasUsed": "2070505", + "gasRemaining": "2929495", + "tapeHash": null, + "tapeLength": 0, + "certified": true, + "reportSource": "examples/03-library-reuse", + "fixtureCoverage": [ + { + "suite": "chess-library", + "fixtureName": "chess-e2e6" + }, + { + "suite": "binary-library", + "fixtureName": "base64-js-roundtrip" + }, + { + "suite": "binary-library", + "fixtureName": "noble-sha256-hex" + } + ] + }, + "example-promises-async": { + "stage": "success", + "resultHash": "7f83f7bda2d63959d34767689f06d47576683d378d9eb8d09386c9a020395c53", + "errorCode": null, + "errorTag": null, + "gasUsed": "128", + "gasRemaining": "49872", + "tapeHash": null, + "tapeLength": 0, + "certified": true, + "reportSource": "examples/04-promises-async", + "fixtureCoverage": [ + { + "suite": "determinism", + "fixtureName": "async-promise-chain" + } + ] + }, + "example-promises-library-host": { + "stage": "success", + "resultHash": "7f83f7bda2d63959d34767689f06d47576683d378d9eb8d09386c9a020395c53", + "errorCode": null, + "errorTag": null, + "gasUsed": "290", + "gasRemaining": "99710", + "tapeHash": "a60c7561730c64206ffefbef8a581959560436b8e06f481d25131684ce529790", + "tapeLength": 1, + "certified": true, + "reportSource": "examples/05-promises-library-host", + "fixtureCoverage": [ + { + "suite": "module-pack", + "fixtureName": "module-pack-async-import-host-call" + } + ] + }, + "example-binary-host-v2": { + "stage": "success", + "resultHash": "a538717d219fa0484c601ef7b5b63704c90cb9ae0406495b9f0083989a9fb2f8", + "errorCode": null, + "errorTag": null, + "gasUsed": "253", + "gasRemaining": "49747", + "tapeHash": "b2d3a3b07a1be6b39cd854077910a2bc839c281281275c2c137f6a704723a734", + "tapeLength": 2, + "certified": true, + "reportSource": "examples/06-binary-host-v2", + "fixtureCoverage": [ + { + "suite": "determinism", + "fixtureName": "compat-binary-host-v2-bytes-roundtrip" + } + ] + }, + "example-console-shim": { + "stage": "success", + "resultHash": "20a934991093b3d9bfcb5f3c05871eb1db002d19469c29ea3ae1ff7e4a29cd02", + "errorCode": null, + "errorTag": null, + "gasUsed": "139", + "gasRemaining": "49861", + "tapeHash": "c481a1396ab5097cc8aa68fd11c1bb6e96d63259dba00b560bf49489fe5b2e3f", + "tapeLength": 1, + "certified": true, + "reportSource": "examples/07-console-shim", + "fixtureCoverage": [ + { + "suite": "determinism", + "fixtureName": "compat-console-shim" + } + ] + }, + "example-stable-sort": { + "stage": "success", + "resultHash": "950f57b0bb4280b09b5a63004acc9c50811ca16cea7c932494f47cb3cfb23c04", + "errorCode": null, + "errorTag": null, + "gasUsed": "1020", + "gasRemaining": "98980", + "tapeHash": null, + "tapeLength": 0, + "certified": true, + "reportSource": "examples/08-stable-sort", + "fixtureCoverage": [ + { + "suite": "determinism", + "fixtureName": "compat-stable-sort" + } + ] + }, + "example-kitchen-sink": { + "stage": "success", + "resultHash": "81c484749a779eed55f5556d116e42d167df403c6800f9a543228d459d2cee75", + "errorCode": null, + "errorTag": null, + "gasUsed": "1390", + "gasRemaining": "198610", + "tapeHash": "39a88fa80e264d1836759dd547e397ea79508e761caea5b4e393f9aeeb5cdee3", + "tapeLength": 3, + "certified": true, + "reportSource": "examples/09-kitchen-sink", + "fixtureCoverage": [ + { + "suite": "module-pack", + "fixtureName": "module-pack-kitchen-sink" + } + ] + }, + "example-max-gas-policy": { + "stage": "success", + "resultHash": "a3fa3495623f19996818ce7b196fc524e687ef2cc4910a6ff628a76460c4e557", + "errorCode": null, + "errorTag": null, + "gasUsed": "170099", + "gasRemaining": "829901", + "tapeHash": null, + "tapeLength": 0, + "certified": true, + "reportSource": "examples/10-max-gas-policy", + "fixtureCoverage": [ + { + "suite": "gas-boundary", + "fixtureName": "loop-10k" + } + ] + }, + "green-semver": { + "stage": "success", + "resultHash": "0f772d5874a1d5da187a42d18a36eef020a8a20be43e106cccd6b35bd7589913", + "errorCode": null, + "errorTag": null, + "gasUsed": "36886", + "gasRemaining": "963114", + "tapeHash": "cb2a385dddf91f104061c25073236d1518b4d87ff10a4c8a40deda856410deb0", + "tapeLength": 1, + "certified": true, + "reportSource": "ecosystem-certifier:green-semver", + "fixtureCoverage": [ + { + "suite": "ecosystem-certifier", + "fixtureName": "green-semver" + } + ] + }, + "green-base64": { + "stage": "success", + "resultHash": "87dbcca4f5403c38f1d4259ba4d152240ab993b6d54d2bc5be615294634398d2", + "errorCode": null, + "errorTag": null, + "gasUsed": "3378", + "gasRemaining": "4996622", + "tapeHash": null, + "tapeLength": 0, + "certified": true, + "reportSource": "ecosystem-certifier:green-base64", + "fixtureCoverage": [ + { + "suite": "ecosystem-certifier", + "fixtureName": "green-base64" + } + ] + }, + "green-markdown-it": { + "stage": "success", + "resultHash": "e066b59858afb2601fec42a0a29527508545e9e21b84770d5dfb092d70da85d0", + "errorCode": null, + "errorTag": null, + "gasUsed": "212292", + "gasRemaining": "787708", + "tapeHash": "c8bebb3029ad855bc4972ad0a6de535daf1b7f13e1ca3ddbd458038afb4f2904", + "tapeLength": 1, + "certified": true, + "reportSource": "ecosystem-certifier:green-markdown-it", + "fixtureCoverage": [ + { + "suite": "ecosystem-certifier", + "fixtureName": "green-markdown-it" + } + ] + }, + "green-noble-sha": { + "stage": "success", + "resultHash": "137c77da6a39cb7439836094805726f43751c3d4df281f9268ba4bf03b523afd", + "errorCode": null, + "errorTag": null, + "gasUsed": "25631", + "gasRemaining": "4974369", + "tapeHash": null, + "tapeLength": 0, + "certified": true, + "reportSource": "ecosystem-certifier:green-noble-sha", + "fixtureCoverage": [ + { + "suite": "ecosystem-certifier", + "fixtureName": "green-noble-sha" + } + ] + }, + "flagship-knowledge-pack": { + "stage": "success", + "resultHash": "098e33e655dc8d5539e5628bcb03649cc952103b12ebd942a99e5dba0e2417b8", + "errorCode": null, + "errorTag": null, + "gasUsed": "3280236", + "gasRemaining": "4719764", + "tapeHash": "1f5a6804fd52594adfbab5c3292076aeeaec340c2232eb7cdbe5d90dfd1560b7", + "tapeLength": 12, + "certified": true, + "reportSource": "ecosystem-certifier:flagship-knowledge-pack", + "fixtureCoverage": [ + { + "suite": "ecosystem-certifier", + "fixtureName": "flagship-knowledge-pack" + } + ] + } + } +} diff --git a/apps/bluequickjs-playground/public/generated/playground-examples.json b/apps/bluequickjs-playground/public/generated/playground-examples.json new file mode 100644 index 0000000..b6493ac --- /dev/null +++ b/apps/bluequickjs-playground/public/generated/playground-examples.json @@ -0,0 +1,3054 @@ +{ + "generatedAt": "current-worktree", + "metadata": { + "engineBuildHash": "f91091cb7feb788df340305a877a9cadb0c6f4d13aea8a7da4040b6367d178ea", + "gasVersion": 8, + "wasmVariant": "wasm32", + "wasmBuildType": "release" + }, + "examples": [ + { + "id": "example-basic-script", + "title": "Basic deterministic script", + "kind": "example", + "badge": "Example 1", + "description": "Smallest possible deterministic script-mode example.", + "certified": true, + "executionProfile": "baseline-v1", + "sourceKind": "script", + "abiId": "Host.v1", + "gasLimit": "1000000", + "sourcePaths": [ + "examples/01-basic-script/program.js" + ], + "sourceText": "(() => 1)();\n", + "hostPreset": "determinism", + "hostSummary": { + "label": "Determinism fixture host", + "description": "Provides stable Host.v1/Host.v2 document responses plus deterministic emit tape capture.", + "documents": [ + "path/to/doc", + "path/to/canonical", + "path/to/first", + "path/to/second", + "path/to/third", + "bytes/payload" + ] + }, + "docsLinks": [ + { + "label": "Learn path", + "href": "/docs/learn/README.md" + }, + { + "label": "Examples corpus", + "href": "/examples/README.md" + } + ], + "supportsOogSearch": true, + "program": { + "version": 2, + "abiId": "Host.v1", + "abiVersion": 1, + "abiManifestHash": "e23b0b2ee169900bbde7aff78e6ce20fead1715c60f8a8e3106d9959450a3d34", + "executionProfile": "baseline-v1", + "sourceKind": "script", + "source": { + "code": "(() => 1)();\n" + }, + "engineBuildHash": "f91091cb7feb788df340305a877a9cadb0c6f4d13aea8a7da4040b6367d178ea", + "gasVersion": 8 + }, + "manifest": { + "abi_id": "Host.v1", + "abi_version": 1, + "functions": [ + { + "fn_id": 1, + "js_path": [ + "document", + "get" + ], + "effect": "READ", + "arity": 1, + "arg_schema": [ + { + "type": "string" + } + ], + "return_schema": { + "type": "dv" + }, + "gas": { + "schedule_id": "doc-read-v1", + "base": 20, + "k_arg_bytes": 1, + "k_ret_bytes": 1, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 4096, + "max_response_bytes": 262144, + "max_units": 1000, + "arg_utf8_max": [ + 2048 + ] + }, + "error_codes": [ + { + "code": "INVALID_PATH", + "tag": "host/invalid_path" + }, + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + }, + { + "code": "NOT_FOUND", + "tag": "host/not_found" + } + ] + }, + { + "fn_id": 2, + "js_path": [ + "document", + "getCanonical" + ], + "effect": "READ", + "arity": 1, + "arg_schema": [ + { + "type": "string" + } + ], + "return_schema": { + "type": "dv" + }, + "gas": { + "schedule_id": "doc-read-v1", + "base": 20, + "k_arg_bytes": 1, + "k_ret_bytes": 1, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 4096, + "max_response_bytes": 262144, + "max_units": 1000, + "arg_utf8_max": [ + 2048 + ] + }, + "error_codes": [ + { + "code": "INVALID_PATH", + "tag": "host/invalid_path" + }, + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + }, + { + "code": "NOT_FOUND", + "tag": "host/not_found" + } + ] + }, + { + "fn_id": 3, + "js_path": [ + "emit" + ], + "effect": "EMIT", + "arity": 1, + "arg_schema": [ + { + "type": "dv" + } + ], + "return_schema": { + "type": "null" + }, + "gas": { + "schedule_id": "emit-v1", + "base": 5, + "k_arg_bytes": 1, + "k_ret_bytes": 0, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 32768, + "max_response_bytes": 64, + "max_units": 1024 + }, + "error_codes": [ + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + } + ] + } + ] + } + }, + { + "id": "example-module-pack", + "title": "Standard ESM module-pack", + "kind": "example", + "badge": "Example 2", + "description": "Static ESM module-pack example with a deterministic graph hash.", + "certified": true, + "executionProfile": "baseline-v1", + "sourceKind": "module-pack", + "abiId": "Host.v1", + "gasLimit": "50000", + "sourcePaths": [ + "examples/02-module-pack/entry.js", + "examples/02-module-pack/values.js" + ], + "sourceText": "import { base } from './values.js';\n\nexport default base + 1;\n", + "hostPreset": "determinism", + "hostSummary": { + "label": "Determinism fixture host", + "description": "Provides stable Host.v1/Host.v2 document responses plus deterministic emit tape capture.", + "documents": [ + "path/to/doc", + "path/to/canonical", + "path/to/first", + "path/to/second", + "path/to/third", + "bytes/payload" + ] + }, + "docsLinks": [ + { + "label": "Learn path", + "href": "/docs/learn/README.md" + }, + { + "label": "Examples corpus", + "href": "/examples/README.md" + }, + { + "label": "Module packs", + "href": "/docs/learn/03-module-packs-and-imports.md" + } + ], + "supportsOogSearch": true, + "program": { + "version": 2, + "abiId": "Host.v1", + "abiVersion": 1, + "abiManifestHash": "e23b0b2ee169900bbde7aff78e6ce20fead1715c60f8a8e3106d9959450a3d34", + "engineBuildHash": "f91091cb7feb788df340305a877a9cadb0c6f4d13aea8a7da4040b6367d178ea", + "gasVersion": 8, + "executionProfile": "baseline-v1", + "sourceKind": "module-pack", + "source": { + "modulePack": { + "version": 1, + "entrySpecifier": "./entry.js", + "entryExport": "default", + "modules": [ + { + "specifier": "./entry.js", + "source": "// examples/02-module-pack/values.js\nvar base = 6;\n\n// examples/02-module-pack/entry.js\nvar entry_default = base + 1;\nexport {\n entry_default as default\n};\n", + "sourceMap": "{\"mappings\":\";AAAO,IAAM,OAAO;;;ACEpB,IAAO,gBAAQ,OAAO;\",\"names\":[],\"sources\":[\"../examples/02-module-pack/values.js\",\"../examples/02-module-pack/entry.js\"],\"sourcesContent\":[\"export const base = 6;\\n\",\"import { base } from './values.js';\\n\\nexport default base + 1;\\n\"],\"version\":3}", + "originMeta": { + "originalPath": "examples/02-module-pack/entry.js" + } + } + ], + "builderVersion": "deterministic-builder-v1", + "dependencyIntegrity": "483aad47a5ae3669a320d313a6ce1be9be705b5c52775cba1b4f45d1fada0562", + "diagnosticsMeta": { + "entryPath": "/workspace/examples/02-module-pack/entry.js", + "modulePaths": [ + "./entry.js" + ] + }, + "graphHash": "73f5f34c3f965a90d50b923534cb9afd11cbcee8e9b28111724f1b5c73e7c712" + } + } + }, + "manifest": { + "abi_id": "Host.v1", + "abi_version": 1, + "functions": [ + { + "fn_id": 1, + "js_path": [ + "document", + "get" + ], + "effect": "READ", + "arity": 1, + "arg_schema": [ + { + "type": "string" + } + ], + "return_schema": { + "type": "dv" + }, + "gas": { + "schedule_id": "doc-read-v1", + "base": 20, + "k_arg_bytes": 1, + "k_ret_bytes": 1, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 4096, + "max_response_bytes": 262144, + "max_units": 1000, + "arg_utf8_max": [ + 2048 + ] + }, + "error_codes": [ + { + "code": "INVALID_PATH", + "tag": "host/invalid_path" + }, + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + }, + { + "code": "NOT_FOUND", + "tag": "host/not_found" + } + ] + }, + { + "fn_id": 2, + "js_path": [ + "document", + "getCanonical" + ], + "effect": "READ", + "arity": 1, + "arg_schema": [ + { + "type": "string" + } + ], + "return_schema": { + "type": "dv" + }, + "gas": { + "schedule_id": "doc-read-v1", + "base": 20, + "k_arg_bytes": 1, + "k_ret_bytes": 1, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 4096, + "max_response_bytes": 262144, + "max_units": 1000, + "arg_utf8_max": [ + 2048 + ] + }, + "error_codes": [ + { + "code": "INVALID_PATH", + "tag": "host/invalid_path" + }, + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + }, + { + "code": "NOT_FOUND", + "tag": "host/not_found" + } + ] + }, + { + "fn_id": 3, + "js_path": [ + "emit" + ], + "effect": "EMIT", + "arity": 1, + "arg_schema": [ + { + "type": "dv" + } + ], + "return_schema": { + "type": "null" + }, + "gas": { + "schedule_id": "emit-v1", + "base": 5, + "k_arg_bytes": 1, + "k_ret_bytes": 0, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 32768, + "max_response_bytes": 64, + "max_units": 1024 + }, + "error_codes": [ + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + } + ] + } + ] + } + }, + { + "id": "example-library-reuse", + "title": "Real npm library reuse", + "kind": "example", + "badge": "Example 3", + "description": "Real library reuse through a deterministic module-pack instead of runtime imports. The binary base64 companion source remains listed alongside the chess.js entry for comparison.", + "certified": true, + "executionProfile": "compat-general-v1", + "sourceKind": "module-pack", + "abiId": "Host.v1", + "gasLimit": "5000000", + "sourcePaths": [ + "examples/03-library-reuse/chess-entry.ts", + "examples/03-library-reuse/binary-base64-entry.ts" + ], + "sourceText": "import { Chess } from 'chess.js';\n\nconst game = new Chess();\ngame.move('e4');\ngame.move('e5');\n\nexport default game.move('e2e6') !== null;\n", + "hostPreset": "determinism", + "hostSummary": { + "label": "Determinism fixture host", + "description": "Provides stable Host.v1/Host.v2 document responses plus deterministic emit tape capture.", + "documents": [ + "path/to/doc", + "path/to/canonical", + "path/to/first", + "path/to/second", + "path/to/third", + "bytes/payload" + ] + }, + "docsLinks": [ + { + "label": "Learn path", + "href": "/docs/learn/README.md" + }, + { + "label": "Examples corpus", + "href": "/examples/README.md" + } + ], + "supportsOogSearch": true, + "program": { + "version": 2, + "abiId": "Host.v1", + "abiVersion": 1, + "abiManifestHash": "e23b0b2ee169900bbde7aff78e6ce20fead1715c60f8a8e3106d9959450a3d34", + "engineBuildHash": "f91091cb7feb788df340305a877a9cadb0c6f4d13aea8a7da4040b6367d178ea", + "gasVersion": 8, + "executionProfile": "compat-general-v1", + "sourceKind": "module-pack", + "source": { + "modulePack": { + "version": 1, + "entrySpecifier": "./chess-entry.js", + "entryExport": "default", + "modules": [ + { + "specifier": "./chess-entry.js", + "source": "var __defProp = Object.defineProperty;\nvar __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;\nvar __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== \"symbol\" ? key + \"\" : key, value);\n\n// node_modules/.pnpm/chess.js@1.4.0/node_modules/chess.js/dist/esm/chess.js\nfunction rootNode(comment) {\n return comment !== null ? { comment, variations: [] } : { variations: [] };\n}\nfunction node(move, suffix, nag, comment, variations) {\n const node2 = { move, variations };\n if (suffix) {\n node2.suffix = suffix;\n }\n if (nag) {\n node2.nag = nag;\n }\n if (comment !== null) {\n node2.comment = comment;\n }\n return node2;\n}\nfunction lineToTree(...nodes) {\n const [root, ...rest] = nodes;\n let parent = root;\n for (const child of rest) {\n if (child !== null) {\n parent.variations = [child, ...child.variations];\n child.variations = [];\n parent = child;\n }\n }\n return root;\n}\nfunction pgn(headers, game) {\n if (game.marker && game.marker.comment) {\n let node2 = game.root;\n while (true) {\n const next = node2.variations[0];\n if (!next) {\n node2.comment = game.marker.comment;\n break;\n }\n node2 = next;\n }\n }\n return {\n headers,\n root: game.root,\n result: (game.marker && game.marker.result) ?? void 0\n };\n}\nfunction peg$subclass(child, parent) {\n function C() {\n this.constructor = child;\n }\n C.prototype = parent.prototype;\n child.prototype = new C();\n}\nfunction peg$SyntaxError(message, expected, found, location) {\n var self = Error.call(this, message);\n if (Object.setPrototypeOf) {\n Object.setPrototypeOf(self, peg$SyntaxError.prototype);\n }\n self.expected = expected;\n self.found = found;\n self.location = location;\n self.name = \"SyntaxError\";\n return self;\n}\npeg$subclass(peg$SyntaxError, Error);\nfunction peg$padEnd(str, targetLength, padString) {\n padString = padString || \" \";\n if (str.length > targetLength) {\n return str;\n }\n targetLength -= str.length;\n padString += padString.repeat(targetLength);\n return str + padString.slice(0, targetLength);\n}\npeg$SyntaxError.prototype.format = function(sources) {\n var str = \"Error: \" + this.message;\n if (this.location) {\n var src = null;\n var k;\n for (k = 0; k < sources.length; k++) {\n if (sources[k].source === this.location.source) {\n src = sources[k].text.split(/\\r\\n|\\n|\\r/g);\n break;\n }\n }\n var s = this.location.start;\n var offset_s = this.location.source && typeof this.location.source.offset === \"function\" ? this.location.source.offset(s) : s;\n var loc = this.location.source + \":\" + offset_s.line + \":\" + offset_s.column;\n if (src) {\n var e = this.location.end;\n var filler = peg$padEnd(\"\", offset_s.line.toString().length, \" \");\n var line = src[s.line - 1];\n var last = s.line === e.line ? e.column : line.length + 1;\n var hatLen = last - s.column || 1;\n str += \"\\n --> \" + loc + \"\\n\" + filler + \" |\\n\" + offset_s.line + \" | \" + line + \"\\n\" + filler + \" | \" + peg$padEnd(\"\", s.column - 1, \" \") + peg$padEnd(\"\", hatLen, \"^\");\n } else {\n str += \"\\n at \" + loc;\n }\n }\n return str;\n};\npeg$SyntaxError.buildMessage = function(expected, found) {\n var DESCRIBE_EXPECTATION_FNS = {\n literal: function(expectation) {\n return '\"' + literalEscape(expectation.text) + '\"';\n },\n class: function(expectation) {\n var escapedParts = expectation.parts.map(function(part) {\n return Array.isArray(part) ? classEscape(part[0]) + \"-\" + classEscape(part[1]) : classEscape(part);\n });\n return \"[\" + (expectation.inverted ? \"^\" : \"\") + escapedParts.join(\"\") + \"]\";\n },\n any: function() {\n return \"any character\";\n },\n end: function() {\n return \"end of input\";\n },\n other: function(expectation) {\n return expectation.description;\n }\n };\n function hex(ch) {\n return ch.charCodeAt(0).toString(16).toUpperCase();\n }\n function literalEscape(s) {\n return s.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"').replace(/\\0/g, \"\\\\0\").replace(/\\t/g, \"\\\\t\").replace(/\\n/g, \"\\\\n\").replace(/\\r/g, \"\\\\r\").replace(/[\\x00-\\x0F]/g, function(ch) {\n return \"\\\\x0\" + hex(ch);\n }).replace(/[\\x10-\\x1F\\x7F-\\x9F]/g, function(ch) {\n return \"\\\\x\" + hex(ch);\n });\n }\n function classEscape(s) {\n return s.replace(/\\\\/g, \"\\\\\\\\\").replace(/\\]/g, \"\\\\]\").replace(/\\^/g, \"\\\\^\").replace(/-/g, \"\\\\-\").replace(/\\0/g, \"\\\\0\").replace(/\\t/g, \"\\\\t\").replace(/\\n/g, \"\\\\n\").replace(/\\r/g, \"\\\\r\").replace(/[\\x00-\\x0F]/g, function(ch) {\n return \"\\\\x0\" + hex(ch);\n }).replace(/[\\x10-\\x1F\\x7F-\\x9F]/g, function(ch) {\n return \"\\\\x\" + hex(ch);\n });\n }\n function describeExpectation(expectation) {\n return DESCRIBE_EXPECTATION_FNS[expectation.type](expectation);\n }\n function describeExpected(expected2) {\n var descriptions = expected2.map(describeExpectation);\n var i, j;\n descriptions.sort();\n if (descriptions.length > 0) {\n for (i = 1, j = 1; i < descriptions.length; i++) {\n if (descriptions[i - 1] !== descriptions[i]) {\n descriptions[j] = descriptions[i];\n j++;\n }\n }\n descriptions.length = j;\n }\n switch (descriptions.length) {\n case 1:\n return descriptions[0];\n case 2:\n return descriptions[0] + \" or \" + descriptions[1];\n default:\n return descriptions.slice(0, -1).join(\", \") + \", or \" + descriptions[descriptions.length - 1];\n }\n }\n function describeFound(found2) {\n return found2 ? '\"' + literalEscape(found2) + '\"' : \"end of input\";\n }\n return \"Expected \" + describeExpected(expected) + \" but \" + describeFound(found) + \" found.\";\n};\nfunction peg$parse(input, options) {\n options = options !== void 0 ? options : {};\n var peg$FAILED = {};\n var peg$source = options.grammarSource;\n var peg$startRuleFunctions = { pgn: peg$parsepgn };\n var peg$startRuleFunction = peg$parsepgn;\n var peg$c0 = \"[\";\n var peg$c1 = '\"';\n var peg$c2 = \"]\";\n var peg$c3 = \".\";\n var peg$c4 = \"O-O-O\";\n var peg$c5 = \"O-O\";\n var peg$c6 = \"0-0-0\";\n var peg$c7 = \"0-0\";\n var peg$c8 = \"$\";\n var peg$c9 = \"{\";\n var peg$c10 = \"}\";\n var peg$c11 = \";\";\n var peg$c12 = \"(\";\n var peg$c13 = \")\";\n var peg$c14 = \"1-0\";\n var peg$c15 = \"0-1\";\n var peg$c16 = \"1/2-1/2\";\n var peg$c17 = \"*\";\n var peg$r0 = /^[a-zA-Z]/;\n var peg$r1 = /^[^\"]/;\n var peg$r2 = /^[0-9]/;\n var peg$r3 = /^[.]/;\n var peg$r4 = /^[a-zA-Z1-8\\-=]/;\n var peg$r5 = /^[+#]/;\n var peg$r6 = /^[!?]/;\n var peg$r7 = /^[^}]/;\n var peg$r8 = /^[^\\r\\n]/;\n var peg$r9 = /^[ \\t\\r\\n]/;\n var peg$e0 = peg$otherExpectation(\"tag pair\");\n var peg$e1 = peg$literalExpectation(\"[\", false);\n var peg$e2 = peg$literalExpectation('\"', false);\n var peg$e3 = peg$literalExpectation(\"]\", false);\n var peg$e4 = peg$otherExpectation(\"tag name\");\n var peg$e5 = peg$classExpectation([[\"a\", \"z\"], [\"A\", \"Z\"]], false, false);\n var peg$e6 = peg$otherExpectation(\"tag value\");\n var peg$e7 = peg$classExpectation(['\"'], true, false);\n var peg$e8 = peg$otherExpectation(\"move number\");\n var peg$e9 = peg$classExpectation([[\"0\", \"9\"]], false, false);\n var peg$e10 = peg$literalExpectation(\".\", false);\n var peg$e11 = peg$classExpectation([\".\"], false, false);\n var peg$e12 = peg$otherExpectation(\"standard algebraic notation\");\n var peg$e13 = peg$literalExpectation(\"O-O-O\", false);\n var peg$e14 = peg$literalExpectation(\"O-O\", false);\n var peg$e15 = peg$literalExpectation(\"0-0-0\", false);\n var peg$e16 = peg$literalExpectation(\"0-0\", false);\n var peg$e17 = peg$classExpectation([[\"a\", \"z\"], [\"A\", \"Z\"], [\"1\", \"8\"], \"-\", \"=\"], false, false);\n var peg$e18 = peg$classExpectation([\"+\", \"#\"], false, false);\n var peg$e19 = peg$otherExpectation(\"suffix annotation\");\n var peg$e20 = peg$classExpectation([\"!\", \"?\"], false, false);\n var peg$e21 = peg$otherExpectation(\"NAG\");\n var peg$e22 = peg$literalExpectation(\"$\", false);\n var peg$e23 = peg$otherExpectation(\"brace comment\");\n var peg$e24 = peg$literalExpectation(\"{\", false);\n var peg$e25 = peg$classExpectation([\"}\"], true, false);\n var peg$e26 = peg$literalExpectation(\"}\", false);\n var peg$e27 = peg$otherExpectation(\"rest of line comment\");\n var peg$e28 = peg$literalExpectation(\";\", false);\n var peg$e29 = peg$classExpectation([\"\\r\", \"\\n\"], true, false);\n var peg$e30 = peg$otherExpectation(\"variation\");\n var peg$e31 = peg$literalExpectation(\"(\", false);\n var peg$e32 = peg$literalExpectation(\")\", false);\n var peg$e33 = peg$otherExpectation(\"game termination marker\");\n var peg$e34 = peg$literalExpectation(\"1-0\", false);\n var peg$e35 = peg$literalExpectation(\"0-1\", false);\n var peg$e36 = peg$literalExpectation(\"1/2-1/2\", false);\n var peg$e37 = peg$literalExpectation(\"*\", false);\n var peg$e38 = peg$otherExpectation(\"whitespace\");\n var peg$e39 = peg$classExpectation([\" \", \"\t\", \"\\r\", \"\\n\"], false, false);\n var peg$f0 = function(headers, game) {\n return pgn(headers, game);\n };\n var peg$f1 = function(tagPairs) {\n return Object.fromEntries(tagPairs);\n };\n var peg$f2 = function(tagName, tagValue) {\n return [tagName, tagValue];\n };\n var peg$f3 = function(root, marker) {\n return { root, marker };\n };\n var peg$f4 = function(comment, moves) {\n return lineToTree(rootNode(comment), ...moves.flat());\n };\n var peg$f5 = function(san, suffix, nag, comment, variations) {\n return node(san, suffix, nag, comment, variations);\n };\n var peg$f6 = function(nag) {\n return nag;\n };\n var peg$f7 = function(comment) {\n return comment.replace(/[\\r\\n]+/g, \" \");\n };\n var peg$f8 = function(comment) {\n return comment.trim();\n };\n var peg$f9 = function(line) {\n return line;\n };\n var peg$f10 = function(result, comment) {\n return { result, comment };\n };\n var peg$currPos = options.peg$currPos | 0;\n var peg$posDetailsCache = [{ line: 1, column: 1 }];\n var peg$maxFailPos = peg$currPos;\n var peg$maxFailExpected = options.peg$maxFailExpected || [];\n var peg$silentFails = options.peg$silentFails | 0;\n var peg$result;\n if (options.startRule) {\n if (!(options.startRule in peg$startRuleFunctions)) {\n throw new Error(`Can't start parsing from rule \"` + options.startRule + '\".');\n }\n peg$startRuleFunction = peg$startRuleFunctions[options.startRule];\n }\n function peg$literalExpectation(text, ignoreCase) {\n return { type: \"literal\", text, ignoreCase };\n }\n function peg$classExpectation(parts, inverted, ignoreCase) {\n return { type: \"class\", parts, inverted, ignoreCase };\n }\n function peg$endExpectation() {\n return { type: \"end\" };\n }\n function peg$otherExpectation(description) {\n return { type: \"other\", description };\n }\n function peg$computePosDetails(pos) {\n var details = peg$posDetailsCache[pos];\n var p;\n if (details) {\n return details;\n } else {\n if (pos >= peg$posDetailsCache.length) {\n p = peg$posDetailsCache.length - 1;\n } else {\n p = pos;\n while (!peg$posDetailsCache[--p]) {\n }\n }\n details = peg$posDetailsCache[p];\n details = {\n line: details.line,\n column: details.column\n };\n while (p < pos) {\n if (input.charCodeAt(p) === 10) {\n details.line++;\n details.column = 1;\n } else {\n details.column++;\n }\n p++;\n }\n peg$posDetailsCache[pos] = details;\n return details;\n }\n }\n function peg$computeLocation(startPos, endPos, offset) {\n var startPosDetails = peg$computePosDetails(startPos);\n var endPosDetails = peg$computePosDetails(endPos);\n var res = {\n source: peg$source,\n start: {\n offset: startPos,\n line: startPosDetails.line,\n column: startPosDetails.column\n },\n end: {\n offset: endPos,\n line: endPosDetails.line,\n column: endPosDetails.column\n }\n };\n return res;\n }\n function peg$fail(expected) {\n if (peg$currPos < peg$maxFailPos) {\n return;\n }\n if (peg$currPos > peg$maxFailPos) {\n peg$maxFailPos = peg$currPos;\n peg$maxFailExpected = [];\n }\n peg$maxFailExpected.push(expected);\n }\n function peg$buildStructuredError(expected, found, location) {\n return new peg$SyntaxError(\n peg$SyntaxError.buildMessage(expected, found),\n expected,\n found,\n location\n );\n }\n function peg$parsepgn() {\n var s0, s1, s2;\n s0 = peg$currPos;\n s1 = peg$parsetagPairSection();\n s2 = peg$parsemoveTextSection();\n s0 = peg$f0(s1, s2);\n return s0;\n }\n function peg$parsetagPairSection() {\n var s0, s1, s2;\n s0 = peg$currPos;\n s1 = [];\n s2 = peg$parsetagPair();\n while (s2 !== peg$FAILED) {\n s1.push(s2);\n s2 = peg$parsetagPair();\n }\n s2 = peg$parse_();\n s0 = peg$f1(s1);\n return s0;\n }\n function peg$parsetagPair() {\n var s0, s2, s4, s6, s7, s8, s10;\n peg$silentFails++;\n s0 = peg$currPos;\n peg$parse_();\n if (input.charCodeAt(peg$currPos) === 91) {\n s2 = peg$c0;\n peg$currPos++;\n } else {\n s2 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e1);\n }\n }\n if (s2 !== peg$FAILED) {\n peg$parse_();\n s4 = peg$parsetagName();\n if (s4 !== peg$FAILED) {\n peg$parse_();\n if (input.charCodeAt(peg$currPos) === 34) {\n s6 = peg$c1;\n peg$currPos++;\n } else {\n s6 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e2);\n }\n }\n if (s6 !== peg$FAILED) {\n s7 = peg$parsetagValue();\n if (input.charCodeAt(peg$currPos) === 34) {\n s8 = peg$c1;\n peg$currPos++;\n } else {\n s8 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e2);\n }\n }\n if (s8 !== peg$FAILED) {\n peg$parse_();\n if (input.charCodeAt(peg$currPos) === 93) {\n s10 = peg$c2;\n peg$currPos++;\n } else {\n s10 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e3);\n }\n }\n if (s10 !== peg$FAILED) {\n s0 = peg$f2(s4, s7);\n } else {\n peg$currPos = s0;\n s0 = peg$FAILED;\n }\n } else {\n peg$currPos = s0;\n s0 = peg$FAILED;\n }\n } else {\n peg$currPos = s0;\n s0 = peg$FAILED;\n }\n } else {\n peg$currPos = s0;\n s0 = peg$FAILED;\n }\n } else {\n peg$currPos = s0;\n s0 = peg$FAILED;\n }\n peg$silentFails--;\n if (s0 === peg$FAILED) {\n if (peg$silentFails === 0) {\n peg$fail(peg$e0);\n }\n }\n return s0;\n }\n function peg$parsetagName() {\n var s0, s1, s2;\n peg$silentFails++;\n s0 = peg$currPos;\n s1 = [];\n s2 = input.charAt(peg$currPos);\n if (peg$r0.test(s2)) {\n peg$currPos++;\n } else {\n s2 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e5);\n }\n }\n if (s2 !== peg$FAILED) {\n while (s2 !== peg$FAILED) {\n s1.push(s2);\n s2 = input.charAt(peg$currPos);\n if (peg$r0.test(s2)) {\n peg$currPos++;\n } else {\n s2 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e5);\n }\n }\n }\n } else {\n s1 = peg$FAILED;\n }\n if (s1 !== peg$FAILED) {\n s0 = input.substring(s0, peg$currPos);\n } else {\n s0 = s1;\n }\n peg$silentFails--;\n if (s0 === peg$FAILED) {\n s1 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e4);\n }\n }\n return s0;\n }\n function peg$parsetagValue() {\n var s0, s1, s2;\n peg$silentFails++;\n s0 = peg$currPos;\n s1 = [];\n s2 = input.charAt(peg$currPos);\n if (peg$r1.test(s2)) {\n peg$currPos++;\n } else {\n s2 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e7);\n }\n }\n while (s2 !== peg$FAILED) {\n s1.push(s2);\n s2 = input.charAt(peg$currPos);\n if (peg$r1.test(s2)) {\n peg$currPos++;\n } else {\n s2 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e7);\n }\n }\n }\n s0 = input.substring(s0, peg$currPos);\n peg$silentFails--;\n s1 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e6);\n }\n return s0;\n }\n function peg$parsemoveTextSection() {\n var s0, s1, s3;\n s0 = peg$currPos;\n s1 = peg$parseline();\n peg$parse_();\n s3 = peg$parsegameTerminationMarker();\n if (s3 === peg$FAILED) {\n s3 = null;\n }\n peg$parse_();\n s0 = peg$f3(s1, s3);\n return s0;\n }\n function peg$parseline() {\n var s0, s1, s2, s3;\n s0 = peg$currPos;\n s1 = peg$parsecomment();\n if (s1 === peg$FAILED) {\n s1 = null;\n }\n s2 = [];\n s3 = peg$parsemove();\n while (s3 !== peg$FAILED) {\n s2.push(s3);\n s3 = peg$parsemove();\n }\n s0 = peg$f4(s1, s2);\n return s0;\n }\n function peg$parsemove() {\n var s0, s4, s5, s6, s7, s8, s9, s10;\n s0 = peg$currPos;\n peg$parse_();\n peg$parsemoveNumber();\n peg$parse_();\n s4 = peg$parsesan();\n if (s4 !== peg$FAILED) {\n s5 = peg$parsesuffixAnnotation();\n if (s5 === peg$FAILED) {\n s5 = null;\n }\n s6 = [];\n s7 = peg$parsenag();\n while (s7 !== peg$FAILED) {\n s6.push(s7);\n s7 = peg$parsenag();\n }\n s7 = peg$parse_();\n s8 = peg$parsecomment();\n if (s8 === peg$FAILED) {\n s8 = null;\n }\n s9 = [];\n s10 = peg$parsevariation();\n while (s10 !== peg$FAILED) {\n s9.push(s10);\n s10 = peg$parsevariation();\n }\n s0 = peg$f5(s4, s5, s6, s8, s9);\n } else {\n peg$currPos = s0;\n s0 = peg$FAILED;\n }\n return s0;\n }\n function peg$parsemoveNumber() {\n var s0, s1, s2, s3, s4, s5;\n peg$silentFails++;\n s0 = peg$currPos;\n s1 = [];\n s2 = input.charAt(peg$currPos);\n if (peg$r2.test(s2)) {\n peg$currPos++;\n } else {\n s2 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e9);\n }\n }\n while (s2 !== peg$FAILED) {\n s1.push(s2);\n s2 = input.charAt(peg$currPos);\n if (peg$r2.test(s2)) {\n peg$currPos++;\n } else {\n s2 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e9);\n }\n }\n }\n if (input.charCodeAt(peg$currPos) === 46) {\n s2 = peg$c3;\n peg$currPos++;\n } else {\n s2 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e10);\n }\n }\n if (s2 !== peg$FAILED) {\n s3 = peg$parse_();\n s4 = [];\n s5 = input.charAt(peg$currPos);\n if (peg$r3.test(s5)) {\n peg$currPos++;\n } else {\n s5 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e11);\n }\n }\n while (s5 !== peg$FAILED) {\n s4.push(s5);\n s5 = input.charAt(peg$currPos);\n if (peg$r3.test(s5)) {\n peg$currPos++;\n } else {\n s5 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e11);\n }\n }\n }\n s1 = [s1, s2, s3, s4];\n s0 = s1;\n } else {\n peg$currPos = s0;\n s0 = peg$FAILED;\n }\n peg$silentFails--;\n if (s0 === peg$FAILED) {\n s1 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e8);\n }\n }\n return s0;\n }\n function peg$parsesan() {\n var s0, s1, s2, s3, s4, s5;\n peg$silentFails++;\n s0 = peg$currPos;\n s1 = peg$currPos;\n if (input.substr(peg$currPos, 5) === peg$c4) {\n s2 = peg$c4;\n peg$currPos += 5;\n } else {\n s2 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e13);\n }\n }\n if (s2 === peg$FAILED) {\n if (input.substr(peg$currPos, 3) === peg$c5) {\n s2 = peg$c5;\n peg$currPos += 3;\n } else {\n s2 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e14);\n }\n }\n if (s2 === peg$FAILED) {\n if (input.substr(peg$currPos, 5) === peg$c6) {\n s2 = peg$c6;\n peg$currPos += 5;\n } else {\n s2 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e15);\n }\n }\n if (s2 === peg$FAILED) {\n if (input.substr(peg$currPos, 3) === peg$c7) {\n s2 = peg$c7;\n peg$currPos += 3;\n } else {\n s2 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e16);\n }\n }\n if (s2 === peg$FAILED) {\n s2 = peg$currPos;\n s3 = input.charAt(peg$currPos);\n if (peg$r0.test(s3)) {\n peg$currPos++;\n } else {\n s3 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e5);\n }\n }\n if (s3 !== peg$FAILED) {\n s4 = [];\n s5 = input.charAt(peg$currPos);\n if (peg$r4.test(s5)) {\n peg$currPos++;\n } else {\n s5 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e17);\n }\n }\n if (s5 !== peg$FAILED) {\n while (s5 !== peg$FAILED) {\n s4.push(s5);\n s5 = input.charAt(peg$currPos);\n if (peg$r4.test(s5)) {\n peg$currPos++;\n } else {\n s5 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e17);\n }\n }\n }\n } else {\n s4 = peg$FAILED;\n }\n if (s4 !== peg$FAILED) {\n s3 = [s3, s4];\n s2 = s3;\n } else {\n peg$currPos = s2;\n s2 = peg$FAILED;\n }\n } else {\n peg$currPos = s2;\n s2 = peg$FAILED;\n }\n }\n }\n }\n }\n if (s2 !== peg$FAILED) {\n s3 = input.charAt(peg$currPos);\n if (peg$r5.test(s3)) {\n peg$currPos++;\n } else {\n s3 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e18);\n }\n }\n if (s3 === peg$FAILED) {\n s3 = null;\n }\n s2 = [s2, s3];\n s1 = s2;\n } else {\n peg$currPos = s1;\n s1 = peg$FAILED;\n }\n if (s1 !== peg$FAILED) {\n s0 = input.substring(s0, peg$currPos);\n } else {\n s0 = s1;\n }\n peg$silentFails--;\n if (s0 === peg$FAILED) {\n s1 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e12);\n }\n }\n return s0;\n }\n function peg$parsesuffixAnnotation() {\n var s0, s1, s2;\n peg$silentFails++;\n s0 = peg$currPos;\n s1 = [];\n s2 = input.charAt(peg$currPos);\n if (peg$r6.test(s2)) {\n peg$currPos++;\n } else {\n s2 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e20);\n }\n }\n while (s2 !== peg$FAILED) {\n s1.push(s2);\n if (s1.length >= 2) {\n s2 = peg$FAILED;\n } else {\n s2 = input.charAt(peg$currPos);\n if (peg$r6.test(s2)) {\n peg$currPos++;\n } else {\n s2 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e20);\n }\n }\n }\n }\n if (s1.length < 1) {\n peg$currPos = s0;\n s0 = peg$FAILED;\n } else {\n s0 = s1;\n }\n peg$silentFails--;\n if (s0 === peg$FAILED) {\n s1 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e19);\n }\n }\n return s0;\n }\n function peg$parsenag() {\n var s0, s2, s3, s4, s5;\n peg$silentFails++;\n s0 = peg$currPos;\n peg$parse_();\n if (input.charCodeAt(peg$currPos) === 36) {\n s2 = peg$c8;\n peg$currPos++;\n } else {\n s2 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e22);\n }\n }\n if (s2 !== peg$FAILED) {\n s3 = peg$currPos;\n s4 = [];\n s5 = input.charAt(peg$currPos);\n if (peg$r2.test(s5)) {\n peg$currPos++;\n } else {\n s5 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e9);\n }\n }\n if (s5 !== peg$FAILED) {\n while (s5 !== peg$FAILED) {\n s4.push(s5);\n s5 = input.charAt(peg$currPos);\n if (peg$r2.test(s5)) {\n peg$currPos++;\n } else {\n s5 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e9);\n }\n }\n }\n } else {\n s4 = peg$FAILED;\n }\n if (s4 !== peg$FAILED) {\n s3 = input.substring(s3, peg$currPos);\n } else {\n s3 = s4;\n }\n if (s3 !== peg$FAILED) {\n s0 = peg$f6(s3);\n } else {\n peg$currPos = s0;\n s0 = peg$FAILED;\n }\n } else {\n peg$currPos = s0;\n s0 = peg$FAILED;\n }\n peg$silentFails--;\n if (s0 === peg$FAILED) {\n if (peg$silentFails === 0) {\n peg$fail(peg$e21);\n }\n }\n return s0;\n }\n function peg$parsecomment() {\n var s0;\n s0 = peg$parsebraceComment();\n if (s0 === peg$FAILED) {\n s0 = peg$parserestOfLineComment();\n }\n return s0;\n }\n function peg$parsebraceComment() {\n var s0, s1, s2, s3, s4;\n peg$silentFails++;\n s0 = peg$currPos;\n if (input.charCodeAt(peg$currPos) === 123) {\n s1 = peg$c9;\n peg$currPos++;\n } else {\n s1 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e24);\n }\n }\n if (s1 !== peg$FAILED) {\n s2 = peg$currPos;\n s3 = [];\n s4 = input.charAt(peg$currPos);\n if (peg$r7.test(s4)) {\n peg$currPos++;\n } else {\n s4 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e25);\n }\n }\n while (s4 !== peg$FAILED) {\n s3.push(s4);\n s4 = input.charAt(peg$currPos);\n if (peg$r7.test(s4)) {\n peg$currPos++;\n } else {\n s4 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e25);\n }\n }\n }\n s2 = input.substring(s2, peg$currPos);\n if (input.charCodeAt(peg$currPos) === 125) {\n s3 = peg$c10;\n peg$currPos++;\n } else {\n s3 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e26);\n }\n }\n if (s3 !== peg$FAILED) {\n s0 = peg$f7(s2);\n } else {\n peg$currPos = s0;\n s0 = peg$FAILED;\n }\n } else {\n peg$currPos = s0;\n s0 = peg$FAILED;\n }\n peg$silentFails--;\n if (s0 === peg$FAILED) {\n s1 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e23);\n }\n }\n return s0;\n }\n function peg$parserestOfLineComment() {\n var s0, s1, s2, s3, s4;\n peg$silentFails++;\n s0 = peg$currPos;\n if (input.charCodeAt(peg$currPos) === 59) {\n s1 = peg$c11;\n peg$currPos++;\n } else {\n s1 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e28);\n }\n }\n if (s1 !== peg$FAILED) {\n s2 = peg$currPos;\n s3 = [];\n s4 = input.charAt(peg$currPos);\n if (peg$r8.test(s4)) {\n peg$currPos++;\n } else {\n s4 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e29);\n }\n }\n while (s4 !== peg$FAILED) {\n s3.push(s4);\n s4 = input.charAt(peg$currPos);\n if (peg$r8.test(s4)) {\n peg$currPos++;\n } else {\n s4 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e29);\n }\n }\n }\n s2 = input.substring(s2, peg$currPos);\n s0 = peg$f8(s2);\n } else {\n peg$currPos = s0;\n s0 = peg$FAILED;\n }\n peg$silentFails--;\n if (s0 === peg$FAILED) {\n s1 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e27);\n }\n }\n return s0;\n }\n function peg$parsevariation() {\n var s0, s2, s3, s5;\n peg$silentFails++;\n s0 = peg$currPos;\n peg$parse_();\n if (input.charCodeAt(peg$currPos) === 40) {\n s2 = peg$c12;\n peg$currPos++;\n } else {\n s2 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e31);\n }\n }\n if (s2 !== peg$FAILED) {\n s3 = peg$parseline();\n if (s3 !== peg$FAILED) {\n peg$parse_();\n if (input.charCodeAt(peg$currPos) === 41) {\n s5 = peg$c13;\n peg$currPos++;\n } else {\n s5 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e32);\n }\n }\n if (s5 !== peg$FAILED) {\n s0 = peg$f9(s3);\n } else {\n peg$currPos = s0;\n s0 = peg$FAILED;\n }\n } else {\n peg$currPos = s0;\n s0 = peg$FAILED;\n }\n } else {\n peg$currPos = s0;\n s0 = peg$FAILED;\n }\n peg$silentFails--;\n if (s0 === peg$FAILED) {\n if (peg$silentFails === 0) {\n peg$fail(peg$e30);\n }\n }\n return s0;\n }\n function peg$parsegameTerminationMarker() {\n var s0, s1, s3;\n peg$silentFails++;\n s0 = peg$currPos;\n if (input.substr(peg$currPos, 3) === peg$c14) {\n s1 = peg$c14;\n peg$currPos += 3;\n } else {\n s1 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e34);\n }\n }\n if (s1 === peg$FAILED) {\n if (input.substr(peg$currPos, 3) === peg$c15) {\n s1 = peg$c15;\n peg$currPos += 3;\n } else {\n s1 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e35);\n }\n }\n if (s1 === peg$FAILED) {\n if (input.substr(peg$currPos, 7) === peg$c16) {\n s1 = peg$c16;\n peg$currPos += 7;\n } else {\n s1 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e36);\n }\n }\n if (s1 === peg$FAILED) {\n if (input.charCodeAt(peg$currPos) === 42) {\n s1 = peg$c17;\n peg$currPos++;\n } else {\n s1 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e37);\n }\n }\n }\n }\n }\n if (s1 !== peg$FAILED) {\n peg$parse_();\n s3 = peg$parsecomment();\n if (s3 === peg$FAILED) {\n s3 = null;\n }\n s0 = peg$f10(s1, s3);\n } else {\n peg$currPos = s0;\n s0 = peg$FAILED;\n }\n peg$silentFails--;\n if (s0 === peg$FAILED) {\n s1 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e33);\n }\n }\n return s0;\n }\n function peg$parse_() {\n var s0, s1;\n peg$silentFails++;\n s0 = [];\n s1 = input.charAt(peg$currPos);\n if (peg$r9.test(s1)) {\n peg$currPos++;\n } else {\n s1 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e39);\n }\n }\n while (s1 !== peg$FAILED) {\n s0.push(s1);\n s1 = input.charAt(peg$currPos);\n if (peg$r9.test(s1)) {\n peg$currPos++;\n } else {\n s1 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e39);\n }\n }\n }\n peg$silentFails--;\n s1 = peg$FAILED;\n if (peg$silentFails === 0) {\n peg$fail(peg$e38);\n }\n return s0;\n }\n peg$result = peg$startRuleFunction();\n if (options.peg$library) {\n return (\n /** @type {any} */\n {\n peg$result,\n peg$currPos,\n peg$FAILED,\n peg$maxFailExpected,\n peg$maxFailPos\n }\n );\n }\n if (peg$result !== peg$FAILED && peg$currPos === input.length) {\n return peg$result;\n } else {\n if (peg$result !== peg$FAILED && peg$currPos < input.length) {\n peg$fail(peg$endExpectation());\n }\n throw peg$buildStructuredError(\n peg$maxFailExpected,\n peg$maxFailPos < input.length ? input.charAt(peg$maxFailPos) : null,\n peg$maxFailPos < input.length ? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1) : peg$computeLocation(peg$maxFailPos, peg$maxFailPos)\n );\n }\n}\nvar MASK64 = 0xffffffffffffffffn;\nfunction rotl(x, k) {\n return (x << k | x >> 64n - k) & 0xffffffffffffffffn;\n}\nfunction wrappingMul(x, y) {\n return x * y & MASK64;\n}\nfunction xoroshiro128(state) {\n return function() {\n let s0 = BigInt(state & MASK64);\n let s1 = BigInt(state >> 64n & MASK64);\n const result = wrappingMul(rotl(wrappingMul(s0, 5n), 7n), 9n);\n s1 ^= s0;\n s0 = (rotl(s0, 24n) ^ s1 ^ s1 << 16n) & MASK64;\n s1 = rotl(s1, 37n);\n state = s1 << 64n | s0;\n return result;\n };\n}\nvar rand = xoroshiro128(0xa187eb39cdcaed8f31c4b365b102e01en);\nvar PIECE_KEYS = Array.from({ length: 2 }, () => Array.from({ length: 6 }, () => Array.from({ length: 128 }, () => rand())));\nvar EP_KEYS = Array.from({ length: 8 }, () => rand());\nvar CASTLING_KEYS = Array.from({ length: 16 }, () => rand());\nvar SIDE_KEY = rand();\nvar WHITE = \"w\";\nvar BLACK = \"b\";\nvar PAWN = \"p\";\nvar KNIGHT = \"n\";\nvar BISHOP = \"b\";\nvar ROOK = \"r\";\nvar QUEEN = \"q\";\nvar KING = \"k\";\nvar DEFAULT_POSITION = \"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1\";\nvar Move = class {\n constructor(chess2, internal) {\n __publicField(this, \"color\");\n __publicField(this, \"from\");\n __publicField(this, \"to\");\n __publicField(this, \"piece\");\n __publicField(this, \"captured\");\n __publicField(this, \"promotion\");\n /**\n * @deprecated This field is deprecated and will be removed in version 2.0.0.\n * Please use move descriptor functions instead: `isCapture`, `isPromotion`,\n * `isEnPassant`, `isKingsideCastle`, `isQueensideCastle`, `isCastle`, and\n * `isBigPawn`\n */\n __publicField(this, \"flags\");\n __publicField(this, \"san\");\n __publicField(this, \"lan\");\n __publicField(this, \"before\");\n __publicField(this, \"after\");\n const { color, piece, from, to, flags, captured, promotion } = internal;\n const fromAlgebraic = algebraic(from);\n const toAlgebraic = algebraic(to);\n this.color = color;\n this.piece = piece;\n this.from = fromAlgebraic;\n this.to = toAlgebraic;\n this.san = chess2[\"_moveToSan\"](internal, chess2[\"_moves\"]({ legal: true }));\n this.lan = fromAlgebraic + toAlgebraic;\n this.before = chess2.fen();\n chess2[\"_makeMove\"](internal);\n this.after = chess2.fen();\n chess2[\"_undoMove\"]();\n this.flags = \"\";\n for (const flag in BITS) {\n if (BITS[flag] & flags) {\n this.flags += FLAGS[flag];\n }\n }\n if (captured) {\n this.captured = captured;\n }\n if (promotion) {\n this.promotion = promotion;\n this.lan += promotion;\n }\n }\n isCapture() {\n return this.flags.indexOf(FLAGS[\"CAPTURE\"]) > -1;\n }\n isPromotion() {\n return this.flags.indexOf(FLAGS[\"PROMOTION\"]) > -1;\n }\n isEnPassant() {\n return this.flags.indexOf(FLAGS[\"EP_CAPTURE\"]) > -1;\n }\n isKingsideCastle() {\n return this.flags.indexOf(FLAGS[\"KSIDE_CASTLE\"]) > -1;\n }\n isQueensideCastle() {\n return this.flags.indexOf(FLAGS[\"QSIDE_CASTLE\"]) > -1;\n }\n isBigPawn() {\n return this.flags.indexOf(FLAGS[\"BIG_PAWN\"]) > -1;\n }\n};\nvar EMPTY = -1;\nvar FLAGS = {\n NORMAL: \"n\",\n CAPTURE: \"c\",\n BIG_PAWN: \"b\",\n EP_CAPTURE: \"e\",\n PROMOTION: \"p\",\n KSIDE_CASTLE: \"k\",\n QSIDE_CASTLE: \"q\",\n NULL_MOVE: \"-\"\n};\nvar BITS = {\n NORMAL: 1,\n CAPTURE: 2,\n BIG_PAWN: 4,\n EP_CAPTURE: 8,\n PROMOTION: 16,\n KSIDE_CASTLE: 32,\n QSIDE_CASTLE: 64,\n NULL_MOVE: 128\n};\nvar SEVEN_TAG_ROSTER = {\n Event: \"?\",\n Site: \"?\",\n Date: \"????.??.??\",\n Round: \"?\",\n White: \"?\",\n Black: \"?\",\n Result: \"*\"\n};\nvar SUPLEMENTAL_TAGS = {\n WhiteTitle: null,\n BlackTitle: null,\n WhiteElo: null,\n BlackElo: null,\n WhiteUSCF: null,\n BlackUSCF: null,\n WhiteNA: null,\n BlackNA: null,\n WhiteType: null,\n BlackType: null,\n EventDate: null,\n EventSponsor: null,\n Section: null,\n Stage: null,\n Board: null,\n Opening: null,\n Variation: null,\n SubVariation: null,\n ECO: null,\n NIC: null,\n Time: null,\n UTCTime: null,\n UTCDate: null,\n TimeControl: null,\n SetUp: null,\n FEN: null,\n Termination: null,\n Annotator: null,\n Mode: null,\n PlyCount: null\n};\nvar HEADER_TEMPLATE = {\n ...SEVEN_TAG_ROSTER,\n ...SUPLEMENTAL_TAGS\n};\nvar Ox88 = {\n a8: 0,\n b8: 1,\n c8: 2,\n d8: 3,\n e8: 4,\n f8: 5,\n g8: 6,\n h8: 7,\n a7: 16,\n b7: 17,\n c7: 18,\n d7: 19,\n e7: 20,\n f7: 21,\n g7: 22,\n h7: 23,\n a6: 32,\n b6: 33,\n c6: 34,\n d6: 35,\n e6: 36,\n f6: 37,\n g6: 38,\n h6: 39,\n a5: 48,\n b5: 49,\n c5: 50,\n d5: 51,\n e5: 52,\n f5: 53,\n g5: 54,\n h5: 55,\n a4: 64,\n b4: 65,\n c4: 66,\n d4: 67,\n e4: 68,\n f4: 69,\n g4: 70,\n h4: 71,\n a3: 80,\n b3: 81,\n c3: 82,\n d3: 83,\n e3: 84,\n f3: 85,\n g3: 86,\n h3: 87,\n a2: 96,\n b2: 97,\n c2: 98,\n d2: 99,\n e2: 100,\n f2: 101,\n g2: 102,\n h2: 103,\n a1: 112,\n b1: 113,\n c1: 114,\n d1: 115,\n e1: 116,\n f1: 117,\n g1: 118,\n h1: 119\n};\nvar PAWN_OFFSETS = {\n b: [16, 32, 17, 15],\n w: [-16, -32, -17, -15]\n};\nvar PIECE_OFFSETS = {\n n: [-18, -33, -31, -14, 18, 33, 31, 14],\n b: [-17, -15, 17, 15],\n r: [-16, 1, 16, -1],\n q: [-17, -16, -15, 1, 17, 16, 15, -1],\n k: [-17, -16, -15, 1, 17, 16, 15, -1]\n};\nvar ATTACKS = [\n 20,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 24,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 20,\n 0,\n 0,\n 20,\n 0,\n 0,\n 0,\n 0,\n 0,\n 24,\n 0,\n 0,\n 0,\n 0,\n 0,\n 20,\n 0,\n 0,\n 0,\n 0,\n 20,\n 0,\n 0,\n 0,\n 0,\n 24,\n 0,\n 0,\n 0,\n 0,\n 20,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 20,\n 0,\n 0,\n 0,\n 24,\n 0,\n 0,\n 0,\n 20,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 20,\n 0,\n 0,\n 24,\n 0,\n 0,\n 20,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 20,\n 2,\n 24,\n 2,\n 20,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 2,\n 53,\n 56,\n 53,\n 2,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 24,\n 24,\n 24,\n 24,\n 24,\n 24,\n 56,\n 0,\n 56,\n 24,\n 24,\n 24,\n 24,\n 24,\n 24,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 2,\n 53,\n 56,\n 53,\n 2,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 20,\n 2,\n 24,\n 2,\n 20,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 20,\n 0,\n 0,\n 24,\n 0,\n 0,\n 20,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 20,\n 0,\n 0,\n 0,\n 24,\n 0,\n 0,\n 0,\n 20,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 20,\n 0,\n 0,\n 0,\n 0,\n 24,\n 0,\n 0,\n 0,\n 0,\n 20,\n 0,\n 0,\n 0,\n 0,\n 20,\n 0,\n 0,\n 0,\n 0,\n 0,\n 24,\n 0,\n 0,\n 0,\n 0,\n 0,\n 20,\n 0,\n 0,\n 20,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 24,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 20\n];\nvar RAYS = [\n 17,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 16,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 15,\n 0,\n 0,\n 17,\n 0,\n 0,\n 0,\n 0,\n 0,\n 16,\n 0,\n 0,\n 0,\n 0,\n 0,\n 15,\n 0,\n 0,\n 0,\n 0,\n 17,\n 0,\n 0,\n 0,\n 0,\n 16,\n 0,\n 0,\n 0,\n 0,\n 15,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 17,\n 0,\n 0,\n 0,\n 16,\n 0,\n 0,\n 0,\n 15,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 17,\n 0,\n 0,\n 16,\n 0,\n 0,\n 15,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 17,\n 0,\n 16,\n 0,\n 15,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 17,\n 16,\n 15,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 1,\n 1,\n 1,\n 1,\n 1,\n 1,\n 1,\n 0,\n -1,\n -1,\n -1,\n -1,\n -1,\n -1,\n -1,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n -15,\n -16,\n -17,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n -15,\n 0,\n -16,\n 0,\n -17,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n -15,\n 0,\n 0,\n -16,\n 0,\n 0,\n -17,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n -15,\n 0,\n 0,\n 0,\n -16,\n 0,\n 0,\n 0,\n -17,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n -15,\n 0,\n 0,\n 0,\n 0,\n -16,\n 0,\n 0,\n 0,\n 0,\n -17,\n 0,\n 0,\n 0,\n 0,\n -15,\n 0,\n 0,\n 0,\n 0,\n 0,\n -16,\n 0,\n 0,\n 0,\n 0,\n 0,\n -17,\n 0,\n 0,\n -15,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n -16,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n -17\n];\nvar PIECE_MASKS = { p: 1, n: 2, b: 4, r: 8, q: 16, k: 32 };\nvar SYMBOLS = \"pnbrqkPNBRQK\";\nvar PROMOTIONS = [KNIGHT, BISHOP, ROOK, QUEEN];\nvar RANK_1 = 7;\nvar RANK_2 = 6;\nvar RANK_7 = 1;\nvar RANK_8 = 0;\nvar SIDES = {\n [KING]: BITS.KSIDE_CASTLE,\n [QUEEN]: BITS.QSIDE_CASTLE\n};\nvar ROOKS = {\n w: [\n { square: Ox88.a1, flag: BITS.QSIDE_CASTLE },\n { square: Ox88.h1, flag: BITS.KSIDE_CASTLE }\n ],\n b: [\n { square: Ox88.a8, flag: BITS.QSIDE_CASTLE },\n { square: Ox88.h8, flag: BITS.KSIDE_CASTLE }\n ]\n};\nvar SECOND_RANK = { b: RANK_7, w: RANK_2 };\nvar SAN_NULLMOVE = \"--\";\nfunction rank(square) {\n return square >> 4;\n}\nfunction file(square) {\n return square & 15;\n}\nfunction isDigit(c) {\n return \"0123456789\".indexOf(c) !== -1;\n}\nfunction algebraic(square) {\n const f = file(square);\n const r = rank(square);\n return \"abcdefgh\".substring(f, f + 1) + \"87654321\".substring(r, r + 1);\n}\nfunction swapColor(color) {\n return color === WHITE ? BLACK : WHITE;\n}\nfunction validateFen(fen) {\n const tokens = fen.split(/\\s+/);\n if (tokens.length !== 6) {\n return {\n ok: false,\n error: \"Invalid FEN: must contain six space-delimited fields\"\n };\n }\n const moveNumber = parseInt(tokens[5], 10);\n if (isNaN(moveNumber) || moveNumber <= 0) {\n return {\n ok: false,\n error: \"Invalid FEN: move number must be a positive integer\"\n };\n }\n const halfMoves = parseInt(tokens[4], 10);\n if (isNaN(halfMoves) || halfMoves < 0) {\n return {\n ok: false,\n error: \"Invalid FEN: half move counter number must be a non-negative integer\"\n };\n }\n if (!/^(-|[abcdefgh][36])$/.test(tokens[3])) {\n return { ok: false, error: \"Invalid FEN: en-passant square is invalid\" };\n }\n if (/[^kKqQ-]/.test(tokens[2])) {\n return { ok: false, error: \"Invalid FEN: castling availability is invalid\" };\n }\n if (!/^(w|b)$/.test(tokens[1])) {\n return { ok: false, error: \"Invalid FEN: side-to-move is invalid\" };\n }\n const rows = tokens[0].split(\"/\");\n if (rows.length !== 8) {\n return {\n ok: false,\n error: \"Invalid FEN: piece data does not contain 8 '/'-delimited rows\"\n };\n }\n for (let i = 0; i < rows.length; i++) {\n let sumFields = 0;\n let previousWasNumber = false;\n for (let k = 0; k < rows[i].length; k++) {\n if (isDigit(rows[i][k])) {\n if (previousWasNumber) {\n return {\n ok: false,\n error: \"Invalid FEN: piece data is invalid (consecutive number)\"\n };\n }\n sumFields += parseInt(rows[i][k], 10);\n previousWasNumber = true;\n } else {\n if (!/^[prnbqkPRNBQK]$/.test(rows[i][k])) {\n return {\n ok: false,\n error: \"Invalid FEN: piece data is invalid (invalid piece)\"\n };\n }\n sumFields += 1;\n previousWasNumber = false;\n }\n }\n if (sumFields !== 8) {\n return {\n ok: false,\n error: \"Invalid FEN: piece data is invalid (too many squares in rank)\"\n };\n }\n }\n if (tokens[3][1] == \"3\" && tokens[1] == \"w\" || tokens[3][1] == \"6\" && tokens[1] == \"b\") {\n return { ok: false, error: \"Invalid FEN: illegal en-passant square\" };\n }\n const kings = [\n { color: \"white\", regex: /K/g },\n { color: \"black\", regex: /k/g }\n ];\n for (const { color, regex } of kings) {\n if (!regex.test(tokens[0])) {\n return { ok: false, error: `Invalid FEN: missing ${color} king` };\n }\n if ((tokens[0].match(regex) || []).length > 1) {\n return { ok: false, error: `Invalid FEN: too many ${color} kings` };\n }\n }\n if (Array.from(rows[0] + rows[7]).some((char) => char.toUpperCase() === \"P\")) {\n return {\n ok: false,\n error: \"Invalid FEN: some pawns are on the edge rows\"\n };\n }\n return { ok: true };\n}\nfunction getDisambiguator(move, moves) {\n const from = move.from;\n const to = move.to;\n const piece = move.piece;\n let ambiguities = 0;\n let sameRank = 0;\n let sameFile = 0;\n for (let i = 0, len = moves.length; i < len; i++) {\n const ambigFrom = moves[i].from;\n const ambigTo = moves[i].to;\n const ambigPiece = moves[i].piece;\n if (piece === ambigPiece && from !== ambigFrom && to === ambigTo) {\n ambiguities++;\n if (rank(from) === rank(ambigFrom)) {\n sameRank++;\n }\n if (file(from) === file(ambigFrom)) {\n sameFile++;\n }\n }\n }\n if (ambiguities > 0) {\n if (sameRank > 0 && sameFile > 0) {\n return algebraic(from);\n } else if (sameFile > 0) {\n return algebraic(from).charAt(1);\n } else {\n return algebraic(from).charAt(0);\n }\n }\n return \"\";\n}\nfunction addMove(moves, color, from, to, piece, captured = void 0, flags = BITS.NORMAL) {\n const r = rank(to);\n if (piece === PAWN && (r === RANK_1 || r === RANK_8)) {\n for (let i = 0; i < PROMOTIONS.length; i++) {\n const promotion = PROMOTIONS[i];\n moves.push({\n color,\n from,\n to,\n piece,\n captured,\n promotion,\n flags: flags | BITS.PROMOTION\n });\n }\n } else {\n moves.push({\n color,\n from,\n to,\n piece,\n captured,\n flags\n });\n }\n}\nfunction inferPieceType(san) {\n let pieceType = san.charAt(0);\n if (pieceType >= \"a\" && pieceType <= \"h\") {\n const matches = san.match(/[a-h]\\d.*[a-h]\\d/);\n if (matches) {\n return void 0;\n }\n return PAWN;\n }\n pieceType = pieceType.toLowerCase();\n if (pieceType === \"o\") {\n return KING;\n }\n return pieceType;\n}\nfunction strippedSan(move) {\n return move.replace(/=/, \"\").replace(/[+#]?[?!]*$/, \"\");\n}\nvar Chess = class {\n constructor(fen = DEFAULT_POSITION, { skipValidation = false } = {}) {\n __publicField(this, \"_board\", new Array(128));\n __publicField(this, \"_turn\", WHITE);\n __publicField(this, \"_header\", {});\n __publicField(this, \"_kings\", { w: EMPTY, b: EMPTY });\n __publicField(this, \"_epSquare\", -1);\n __publicField(this, \"_halfMoves\", 0);\n __publicField(this, \"_moveNumber\", 0);\n __publicField(this, \"_history\", []);\n __publicField(this, \"_comments\", {});\n __publicField(this, \"_castling\", { w: 0, b: 0 });\n __publicField(this, \"_hash\", 0n);\n // tracks number of times a position has been seen for repetition checking\n __publicField(this, \"_positionCount\", /* @__PURE__ */ new Map());\n this.load(fen, { skipValidation });\n }\n clear({ preserveHeaders = false } = {}) {\n this._board = new Array(128);\n this._kings = { w: EMPTY, b: EMPTY };\n this._turn = WHITE;\n this._castling = { w: 0, b: 0 };\n this._epSquare = EMPTY;\n this._halfMoves = 0;\n this._moveNumber = 1;\n this._history = [];\n this._comments = {};\n this._header = preserveHeaders ? this._header : { ...HEADER_TEMPLATE };\n this._hash = this._computeHash();\n this._positionCount = /* @__PURE__ */ new Map();\n this._header[\"SetUp\"] = null;\n this._header[\"FEN\"] = null;\n }\n load(fen, { skipValidation = false, preserveHeaders = false } = {}) {\n let tokens = fen.split(/\\s+/);\n if (tokens.length >= 2 && tokens.length < 6) {\n const adjustments = [\"-\", \"-\", \"0\", \"1\"];\n fen = tokens.concat(adjustments.slice(-(6 - tokens.length))).join(\" \");\n }\n tokens = fen.split(/\\s+/);\n if (!skipValidation) {\n const { ok, error } = validateFen(fen);\n if (!ok) {\n throw new Error(error);\n }\n }\n const position = tokens[0];\n let square = 0;\n this.clear({ preserveHeaders });\n for (let i = 0; i < position.length; i++) {\n const piece = position.charAt(i);\n if (piece === \"/\") {\n square += 8;\n } else if (isDigit(piece)) {\n square += parseInt(piece, 10);\n } else {\n const color = piece < \"a\" ? WHITE : BLACK;\n this._put({ type: piece.toLowerCase(), color }, algebraic(square));\n square++;\n }\n }\n this._turn = tokens[1];\n if (tokens[2].indexOf(\"K\") > -1) {\n this._castling.w |= BITS.KSIDE_CASTLE;\n }\n if (tokens[2].indexOf(\"Q\") > -1) {\n this._castling.w |= BITS.QSIDE_CASTLE;\n }\n if (tokens[2].indexOf(\"k\") > -1) {\n this._castling.b |= BITS.KSIDE_CASTLE;\n }\n if (tokens[2].indexOf(\"q\") > -1) {\n this._castling.b |= BITS.QSIDE_CASTLE;\n }\n this._epSquare = tokens[3] === \"-\" ? EMPTY : Ox88[tokens[3]];\n this._halfMoves = parseInt(tokens[4], 10);\n this._moveNumber = parseInt(tokens[5], 10);\n this._hash = this._computeHash();\n this._updateSetup(fen);\n this._incPositionCount();\n }\n fen({ forceEnpassantSquare = false } = {}) {\n let empty = 0;\n let fen = \"\";\n for (let i = Ox88.a8; i <= Ox88.h1; i++) {\n if (this._board[i]) {\n if (empty > 0) {\n fen += empty;\n empty = 0;\n }\n const { color, type: piece } = this._board[i];\n fen += color === WHITE ? piece.toUpperCase() : piece.toLowerCase();\n } else {\n empty++;\n }\n if (i + 1 & 136) {\n if (empty > 0) {\n fen += empty;\n }\n if (i !== Ox88.h1) {\n fen += \"/\";\n }\n empty = 0;\n i += 8;\n }\n }\n let castling = \"\";\n if (this._castling[WHITE] & BITS.KSIDE_CASTLE) {\n castling += \"K\";\n }\n if (this._castling[WHITE] & BITS.QSIDE_CASTLE) {\n castling += \"Q\";\n }\n if (this._castling[BLACK] & BITS.KSIDE_CASTLE) {\n castling += \"k\";\n }\n if (this._castling[BLACK] & BITS.QSIDE_CASTLE) {\n castling += \"q\";\n }\n castling = castling || \"-\";\n let epSquare = \"-\";\n if (this._epSquare !== EMPTY) {\n if (forceEnpassantSquare) {\n epSquare = algebraic(this._epSquare);\n } else {\n const bigPawnSquare = this._epSquare + (this._turn === WHITE ? 16 : -16);\n const squares = [bigPawnSquare + 1, bigPawnSquare - 1];\n for (const square of squares) {\n if (square & 136) {\n continue;\n }\n const color = this._turn;\n if (this._board[square]?.color === color && this._board[square]?.type === PAWN) {\n this._makeMove({\n color,\n from: square,\n to: this._epSquare,\n piece: PAWN,\n captured: PAWN,\n flags: BITS.EP_CAPTURE\n });\n const isLegal = !this._isKingAttacked(color);\n this._undoMove();\n if (isLegal) {\n epSquare = algebraic(this._epSquare);\n break;\n }\n }\n }\n }\n }\n return [\n fen,\n this._turn,\n castling,\n epSquare,\n this._halfMoves,\n this._moveNumber\n ].join(\" \");\n }\n _pieceKey(i) {\n if (!this._board[i]) {\n return 0n;\n }\n const { color, type } = this._board[i];\n const colorIndex = {\n w: 0,\n b: 1\n }[color];\n const typeIndex = {\n p: 0,\n n: 1,\n b: 2,\n r: 3,\n q: 4,\n k: 5\n }[type];\n return PIECE_KEYS[colorIndex][typeIndex][i];\n }\n _epKey() {\n return this._epSquare === EMPTY ? 0n : EP_KEYS[this._epSquare & 7];\n }\n _castlingKey() {\n const index = this._castling.w >> 5 | this._castling.b >> 3;\n return CASTLING_KEYS[index];\n }\n _computeHash() {\n let hash = 0n;\n for (let i = Ox88.a8; i <= Ox88.h1; i++) {\n if (i & 136) {\n i += 7;\n continue;\n }\n if (this._board[i]) {\n hash ^= this._pieceKey(i);\n }\n }\n hash ^= this._epKey();\n hash ^= this._castlingKey();\n if (this._turn === \"b\") {\n hash ^= SIDE_KEY;\n }\n return hash;\n }\n /*\n * Called when the initial board setup is changed with put() or remove().\n * modifies the SetUp and FEN properties of the header object. If the FEN\n * is equal to the default position, the SetUp and FEN are deleted the setup\n * is only updated if history.length is zero, ie moves haven't been made.\n */\n _updateSetup(fen) {\n if (this._history.length > 0)\n return;\n if (fen !== DEFAULT_POSITION) {\n this._header[\"SetUp\"] = \"1\";\n this._header[\"FEN\"] = fen;\n } else {\n this._header[\"SetUp\"] = null;\n this._header[\"FEN\"] = null;\n }\n }\n reset() {\n this.load(DEFAULT_POSITION);\n }\n get(square) {\n return this._board[Ox88[square]];\n }\n findPiece(piece) {\n const squares = [];\n for (let i = Ox88.a8; i <= Ox88.h1; i++) {\n if (i & 136) {\n i += 7;\n continue;\n }\n if (!this._board[i] || this._board[i]?.color !== piece.color) {\n continue;\n }\n if (this._board[i].color === piece.color && this._board[i].type === piece.type) {\n squares.push(algebraic(i));\n }\n }\n return squares;\n }\n put({ type, color }, square) {\n if (this._put({ type, color }, square)) {\n this._updateCastlingRights();\n this._updateEnPassantSquare();\n this._updateSetup(this.fen());\n return true;\n }\n return false;\n }\n _set(sq, piece) {\n this._hash ^= this._pieceKey(sq);\n this._board[sq] = piece;\n this._hash ^= this._pieceKey(sq);\n }\n _put({ type, color }, square) {\n if (SYMBOLS.indexOf(type.toLowerCase()) === -1) {\n return false;\n }\n if (!(square in Ox88)) {\n return false;\n }\n const sq = Ox88[square];\n if (type == KING && !(this._kings[color] == EMPTY || this._kings[color] == sq)) {\n return false;\n }\n const currentPieceOnSquare = this._board[sq];\n if (currentPieceOnSquare && currentPieceOnSquare.type === KING) {\n this._kings[currentPieceOnSquare.color] = EMPTY;\n }\n this._set(sq, { type, color });\n if (type === KING) {\n this._kings[color] = sq;\n }\n return true;\n }\n _clear(sq) {\n this._hash ^= this._pieceKey(sq);\n delete this._board[sq];\n }\n remove(square) {\n const piece = this.get(square);\n this._clear(Ox88[square]);\n if (piece && piece.type === KING) {\n this._kings[piece.color] = EMPTY;\n }\n this._updateCastlingRights();\n this._updateEnPassantSquare();\n this._updateSetup(this.fen());\n return piece;\n }\n _updateCastlingRights() {\n this._hash ^= this._castlingKey();\n const whiteKingInPlace = this._board[Ox88.e1]?.type === KING && this._board[Ox88.e1]?.color === WHITE;\n const blackKingInPlace = this._board[Ox88.e8]?.type === KING && this._board[Ox88.e8]?.color === BLACK;\n if (!whiteKingInPlace || this._board[Ox88.a1]?.type !== ROOK || this._board[Ox88.a1]?.color !== WHITE) {\n this._castling.w &= -65;\n }\n if (!whiteKingInPlace || this._board[Ox88.h1]?.type !== ROOK || this._board[Ox88.h1]?.color !== WHITE) {\n this._castling.w &= -33;\n }\n if (!blackKingInPlace || this._board[Ox88.a8]?.type !== ROOK || this._board[Ox88.a8]?.color !== BLACK) {\n this._castling.b &= -65;\n }\n if (!blackKingInPlace || this._board[Ox88.h8]?.type !== ROOK || this._board[Ox88.h8]?.color !== BLACK) {\n this._castling.b &= -33;\n }\n this._hash ^= this._castlingKey();\n }\n _updateEnPassantSquare() {\n if (this._epSquare === EMPTY) {\n return;\n }\n const startSquare = this._epSquare + (this._turn === WHITE ? -16 : 16);\n const currentSquare = this._epSquare + (this._turn === WHITE ? 16 : -16);\n const attackers = [currentSquare + 1, currentSquare - 1];\n if (this._board[startSquare] !== null || this._board[this._epSquare] !== null || this._board[currentSquare]?.color !== swapColor(this._turn) || this._board[currentSquare]?.type !== PAWN) {\n this._hash ^= this._epKey();\n this._epSquare = EMPTY;\n return;\n }\n const canCapture = (square) => !(square & 136) && this._board[square]?.color === this._turn && this._board[square]?.type === PAWN;\n if (!attackers.some(canCapture)) {\n this._hash ^= this._epKey();\n this._epSquare = EMPTY;\n }\n }\n _attacked(color, square, verbose) {\n const attackers = [];\n for (let i = Ox88.a8; i <= Ox88.h1; i++) {\n if (i & 136) {\n i += 7;\n continue;\n }\n if (this._board[i] === void 0 || this._board[i].color !== color) {\n continue;\n }\n const piece = this._board[i];\n const difference = i - square;\n if (difference === 0) {\n continue;\n }\n const index = difference + 119;\n if (ATTACKS[index] & PIECE_MASKS[piece.type]) {\n if (piece.type === PAWN) {\n if (difference > 0 && piece.color === WHITE || difference <= 0 && piece.color === BLACK) {\n if (!verbose) {\n return true;\n } else {\n attackers.push(algebraic(i));\n }\n }\n continue;\n }\n if (piece.type === \"n\" || piece.type === \"k\") {\n if (!verbose) {\n return true;\n } else {\n attackers.push(algebraic(i));\n continue;\n }\n }\n const offset = RAYS[index];\n let j = i + offset;\n let blocked = false;\n while (j !== square) {\n if (this._board[j] != null) {\n blocked = true;\n break;\n }\n j += offset;\n }\n if (!blocked) {\n if (!verbose) {\n return true;\n } else {\n attackers.push(algebraic(i));\n continue;\n }\n }\n }\n }\n if (verbose) {\n return attackers;\n } else {\n return false;\n }\n }\n attackers(square, attackedBy) {\n if (!attackedBy) {\n return this._attacked(this._turn, Ox88[square], true);\n } else {\n return this._attacked(attackedBy, Ox88[square], true);\n }\n }\n _isKingAttacked(color) {\n const square = this._kings[color];\n return square === -1 ? false : this._attacked(swapColor(color), square);\n }\n hash() {\n return this._hash.toString(16);\n }\n isAttacked(square, attackedBy) {\n return this._attacked(attackedBy, Ox88[square]);\n }\n isCheck() {\n return this._isKingAttacked(this._turn);\n }\n inCheck() {\n return this.isCheck();\n }\n isCheckmate() {\n return this.isCheck() && this._moves().length === 0;\n }\n isStalemate() {\n return !this.isCheck() && this._moves().length === 0;\n }\n isInsufficientMaterial() {\n const pieces = {\n b: 0,\n n: 0,\n r: 0,\n q: 0,\n k: 0,\n p: 0\n };\n const bishops = [];\n let numPieces = 0;\n let squareColor = 0;\n for (let i = Ox88.a8; i <= Ox88.h1; i++) {\n squareColor = (squareColor + 1) % 2;\n if (i & 136) {\n i += 7;\n continue;\n }\n const piece = this._board[i];\n if (piece) {\n pieces[piece.type] = piece.type in pieces ? pieces[piece.type] + 1 : 1;\n if (piece.type === BISHOP) {\n bishops.push(squareColor);\n }\n numPieces++;\n }\n }\n if (numPieces === 2) {\n return true;\n } else if (\n // k vs. kn .... or .... k vs. kb\n numPieces === 3 && (pieces[BISHOP] === 1 || pieces[KNIGHT] === 1)\n ) {\n return true;\n } else if (numPieces === pieces[BISHOP] + 2) {\n let sum = 0;\n const len = bishops.length;\n for (let i = 0; i < len; i++) {\n sum += bishops[i];\n }\n if (sum === 0 || sum === len) {\n return true;\n }\n }\n return false;\n }\n isThreefoldRepetition() {\n return this._getPositionCount(this._hash) >= 3;\n }\n isDrawByFiftyMoves() {\n return this._halfMoves >= 100;\n }\n isDraw() {\n return this.isDrawByFiftyMoves() || this.isStalemate() || this.isInsufficientMaterial() || this.isThreefoldRepetition();\n }\n isGameOver() {\n return this.isCheckmate() || this.isDraw();\n }\n moves({ verbose = false, square = void 0, piece = void 0 } = {}) {\n const moves = this._moves({ square, piece });\n if (verbose) {\n return moves.map((move) => new Move(this, move));\n } else {\n return moves.map((move) => this._moveToSan(move, moves));\n }\n }\n _moves({ legal = true, piece = void 0, square = void 0 } = {}) {\n const forSquare = square ? square.toLowerCase() : void 0;\n const forPiece = piece?.toLowerCase();\n const moves = [];\n const us = this._turn;\n const them = swapColor(us);\n let firstSquare = Ox88.a8;\n let lastSquare = Ox88.h1;\n let singleSquare = false;\n if (forSquare) {\n if (!(forSquare in Ox88)) {\n return [];\n } else {\n firstSquare = lastSquare = Ox88[forSquare];\n singleSquare = true;\n }\n }\n for (let from = firstSquare; from <= lastSquare; from++) {\n if (from & 136) {\n from += 7;\n continue;\n }\n if (!this._board[from] || this._board[from].color === them) {\n continue;\n }\n const { type } = this._board[from];\n let to;\n if (type === PAWN) {\n if (forPiece && forPiece !== type)\n continue;\n to = from + PAWN_OFFSETS[us][0];\n if (!this._board[to]) {\n addMove(moves, us, from, to, PAWN);\n to = from + PAWN_OFFSETS[us][1];\n if (SECOND_RANK[us] === rank(from) && !this._board[to]) {\n addMove(moves, us, from, to, PAWN, void 0, BITS.BIG_PAWN);\n }\n }\n for (let j = 2; j < 4; j++) {\n to = from + PAWN_OFFSETS[us][j];\n if (to & 136)\n continue;\n if (this._board[to]?.color === them) {\n addMove(moves, us, from, to, PAWN, this._board[to].type, BITS.CAPTURE);\n } else if (to === this._epSquare) {\n addMove(moves, us, from, to, PAWN, PAWN, BITS.EP_CAPTURE);\n }\n }\n } else {\n if (forPiece && forPiece !== type)\n continue;\n for (let j = 0, len = PIECE_OFFSETS[type].length; j < len; j++) {\n const offset = PIECE_OFFSETS[type][j];\n to = from;\n while (true) {\n to += offset;\n if (to & 136)\n break;\n if (!this._board[to]) {\n addMove(moves, us, from, to, type);\n } else {\n if (this._board[to].color === us)\n break;\n addMove(moves, us, from, to, type, this._board[to].type, BITS.CAPTURE);\n break;\n }\n if (type === KNIGHT || type === KING)\n break;\n }\n }\n }\n }\n if (forPiece === void 0 || forPiece === KING) {\n if (!singleSquare || lastSquare === this._kings[us]) {\n if (this._castling[us] & BITS.KSIDE_CASTLE) {\n const castlingFrom = this._kings[us];\n const castlingTo = castlingFrom + 2;\n if (!this._board[castlingFrom + 1] && !this._board[castlingTo] && !this._attacked(them, this._kings[us]) && !this._attacked(them, castlingFrom + 1) && !this._attacked(them, castlingTo)) {\n addMove(moves, us, this._kings[us], castlingTo, KING, void 0, BITS.KSIDE_CASTLE);\n }\n }\n if (this._castling[us] & BITS.QSIDE_CASTLE) {\n const castlingFrom = this._kings[us];\n const castlingTo = castlingFrom - 2;\n if (!this._board[castlingFrom - 1] && !this._board[castlingFrom - 2] && !this._board[castlingFrom - 3] && !this._attacked(them, this._kings[us]) && !this._attacked(them, castlingFrom - 1) && !this._attacked(them, castlingTo)) {\n addMove(moves, us, this._kings[us], castlingTo, KING, void 0, BITS.QSIDE_CASTLE);\n }\n }\n }\n }\n if (!legal || this._kings[us] === -1) {\n return moves;\n }\n const legalMoves2 = [];\n for (let i = 0, len = moves.length; i < len; i++) {\n this._makeMove(moves[i]);\n if (!this._isKingAttacked(us)) {\n legalMoves2.push(moves[i]);\n }\n this._undoMove();\n }\n return legalMoves2;\n }\n move(move, { strict = false } = {}) {\n let moveObj = null;\n if (typeof move === \"string\") {\n moveObj = this._moveFromSan(move, strict);\n } else if (move === null) {\n moveObj = this._moveFromSan(SAN_NULLMOVE, strict);\n } else if (typeof move === \"object\") {\n const moves = this._moves();\n for (let i = 0, len = moves.length; i < len; i++) {\n if (move.from === algebraic(moves[i].from) && move.to === algebraic(moves[i].to) && (!(\"promotion\" in moves[i]) || move.promotion === moves[i].promotion)) {\n moveObj = moves[i];\n break;\n }\n }\n }\n if (!moveObj) {\n if (typeof move === \"string\") {\n throw new Error(`Invalid move: ${move}`);\n } else {\n throw new Error(`Invalid move: ${JSON.stringify(move)}`);\n }\n }\n if (this.isCheck() && moveObj.flags & BITS.NULL_MOVE) {\n throw new Error(\"Null move not allowed when in check\");\n }\n const prettyMove = new Move(this, moveObj);\n this._makeMove(moveObj);\n this._incPositionCount();\n return prettyMove;\n }\n _push(move) {\n this._history.push({\n move,\n kings: { b: this._kings.b, w: this._kings.w },\n turn: this._turn,\n castling: { b: this._castling.b, w: this._castling.w },\n epSquare: this._epSquare,\n halfMoves: this._halfMoves,\n moveNumber: this._moveNumber\n });\n }\n _movePiece(from, to) {\n this._hash ^= this._pieceKey(from);\n this._board[to] = this._board[from];\n delete this._board[from];\n this._hash ^= this._pieceKey(to);\n }\n _makeMove(move) {\n const us = this._turn;\n const them = swapColor(us);\n this._push(move);\n if (move.flags & BITS.NULL_MOVE) {\n if (us === BLACK) {\n this._moveNumber++;\n }\n this._halfMoves++;\n this._turn = them;\n this._epSquare = EMPTY;\n return;\n }\n this._hash ^= this._epKey();\n this._hash ^= this._castlingKey();\n if (move.captured) {\n this._hash ^= this._pieceKey(move.to);\n }\n this._movePiece(move.from, move.to);\n if (move.flags & BITS.EP_CAPTURE) {\n if (this._turn === BLACK) {\n this._clear(move.to - 16);\n } else {\n this._clear(move.to + 16);\n }\n }\n if (move.promotion) {\n this._clear(move.to);\n this._set(move.to, { type: move.promotion, color: us });\n }\n if (this._board[move.to].type === KING) {\n this._kings[us] = move.to;\n if (move.flags & BITS.KSIDE_CASTLE) {\n const castlingTo = move.to - 1;\n const castlingFrom = move.to + 1;\n this._movePiece(castlingFrom, castlingTo);\n } else if (move.flags & BITS.QSIDE_CASTLE) {\n const castlingTo = move.to + 1;\n const castlingFrom = move.to - 2;\n this._movePiece(castlingFrom, castlingTo);\n }\n this._castling[us] = 0;\n }\n if (this._castling[us]) {\n for (let i = 0, len = ROOKS[us].length; i < len; i++) {\n if (move.from === ROOKS[us][i].square && this._castling[us] & ROOKS[us][i].flag) {\n this._castling[us] ^= ROOKS[us][i].flag;\n break;\n }\n }\n }\n if (this._castling[them]) {\n for (let i = 0, len = ROOKS[them].length; i < len; i++) {\n if (move.to === ROOKS[them][i].square && this._castling[them] & ROOKS[them][i].flag) {\n this._castling[them] ^= ROOKS[them][i].flag;\n break;\n }\n }\n }\n this._hash ^= this._castlingKey();\n if (move.flags & BITS.BIG_PAWN) {\n let epSquare;\n if (us === BLACK) {\n epSquare = move.to - 16;\n } else {\n epSquare = move.to + 16;\n }\n if (!(move.to - 1 & 136) && this._board[move.to - 1]?.type === PAWN && this._board[move.to - 1]?.color === them || !(move.to + 1 & 136) && this._board[move.to + 1]?.type === PAWN && this._board[move.to + 1]?.color === them) {\n this._epSquare = epSquare;\n this._hash ^= this._epKey();\n } else {\n this._epSquare = EMPTY;\n }\n } else {\n this._epSquare = EMPTY;\n }\n if (move.piece === PAWN) {\n this._halfMoves = 0;\n } else if (move.flags & (BITS.CAPTURE | BITS.EP_CAPTURE)) {\n this._halfMoves = 0;\n } else {\n this._halfMoves++;\n }\n if (us === BLACK) {\n this._moveNumber++;\n }\n this._turn = them;\n this._hash ^= SIDE_KEY;\n }\n undo() {\n const hash = this._hash;\n const move = this._undoMove();\n if (move) {\n const prettyMove = new Move(this, move);\n this._decPositionCount(hash);\n return prettyMove;\n }\n return null;\n }\n _undoMove() {\n const old = this._history.pop();\n if (old === void 0) {\n return null;\n }\n this._hash ^= this._epKey();\n this._hash ^= this._castlingKey();\n const move = old.move;\n this._kings = old.kings;\n this._turn = old.turn;\n this._castling = old.castling;\n this._epSquare = old.epSquare;\n this._halfMoves = old.halfMoves;\n this._moveNumber = old.moveNumber;\n this._hash ^= this._epKey();\n this._hash ^= this._castlingKey();\n this._hash ^= SIDE_KEY;\n const us = this._turn;\n const them = swapColor(us);\n if (move.flags & BITS.NULL_MOVE) {\n return move;\n }\n this._movePiece(move.to, move.from);\n if (move.piece) {\n this._clear(move.from);\n this._set(move.from, { type: move.piece, color: us });\n }\n if (move.captured) {\n if (move.flags & BITS.EP_CAPTURE) {\n let index;\n if (us === BLACK) {\n index = move.to - 16;\n } else {\n index = move.to + 16;\n }\n this._set(index, { type: PAWN, color: them });\n } else {\n this._set(move.to, { type: move.captured, color: them });\n }\n }\n if (move.flags & (BITS.KSIDE_CASTLE | BITS.QSIDE_CASTLE)) {\n let castlingTo, castlingFrom;\n if (move.flags & BITS.KSIDE_CASTLE) {\n castlingTo = move.to + 1;\n castlingFrom = move.to - 1;\n } else {\n castlingTo = move.to - 2;\n castlingFrom = move.to + 1;\n }\n this._movePiece(castlingFrom, castlingTo);\n }\n return move;\n }\n pgn({ newline = \"\\n\", maxWidth = 0 } = {}) {\n const result = [];\n let headerExists = false;\n for (const i in this._header) {\n const headerTag = this._header[i];\n if (headerTag)\n result.push(`[${i} \"${this._header[i]}\"]` + newline);\n headerExists = true;\n }\n if (headerExists && this._history.length) {\n result.push(newline);\n }\n const appendComment = (moveString2) => {\n const comment = this._comments[this.fen()];\n if (typeof comment !== \"undefined\") {\n const delimiter = moveString2.length > 0 ? \" \" : \"\";\n moveString2 = `${moveString2}${delimiter}{${comment}}`;\n }\n return moveString2;\n };\n const reversedHistory = [];\n while (this._history.length > 0) {\n reversedHistory.push(this._undoMove());\n }\n const moves = [];\n let moveString = \"\";\n if (reversedHistory.length === 0) {\n moves.push(appendComment(\"\"));\n }\n while (reversedHistory.length > 0) {\n moveString = appendComment(moveString);\n const move = reversedHistory.pop();\n if (!move) {\n break;\n }\n if (!this._history.length && move.color === \"b\") {\n const prefix = `${this._moveNumber}. ...`;\n moveString = moveString ? `${moveString} ${prefix}` : prefix;\n } else if (move.color === \"w\") {\n if (moveString.length) {\n moves.push(moveString);\n }\n moveString = this._moveNumber + \".\";\n }\n moveString = moveString + \" \" + this._moveToSan(move, this._moves({ legal: true }));\n this._makeMove(move);\n }\n if (moveString.length) {\n moves.push(appendComment(moveString));\n }\n moves.push(this._header.Result || \"*\");\n if (maxWidth === 0) {\n return result.join(\"\") + moves.join(\" \");\n }\n const strip = function() {\n if (result.length > 0 && result[result.length - 1] === \" \") {\n result.pop();\n return true;\n }\n return false;\n };\n const wrapComment = function(width, move) {\n for (const token of move.split(\" \")) {\n if (!token) {\n continue;\n }\n if (width + token.length > maxWidth) {\n while (strip()) {\n width--;\n }\n result.push(newline);\n width = 0;\n }\n result.push(token);\n width += token.length;\n result.push(\" \");\n width++;\n }\n if (strip()) {\n width--;\n }\n return width;\n };\n let currentWidth = 0;\n for (let i = 0; i < moves.length; i++) {\n if (currentWidth + moves[i].length > maxWidth) {\n if (moves[i].includes(\"{\")) {\n currentWidth = wrapComment(currentWidth, moves[i]);\n continue;\n }\n }\n if (currentWidth + moves[i].length > maxWidth && i !== 0) {\n if (result[result.length - 1] === \" \") {\n result.pop();\n }\n result.push(newline);\n currentWidth = 0;\n } else if (i !== 0) {\n result.push(\" \");\n currentWidth++;\n }\n result.push(moves[i]);\n currentWidth += moves[i].length;\n }\n return result.join(\"\");\n }\n /**\n * @deprecated Use `setHeader` and `getHeaders` instead. This method will return null header tags (which is not what you want)\n */\n header(...args) {\n for (let i = 0; i < args.length; i += 2) {\n if (typeof args[i] === \"string\" && typeof args[i + 1] === \"string\") {\n this._header[args[i]] = args[i + 1];\n }\n }\n return this._header;\n }\n // TODO: value validation per spec\n setHeader(key, value) {\n this._header[key] = value ?? SEVEN_TAG_ROSTER[key] ?? null;\n return this.getHeaders();\n }\n removeHeader(key) {\n if (key in this._header) {\n this._header[key] = SEVEN_TAG_ROSTER[key] || null;\n return true;\n }\n return false;\n }\n // return only non-null headers (omit placemarker nulls)\n getHeaders() {\n const nonNullHeaders = {};\n for (const [key, value] of Object.entries(this._header)) {\n if (value !== null) {\n nonNullHeaders[key] = value;\n }\n }\n return nonNullHeaders;\n }\n loadPgn(pgn2, { strict = false, newlineChar = \"\\r?\\n\" } = {}) {\n if (newlineChar !== \"\\r?\\n\") {\n pgn2 = pgn2.replace(new RegExp(newlineChar, \"g\"), \"\\n\");\n }\n const parsedPgn = peg$parse(pgn2);\n this.reset();\n const headers = parsedPgn.headers;\n let fen = \"\";\n for (const key in headers) {\n if (key.toLowerCase() === \"fen\") {\n fen = headers[key];\n }\n this.header(key, headers[key]);\n }\n if (!strict) {\n if (fen) {\n this.load(fen, { preserveHeaders: true });\n }\n } else {\n if (headers[\"SetUp\"] === \"1\") {\n if (!(\"FEN\" in headers)) {\n throw new Error(\"Invalid PGN: FEN tag must be supplied with SetUp tag\");\n }\n this.load(headers[\"FEN\"], { preserveHeaders: true });\n }\n }\n let node2 = parsedPgn.root;\n while (node2) {\n if (node2.move) {\n const move = this._moveFromSan(node2.move, strict);\n if (move == null) {\n throw new Error(`Invalid move in PGN: ${node2.move}`);\n } else {\n this._makeMove(move);\n this._incPositionCount();\n }\n }\n if (node2.comment !== void 0) {\n this._comments[this.fen()] = node2.comment;\n }\n node2 = node2.variations[0];\n }\n const result = parsedPgn.result;\n if (result && Object.keys(this._header).length && this._header[\"Result\"] !== result) {\n this.setHeader(\"Result\", result);\n }\n }\n /*\n * Convert a move from 0x88 coordinates to Standard Algebraic Notation\n * (SAN)\n *\n * @param {boolean} strict Use the strict SAN parser. It will throw errors\n * on overly disambiguated moves (see below):\n *\n * r1bqkbnr/ppp2ppp/2n5/1B1pP3/4P3/8/PPPP2PP/RNBQK1NR b KQkq - 2 4\n * 4. ... Nge7 is overly disambiguated because the knight on c6 is pinned\n * 4. ... Ne7 is technically the valid SAN\n */\n _moveToSan(move, moves) {\n let output = \"\";\n if (move.flags & BITS.KSIDE_CASTLE) {\n output = \"O-O\";\n } else if (move.flags & BITS.QSIDE_CASTLE) {\n output = \"O-O-O\";\n } else if (move.flags & BITS.NULL_MOVE) {\n return SAN_NULLMOVE;\n } else {\n if (move.piece !== PAWN) {\n const disambiguator = getDisambiguator(move, moves);\n output += move.piece.toUpperCase() + disambiguator;\n }\n if (move.flags & (BITS.CAPTURE | BITS.EP_CAPTURE)) {\n if (move.piece === PAWN) {\n output += algebraic(move.from)[0];\n }\n output += \"x\";\n }\n output += algebraic(move.to);\n if (move.promotion) {\n output += \"=\" + move.promotion.toUpperCase();\n }\n }\n this._makeMove(move);\n if (this.isCheck()) {\n if (this.isCheckmate()) {\n output += \"#\";\n } else {\n output += \"+\";\n }\n }\n this._undoMove();\n return output;\n }\n // convert a move from Standard Algebraic Notation (SAN) to 0x88 coordinates\n _moveFromSan(move, strict = false) {\n let cleanMove = strippedSan(move);\n if (!strict) {\n if (cleanMove === \"0-0\") {\n cleanMove = \"O-O\";\n } else if (cleanMove === \"0-0-0\") {\n cleanMove = \"O-O-O\";\n }\n }\n if (cleanMove == SAN_NULLMOVE) {\n const res = {\n color: this._turn,\n from: 0,\n to: 0,\n piece: \"k\",\n flags: BITS.NULL_MOVE\n };\n return res;\n }\n let pieceType = inferPieceType(cleanMove);\n let moves = this._moves({ legal: true, piece: pieceType });\n for (let i = 0, len = moves.length; i < len; i++) {\n if (cleanMove === strippedSan(this._moveToSan(moves[i], moves))) {\n return moves[i];\n }\n }\n if (strict) {\n return null;\n }\n let piece = void 0;\n let matches = void 0;\n let from = void 0;\n let to = void 0;\n let promotion = void 0;\n let overlyDisambiguated = false;\n matches = cleanMove.match(/([pnbrqkPNBRQK])?([a-h][1-8])x?-?([a-h][1-8])([qrbnQRBN])?/);\n if (matches) {\n piece = matches[1];\n from = matches[2];\n to = matches[3];\n promotion = matches[4];\n if (from.length == 1) {\n overlyDisambiguated = true;\n }\n } else {\n matches = cleanMove.match(/([pnbrqkPNBRQK])?([a-h]?[1-8]?)x?-?([a-h][1-8])([qrbnQRBN])?/);\n if (matches) {\n piece = matches[1];\n from = matches[2];\n to = matches[3];\n promotion = matches[4];\n if (from.length == 1) {\n overlyDisambiguated = true;\n }\n }\n }\n pieceType = inferPieceType(cleanMove);\n moves = this._moves({\n legal: true,\n piece: piece ? piece : pieceType\n });\n if (!to) {\n return null;\n }\n for (let i = 0, len = moves.length; i < len; i++) {\n if (!from) {\n if (cleanMove === strippedSan(this._moveToSan(moves[i], moves)).replace(\"x\", \"\")) {\n return moves[i];\n }\n } else if ((!piece || piece.toLowerCase() == moves[i].piece) && Ox88[from] == moves[i].from && Ox88[to] == moves[i].to && (!promotion || promotion.toLowerCase() == moves[i].promotion)) {\n return moves[i];\n } else if (overlyDisambiguated) {\n const square = algebraic(moves[i].from);\n if ((!piece || piece.toLowerCase() == moves[i].piece) && Ox88[to] == moves[i].to && (from == square[0] || from == square[1]) && (!promotion || promotion.toLowerCase() == moves[i].promotion)) {\n return moves[i];\n }\n }\n }\n return null;\n }\n ascii() {\n let s = \" +------------------------+\\n\";\n for (let i = Ox88.a8; i <= Ox88.h1; i++) {\n if (file(i) === 0) {\n s += \" \" + \"87654321\"[rank(i)] + \" |\";\n }\n if (this._board[i]) {\n const piece = this._board[i].type;\n const color = this._board[i].color;\n const symbol = color === WHITE ? piece.toUpperCase() : piece.toLowerCase();\n s += \" \" + symbol + \" \";\n } else {\n s += \" . \";\n }\n if (i + 1 & 136) {\n s += \"|\\n\";\n i += 8;\n }\n }\n s += \" +------------------------+\\n\";\n s += \" a b c d e f g h\";\n return s;\n }\n perft(depth) {\n const moves = this._moves({ legal: false });\n let nodes = 0;\n const color = this._turn;\n for (let i = 0, len = moves.length; i < len; i++) {\n this._makeMove(moves[i]);\n if (!this._isKingAttacked(color)) {\n if (depth - 1 > 0) {\n nodes += this.perft(depth - 1);\n } else {\n nodes++;\n }\n }\n this._undoMove();\n }\n return nodes;\n }\n setTurn(color) {\n if (this._turn == color) {\n return false;\n }\n this.move(\"--\");\n return true;\n }\n turn() {\n return this._turn;\n }\n board() {\n const output = [];\n let row = [];\n for (let i = Ox88.a8; i <= Ox88.h1; i++) {\n if (this._board[i] == null) {\n row.push(null);\n } else {\n row.push({\n square: algebraic(i),\n type: this._board[i].type,\n color: this._board[i].color\n });\n }\n if (i + 1 & 136) {\n output.push(row);\n row = [];\n i += 8;\n }\n }\n return output;\n }\n squareColor(square) {\n if (square in Ox88) {\n const sq = Ox88[square];\n return (rank(sq) + file(sq)) % 2 === 0 ? \"light\" : \"dark\";\n }\n return null;\n }\n history({ verbose = false } = {}) {\n const reversedHistory = [];\n const moveHistory = [];\n while (this._history.length > 0) {\n reversedHistory.push(this._undoMove());\n }\n while (true) {\n const move = reversedHistory.pop();\n if (!move) {\n break;\n }\n if (verbose) {\n moveHistory.push(new Move(this, move));\n } else {\n moveHistory.push(this._moveToSan(move, this._moves()));\n }\n this._makeMove(move);\n }\n return moveHistory;\n }\n /*\n * Keeps track of position occurrence counts for the purpose of repetition\n * checking. Old positions are removed from the map if their counts are reduced to 0.\n */\n _getPositionCount(hash) {\n return this._positionCount.get(hash) ?? 0;\n }\n _incPositionCount() {\n this._positionCount.set(this._hash, (this._positionCount.get(this._hash) ?? 0) + 1);\n }\n _decPositionCount(hash) {\n const currentCount = this._positionCount.get(hash) ?? 0;\n if (currentCount === 1) {\n this._positionCount.delete(hash);\n } else {\n this._positionCount.set(hash, currentCount - 1);\n }\n }\n _pruneComments() {\n const reversedHistory = [];\n const currentComments = {};\n const copyComment = (fen) => {\n if (fen in this._comments) {\n currentComments[fen] = this._comments[fen];\n }\n };\n while (this._history.length > 0) {\n reversedHistory.push(this._undoMove());\n }\n copyComment(this.fen());\n while (true) {\n const move = reversedHistory.pop();\n if (!move) {\n break;\n }\n this._makeMove(move);\n copyComment(this.fen());\n }\n this._comments = currentComments;\n }\n getComment() {\n return this._comments[this.fen()];\n }\n setComment(comment) {\n this._comments[this.fen()] = comment.replace(\"{\", \"[\").replace(\"}\", \"]\");\n }\n /**\n * @deprecated Renamed to `removeComment` for consistency\n */\n deleteComment() {\n return this.removeComment();\n }\n removeComment() {\n const comment = this._comments[this.fen()];\n delete this._comments[this.fen()];\n return comment;\n }\n getComments() {\n this._pruneComments();\n return Object.keys(this._comments).map((fen) => {\n return { fen, comment: this._comments[fen] };\n });\n }\n /**\n * @deprecated Renamed to `removeComments` for consistency\n */\n deleteComments() {\n return this.removeComments();\n }\n removeComments() {\n this._pruneComments();\n return Object.keys(this._comments).map((fen) => {\n const comment = this._comments[fen];\n delete this._comments[fen];\n return { fen, comment };\n });\n }\n setCastlingRights(color, rights) {\n for (const side of [KING, QUEEN]) {\n if (rights[side] !== void 0) {\n if (rights[side]) {\n this._castling[color] |= SIDES[side];\n } else {\n this._castling[color] &= ~SIDES[side];\n }\n }\n }\n this._updateCastlingRights();\n const result = this.getCastlingRights(color);\n return (rights[KING] === void 0 || rights[KING] === result[KING]) && (rights[QUEEN] === void 0 || rights[QUEEN] === result[QUEEN]);\n }\n getCastlingRights(color) {\n return {\n [KING]: (this._castling[color] & SIDES[KING]) !== 0,\n [QUEEN]: (this._castling[color] & SIDES[QUEEN]) !== 0\n };\n }\n moveNumber() {\n return this._moveNumber;\n }\n};\n\n// libs/test-harness/fixtures/library-reuse/chess-entry.ts\nvar chess = new Chess();\nvar legalMoves = chess.moves({ verbose: true });\nvar chess_entry_default = legalMoves.some(\n (move) => move.from === \"e2\" && move.to === \"e6\"\n);\nexport {\n chess_entry_default as default\n};\n", + "sourceMap": "{\"mappings\":\";;;;;AAME,SAAS,SAAS,SAAS;AAC1B,SAAO,YAAY,OAAO,EAAE,SAAS,YAAY,CAAA,EAAE,IAAK,EAAE,YAAY,CAAA,EAAE;AAC3E;AAEE,SAAS,KAAK,MAAM,QAAQ,KAAK,SAAS,YAAY;AACrD,QAAMA,QAAO,EAAE,MAAM,WAAU;AAE9B,MAAI,QAAQ;AACX,IAAAA,MAAK,SAAS;EACnB;AAEI,MAAI,KAAK;AACR,IAAAA,MAAK,MAAM;EAChB;AAEI,MAAI,YAAY,MAAM;AACrB,IAAAA,MAAK,UAAU;EACpB;AAEI,SAAOA;AACX;AAEE,SAAS,cAAc,OAAO;AAC7B,QAAM,CAAC,MAAM,GAAG,IAAI,IAAI;AAEvB,MAAI,SAAS;AAEb,aAAW,SAAS,MAAM;AACzB,QAAI,UAAU,MAAM;AAChB,aAAO,aAAa,CAAC,OAAO,GAAG,MAAM,UAAU;AAC5C,YAAM,aAAa,CAAA;AACnB,eAAS;IACrB;EACA;AAEG,SAAO;AACV;AAEE,SAAS,IAAI,SAAS,MAAM;AAC3B,MAAI,KAAK,UAAU,KAAK,OAAO,SAAS;AACtC,QAAIA,QAAO,KAAK;AACb,WAAO,MAAM;AACZ,YAAM,OAAOA,MAAK,WAAW,CAAC;AAC3B,UAAI,CAAC,MAAM;AACV,QAAAA,MAAK,UAAU,KAAK,OAAO;AAC3B;MACb;AACY,MAAAA,QAAO;IACnB;EACA;AAEG,SAAO;IACL;IACG,MAAM,KAAK;IACX,SAAS,KAAK,UAAU,KAAK,OAAO,WAAW;EACvD;AACA;AAEA,SAAS,aAAa,OAAO,QAAQ;AACnC,WAAS,IAAI;AAAE,SAAK,cAAc;EAAM;AACxC,IAAE,YAAY,OAAO;AACrB,QAAM,YAAY,IAAI,EAAC;AACzB;AAEA,SAAS,gBAAgB,SAAS,UAAU,OAAO,UAAU;AAC3D,MAAI,OAAO,MAAM,KAAK,MAAM,OAAO;AAEnC,MAAI,OAAO,gBAAgB;AACzB,WAAO,eAAe,MAAM,gBAAgB,SAAS;EACzD;AACE,OAAK,WAAW;AAChB,OAAK,QAAQ;AACb,OAAK,WAAW;AAChB,OAAK,OAAO;AACZ,SAAO;AACT;AAEA,aAAa,iBAAiB,KAAK;AAEnC,SAAS,WAAW,KAAK,cAAc,WAAW;AAChD,cAAY,aAAa;AACzB,MAAI,IAAI,SAAS,cAAc;AAAE,WAAO;EAAI;AAC5C,kBAAgB,IAAI;AACpB,eAAa,UAAU,OAAO,YAAY;AAC1C,SAAO,MAAM,UAAU,MAAM,GAAG,YAAY;AAC9C;AAEA,gBAAgB,UAAU,SAAS,SAAS,SAAS;AACnD,MAAI,MAAM,YAAY,KAAK;AAC3B,MAAI,KAAK,UAAU;AACjB,QAAI,MAAM;AACV,QAAI;AACJ,SAAK,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACnC,UAAI,QAAQ,CAAC,EAAE,WAAW,KAAK,SAAS,QAAQ;AAC9C,cAAM,QAAQ,CAAC,EAAE,KAAK,MAAM,aAAa;AACzC;MACR;IACA;AACI,QAAI,IAAI,KAAK,SAAS;AACtB,QAAI,WAAY,KAAK,SAAS,UAAW,OAAO,KAAK,SAAS,OAAO,WAAW,aAC5E,KAAK,SAAS,OAAO,OAAO,CAAC,IAC7B;AACJ,QAAI,MAAM,KAAK,SAAS,SAAS,MAAM,SAAS,OAAO,MAAM,SAAS;AACtE,QAAI,KAAK;AACP,UAAI,IAAI,KAAK,SAAS;AACtB,UAAI,SAAS,WAAW,IAAI,SAAS,KAAK,SAAQ,EAAG,QAAQ,GAAG;AAChE,UAAI,OAAO,IAAI,EAAE,OAAO,CAAC;AACzB,UAAI,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,KAAK,SAAS;AACxD,UAAI,SAAU,OAAO,EAAE,UAAW;AAClC,aAAO,YAAY,MAAM,OACnB,SAAS,SACT,SAAS,OAAO,QAAQ,OAAO,OAC/B,SAAS,QAAQ,WAAW,IAAI,EAAE,SAAS,GAAG,GAAG,IACjD,WAAW,IAAI,QAAQ,GAAG;IACtC,OAAW;AACL,aAAO,WAAW;IACxB;EACA;AACE,SAAO;AACT;AAEA,gBAAgB,eAAe,SAAS,UAAU,OAAO;AACvD,MAAI,2BAA2B;IAC7B,SAAS,SAAS,aAAa;AAC7B,aAAO,MAAO,cAAc,YAAY,IAAI,IAAI;IACtD;IAEI,OAAO,SAAS,aAAa;AAC3B,UAAI,eAAe,YAAY,MAAM,IAAI,SAAS,MAAM;AACtD,eAAO,MAAM,QAAQ,IAAI,IACrB,YAAY,KAAK,CAAC,CAAC,IAAI,MAAM,YAAY,KAAK,CAAC,CAAC,IAChD,YAAY,IAAI;MAC5B,CAAO;AAED,aAAO,OAAO,YAAY,WAAW,MAAM,MAAM,aAAa,KAAK,EAAE,IAAI;IAC/E;IAEI,KAAK,WAAW;AACd,aAAO;IACb;IAEI,KAAK,WAAW;AACd,aAAO;IACb;IAEI,OAAO,SAAS,aAAa;AAC3B,aAAO,YAAY;IACzB;EACA;AAEE,WAAS,IAAI,IAAI;AACf,WAAO,GAAG,WAAW,CAAC,EAAE,SAAS,EAAE,EAAE,YAAW;EACpD;AAEE,WAAS,cAAc,GAAG;AACxB,WAAO,EACJ,QAAQ,OAAO,MAAM,EACrB,QAAQ,MAAO,KAAM,EACrB,QAAQ,OAAO,KAAK,EACpB,QAAQ,OAAO,KAAK,EACpB,QAAQ,OAAO,KAAK,EACpB,QAAQ,OAAO,KAAK,EACpB,QAAQ,gBAAyB,SAAS,IAAI;AAAE,aAAO,SAAS,IAAI,EAAE;IAAE,CAAE,EAC1E,QAAQ,yBAAyB,SAAS,IAAI;AAAE,aAAO,QAAS,IAAI,EAAE;IAAE,CAAE;EACjF;AAEE,WAAS,YAAY,GAAG;AACtB,WAAO,EACJ,QAAQ,OAAO,MAAM,EACrB,QAAQ,OAAO,KAAK,EACpB,QAAQ,OAAO,KAAK,EACpB,QAAQ,MAAO,KAAK,EACpB,QAAQ,OAAO,KAAK,EACpB,QAAQ,OAAO,KAAK,EACpB,QAAQ,OAAO,KAAK,EACpB,QAAQ,OAAO,KAAK,EACpB,QAAQ,gBAAyB,SAAS,IAAI;AAAE,aAAO,SAAS,IAAI,EAAE;IAAE,CAAE,EAC1E,QAAQ,yBAAyB,SAAS,IAAI;AAAE,aAAO,QAAS,IAAI,EAAE;IAAE,CAAE;EACjF;AAEE,WAAS,oBAAoB,aAAa;AACxC,WAAO,yBAAyB,YAAY,IAAI,EAAE,WAAW;EACjE;AAEE,WAAS,iBAAiBC,WAAU;AAClC,QAAI,eAAeA,UAAS,IAAI,mBAAmB;AACnD,QAAI,GAAG;AAEP,iBAAa,KAAI;AAEjB,QAAI,aAAa,SAAS,GAAG;AAC3B,WAAK,IAAI,GAAG,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;AAC/C,YAAI,aAAa,IAAI,CAAC,MAAM,aAAa,CAAC,GAAG;AAC3C,uBAAa,CAAC,IAAI,aAAa,CAAC;AAChC;QACV;MACA;AACM,mBAAa,SAAS;IAC5B;AAEI,YAAQ,aAAa,QAAM;MACzB,KAAK;AACH,eAAO,aAAa,CAAC;MAEvB,KAAK;AACH,eAAO,aAAa,CAAC,IAAI,SAAS,aAAa,CAAC;MAElD;AACE,eAAO,aAAa,MAAM,GAAG,EAAE,EAAE,KAAK,IAAI,IACtC,UACA,aAAa,aAAa,SAAS,CAAC;IAChD;EACA;AAEE,WAAS,cAAcC,QAAO;AAC5B,WAAOA,SAAQ,MAAO,cAAcA,MAAK,IAAI,MAAO;EACxD;AAEE,SAAO,cAAc,iBAAiB,QAAQ,IAAI,UAAU,cAAc,KAAK,IAAI;AACrF;AAEA,SAAS,UAAU,OAAO,SAAS;AACjC,YAAU,YAAY,SAAY,UAAU,CAAA;AAE5C,MAAI,aAAa,CAAA;AACjB,MAAI,aAAa,QAAQ;AAEzB,MAAI,yBAAyB,EAAE,KAAK,aAAY;AAChD,MAAI,wBAAwB;AAE5B,MAAI,SAAS;AACb,MAAI,SAAS;AACb,MAAI,SAAS;AACb,MAAI,SAAS;AACb,MAAI,SAAS;AACb,MAAI,SAAS;AACb,MAAI,SAAS;AACb,MAAI,SAAS;AACb,MAAI,SAAS;AACb,MAAI,SAAS;AACb,MAAI,UAAU;AACd,MAAI,UAAU;AACd,MAAI,UAAU;AACd,MAAI,UAAU;AACd,MAAI,UAAU;AACd,MAAI,UAAU;AACd,MAAI,UAAU;AACd,MAAI,UAAU;AAEd,MAAI,SAAS;AACb,MAAI,SAAS;AACb,MAAI,SAAS;AACb,MAAI,SAAS;AACb,MAAI,SAAS;AACb,MAAI,SAAS;AACb,MAAI,SAAS;AACb,MAAI,SAAS;AACb,MAAI,SAAS;AACb,MAAI,SAAS;AAEb,MAAI,SAAS,qBAAqB,UAAU;AAC5C,MAAI,SAAS,uBAAuB,KAAK,KAAK;AAC9C,MAAI,SAAS,uBAAuB,KAAM,KAAK;AAC/C,MAAI,SAAS,uBAAuB,KAAK,KAAK;AAC9C,MAAI,SAAS,qBAAqB,UAAU;AAC5C,MAAI,SAAS,qBAAqB,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,GAAG,CAAC,GAAG,OAAO,KAAK;AACxE,MAAI,SAAS,qBAAqB,WAAW;AAC7C,MAAI,SAAS,qBAAqB,CAAC,GAAI,GAAG,MAAM,KAAK;AACrD,MAAI,SAAS,qBAAqB,aAAa;AAC/C,MAAI,SAAS,qBAAqB,CAAC,CAAC,KAAK,GAAG,CAAC,GAAG,OAAO,KAAK;AAC5D,MAAI,UAAU,uBAAuB,KAAK,KAAK;AAC/C,MAAI,UAAU,qBAAqB,CAAC,GAAG,GAAG,OAAO,KAAK;AACtD,MAAI,UAAU,qBAAqB,6BAA6B;AAChE,MAAI,UAAU,uBAAuB,SAAS,KAAK;AACnD,MAAI,UAAU,uBAAuB,OAAO,KAAK;AACjD,MAAI,UAAU,uBAAuB,SAAS,KAAK;AACnD,MAAI,UAAU,uBAAuB,OAAO,KAAK;AACjD,MAAI,UAAU,qBAAqB,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,GAAG,GAAG,KAAK,GAAG,GAAG,OAAO,KAAK;AAC/F,MAAI,UAAU,qBAAqB,CAAC,KAAK,GAAG,GAAG,OAAO,KAAK;AAC3D,MAAI,UAAU,qBAAqB,mBAAmB;AACtD,MAAI,UAAU,qBAAqB,CAAC,KAAK,GAAG,GAAG,OAAO,KAAK;AAC3D,MAAI,UAAU,qBAAqB,KAAK;AACxC,MAAI,UAAU,uBAAuB,KAAK,KAAK;AAC/C,MAAI,UAAU,qBAAqB,eAAe;AAClD,MAAI,UAAU,uBAAuB,KAAK,KAAK;AAC/C,MAAI,UAAU,qBAAqB,CAAC,GAAG,GAAG,MAAM,KAAK;AACrD,MAAI,UAAU,uBAAuB,KAAK,KAAK;AAC/C,MAAI,UAAU,qBAAqB,sBAAsB;AACzD,MAAI,UAAU,uBAAuB,KAAK,KAAK;AAC/C,MAAI,UAAU,qBAAqB,CAAC,MAAM,IAAI,GAAG,MAAM,KAAK;AAC5D,MAAI,UAAU,qBAAqB,WAAW;AAC9C,MAAI,UAAU,uBAAuB,KAAK,KAAK;AAC/C,MAAI,UAAU,uBAAuB,KAAK,KAAK;AAC/C,MAAI,UAAU,qBAAqB,yBAAyB;AAC5D,MAAI,UAAU,uBAAuB,OAAO,KAAK;AACjD,MAAI,UAAU,uBAAuB,OAAO,KAAK;AACjD,MAAI,UAAU,uBAAuB,WAAW,KAAK;AACrD,MAAI,UAAU,uBAAuB,KAAK,KAAK;AAC/C,MAAI,UAAU,qBAAqB,YAAY;AAC/C,MAAI,UAAU,qBAAqB,CAAC,KAAK,KAAM,MAAM,IAAI,GAAG,OAAO,KAAK;AAExE,MAAI,SAAS,SAAS,SAAS,MAAM;AAAE,WAAO,IAAI,SAAS,IAAI;EAAC;AAChE,MAAI,SAAS,SAAS,UAAU;AAAE,WAAO,OAAO,YAAY,QAAQ;EAAC;AACrE,MAAI,SAAS,SAAS,SAAS,UAAU;AAAE,WAAO,CAAC,SAAS,QAAQ;EAAC;AACrE,MAAI,SAAS,SAAS,MAAM,QAAQ;AAAE,WAAO,EAAE,MAAM,OAAM;EAAC;AAC5D,MAAI,SAAS,SAAS,SAAS,OAAO;AAAE,WAAO,WAAW,SAAS,OAAO,GAAG,GAAG,MAAM,KAAI,CAAE;EAAC;AAC7F,MAAI,SAAS,SAAS,KAAK,QAAQ,KAAK,SAAS,YAAY;AAAE,WAAO,KAAK,KAAK,QAAQ,KAAK,SAAS,UAAU;EAAC;AACjH,MAAI,SAAS,SAAS,KAAK;AAAE,WAAO;EAAG;AACvC,MAAI,SAAS,SAAS,SAAS;AAAE,WAAO,QAAQ,QAAQ,YAAY,GAAG;EAAC;AACxE,MAAI,SAAS,SAAS,SAAS;AAAE,WAAO,QAAQ,KAAI;EAAE;AACtD,MAAI,SAAS,SAAS,MAAM;AAAE,WAAO;EAAI;AACzC,MAAI,UAAU,SAAS,QAAQ,SAAS;AAAE,WAAO,EAAE,QAAQ,QAAO;EAAE;AACpE,MAAI,cAAc,QAAQ,cAAc;AAExC,MAAI,sBAAsB,CAAC,EAAE,MAAM,GAAG,QAAQ,EAAC,CAAE;AACjD,MAAI,iBAAiB;AACrB,MAAI,sBAAsB,QAAQ,uBAAuB,CAAA;AACzD,MAAI,kBAAkB,QAAQ,kBAAkB;AAEhD,MAAI;AAEJ,MAAI,QAAQ,WAAW;AACrB,QAAI,EAAE,QAAQ,aAAa,yBAAyB;AAClD,YAAM,IAAI,MAAM,oCAAqC,QAAQ,YAAY,IAAK;IACpF;AAEI,4BAAwB,uBAAuB,QAAQ,SAAS;EACpE;AA0CE,WAAS,uBAAuB,MAAM,YAAY;AAChD,WAAO,EAAE,MAAM,WAAW,MAAY,WAAsB;EAChE;AAEE,WAAS,qBAAqB,OAAO,UAAU,YAAY;AACzD,WAAO,EAAE,MAAM,SAAS,OAAc,UAAoB,WAAsB;EACpF;AAME,WAAS,qBAAqB;AAC5B,WAAO,EAAE,MAAM,MAAK;EACxB;AAEE,WAAS,qBAAqB,aAAa;AACzC,WAAO,EAAE,MAAM,SAAS,YAAwB;EACpD;AAEE,WAAS,sBAAsB,KAAK;AAClC,QAAI,UAAU,oBAAoB,GAAG;AACrC,QAAI;AAEJ,QAAI,SAAS;AACX,aAAO;IACb,OAAW;AACL,UAAI,OAAO,oBAAoB,QAAQ;AACrC,YAAI,oBAAoB,SAAS;MACzC,OAAa;AACL,YAAI;AACJ,eAAO,CAAC,oBAAoB,EAAE,CAAC,GAAG;QAAA;MAC1C;AAEM,gBAAU,oBAAoB,CAAC;AAC/B,gBAAU;QACR,MAAM,QAAQ;QACd,QAAQ,QAAQ;MACxB;AAEM,aAAO,IAAI,KAAK;AACd,YAAI,MAAM,WAAW,CAAC,MAAM,IAAI;AAC9B,kBAAQ;AACR,kBAAQ,SAAS;QAC3B,OAAe;AACL,kBAAQ;QAClB;AAEQ;MACR;AAEM,0BAAoB,GAAG,IAAI;AAE3B,aAAO;IACb;EACA;AAEE,WAAS,oBAAoB,UAAU,QAAQ,QAAQ;AACrD,QAAI,kBAAkB,sBAAsB,QAAQ;AACpD,QAAI,gBAAgB,sBAAsB,MAAM;AAEhD,QAAI,MAAM;MACR,QAAQ;MACR,OAAO;QACL,QAAQ;QACR,MAAM,gBAAgB;QACtB,QAAQ,gBAAgB;MAChC;MACM,KAAK;QACH,QAAQ;QACR,MAAM,cAAc;QACpB,QAAQ,cAAc;MAC9B;IACA;AAKI,WAAO;EACX;AAEE,WAAS,SAAS,UAAU;AAC1B,QAAI,cAAc,gBAAgB;AAAE;IAAO;AAE3C,QAAI,cAAc,gBAAgB;AAChC,uBAAiB;AACjB,4BAAsB,CAAA;IAC5B;AAEI,wBAAoB,KAAK,QAAQ;EACrC;AAME,WAAS,yBAAyB,UAAU,OAAO,UAAU;AAC3D,WAAO,IAAI;MACT,gBAAgB,aAAa,UAAU,KAAK;MAC5C;MACA;MACA;IACN;EACA;AAEE,WAAS,eAAe;AACtB,QAAI,IAAI,IAAI;AAEZ,SAAK;AACL,SAAK,wBAAuB;AAC5B,SAAK,yBAAwB;AAE7B,SAAK,OAAO,IAAI,EAAE;AAElB,WAAO;EACX;AAEE,WAAS,0BAA0B;AACjC,QAAI,IAAI,IAAI;AAEZ,SAAK;AACL,SAAK,CAAA;AACL,SAAK,iBAAgB;AACrB,WAAO,OAAO,YAAY;AACxB,SAAG,KAAK,EAAE;AACV,WAAK,iBAAgB;IAC3B;AACI,SAAK,WAAU;AAEf,SAAK,OAAO,EAAE;AAEd,WAAO;EACX;AAEE,WAAS,mBAAmB;AACvB,QAAC,IAAQ,IAAQ,IAAQ,IAAI,IAAI,IAAQ;AAE5C;AACA,SAAK;AACA,eAAU;AACf,QAAI,MAAM,WAAW,WAAW,MAAM,IAAI;AACxC,WAAK;AACL;IACN,OAAW;AACL,WAAK;AACL,UAAI,oBAAoB,GAAG;AAAE,iBAAS,MAAM;MAAE;IACpD;AACI,QAAI,OAAO,YAAY;AAChB,iBAAU;AACf,WAAK,iBAAgB;AACrB,UAAI,OAAO,YAAY;AAChB,mBAAU;AACf,YAAI,MAAM,WAAW,WAAW,MAAM,IAAI;AACxC,eAAK;AACL;QACV,OAAe;AACL,eAAK;AACL,cAAI,oBAAoB,GAAG;AAAE,qBAAS,MAAM;UAAE;QACxD;AACQ,YAAI,OAAO,YAAY;AACrB,eAAK,kBAAiB;AACtB,cAAI,MAAM,WAAW,WAAW,MAAM,IAAI;AACxC,iBAAK;AACL;UACZ,OAAiB;AACL,iBAAK;AACL,gBAAI,oBAAoB,GAAG;AAAE,uBAAS,MAAM;YAAE;UAC1D;AACU,cAAI,OAAO,YAAY;AAChB,uBAAU;AACf,gBAAI,MAAM,WAAW,WAAW,MAAM,IAAI;AACxC,oBAAM;AACN;YACd,OAAmB;AACL,oBAAM;AACN,kBAAI,oBAAoB,GAAG;AAAE,yBAAS,MAAM;cAAE;YAC5D;AACY,gBAAI,QAAQ,YAAY;AAEtB,mBAAK,OAAO,IAAI,EAAE;YAChC,OAAmB;AACL,4BAAc;AACd,mBAAK;YACnB;UACA,OAAiB;AACL,0BAAc;AACd,iBAAK;UACjB;QACA,OAAe;AACL,wBAAc;AACd,eAAK;QACf;MACA,OAAa;AACL,sBAAc;AACd,aAAK;MACb;IACA,OAAW;AACL,oBAAc;AACd,WAAK;IACX;AACI;AACA,QAAI,OAAO,YAAY;AAErB,UAAI,oBAAoB,GAAG;AAAE,iBAAS,MAAM;MAAE;IACpD;AAEI,WAAO;EACX;AAEE,WAAS,mBAAmB;AAC1B,QAAI,IAAI,IAAI;AAEZ;AACA,SAAK;AACL,SAAK,CAAA;AACL,SAAK,MAAM,OAAO,WAAW;AAC7B,QAAI,OAAO,KAAK,EAAE,GAAG;AACnB;IACN,OAAW;AACL,WAAK;AACL,UAAI,oBAAoB,GAAG;AAAE,iBAAS,MAAM;MAAE;IACpD;AACI,QAAI,OAAO,YAAY;AACrB,aAAO,OAAO,YAAY;AACxB,WAAG,KAAK,EAAE;AACV,aAAK,MAAM,OAAO,WAAW;AAC7B,YAAI,OAAO,KAAK,EAAE,GAAG;AACnB;QACV,OAAe;AACL,eAAK;AACL,cAAI,oBAAoB,GAAG;AAAE,qBAAS,MAAM;UAAE;QACxD;MACA;IACA,OAAW;AACL,WAAK;IACX;AACI,QAAI,OAAO,YAAY;AACrB,WAAK,MAAM,UAAU,IAAI,WAAW;IAC1C,OAAW;AACL,WAAK;IACX;AACI;AACA,QAAI,OAAO,YAAY;AACrB,WAAK;AACL,UAAI,oBAAoB,GAAG;AAAE,iBAAS,MAAM;MAAE;IACpD;AAEI,WAAO;EACX;AAEE,WAAS,oBAAoB;AAC3B,QAAI,IAAI,IAAI;AAEZ;AACA,SAAK;AACL,SAAK,CAAA;AACL,SAAK,MAAM,OAAO,WAAW;AAC7B,QAAI,OAAO,KAAK,EAAE,GAAG;AACnB;IACN,OAAW;AACL,WAAK;AACL,UAAI,oBAAoB,GAAG;AAAE,iBAAS,MAAM;MAAE;IACpD;AACI,WAAO,OAAO,YAAY;AACxB,SAAG,KAAK,EAAE;AACV,WAAK,MAAM,OAAO,WAAW;AAC7B,UAAI,OAAO,KAAK,EAAE,GAAG;AACnB;MACR,OAAa;AACL,aAAK;AACL,YAAI,oBAAoB,GAAG;AAAE,mBAAS,MAAM;QAAE;MACtD;IACA;AACI,SAAK,MAAM,UAAU,IAAI,WAAW;AACpC;AACA,SAAK;AACL,QAAI,oBAAoB,GAAG;AAAE,eAAS,MAAM;IAAE;AAE9C,WAAO;EACX;AAEE,WAAS,2BAA2B;AAC/B,QAAC,IAAI,IAAQ;AAEhB,SAAK;AACL,SAAK,cAAa;AACb,eAAU;AACf,SAAK,+BAA8B;AACnC,QAAI,OAAO,YAAY;AACrB,WAAK;IACX;AACS,eAAU;AAEf,SAAK,OAAO,IAAI,EAAE;AAElB,WAAO;EACX;AAEE,WAAS,gBAAgB;AACvB,QAAI,IAAI,IAAI,IAAI;AAEhB,SAAK;AACL,SAAK,iBAAgB;AACrB,QAAI,OAAO,YAAY;AACrB,WAAK;IACX;AACI,SAAK,CAAA;AACL,SAAK,cAAa;AAClB,WAAO,OAAO,YAAY;AACxB,SAAG,KAAK,EAAE;AACV,WAAK,cAAa;IACxB;AAEI,SAAK,OAAO,IAAI,EAAE;AAElB,WAAO;EACX;AAEE,WAAS,gBAAgB;AACpB,QAAC,IAAgB,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI;AAE5C,SAAK;AACA,eAAU;AACV,wBAAmB;AAInB,eAAU;AACf,SAAK,aAAY;AACjB,QAAI,OAAO,YAAY;AACrB,WAAK,0BAAyB;AAC9B,UAAI,OAAO,YAAY;AACrB,aAAK;MACb;AACM,WAAK,CAAA;AACL,WAAK,aAAY;AACjB,aAAO,OAAO,YAAY;AACxB,WAAG,KAAK,EAAE;AACV,aAAK,aAAY;MACzB;AACM,WAAK,WAAU;AACf,WAAK,iBAAgB;AACrB,UAAI,OAAO,YAAY;AACrB,aAAK;MACb;AACM,WAAK,CAAA;AACL,YAAM,mBAAkB;AACxB,aAAO,QAAQ,YAAY;AACzB,WAAG,KAAK,GAAG;AACX,cAAM,mBAAkB;MAChC;AAEM,WAAK,OAAO,IAAI,IAAI,IAAI,IAAI,EAAE;IACpC,OAAW;AACL,oBAAc;AACd,WAAK;IACX;AAEI,WAAO;EACX;AAEE,WAAS,sBAAsB;AAC7B,QAAI,IAAI,IAAI,IAAI,IAAI,IAAI;AAExB;AACA,SAAK;AACL,SAAK,CAAA;AACL,SAAK,MAAM,OAAO,WAAW;AAC7B,QAAI,OAAO,KAAK,EAAE,GAAG;AACnB;IACN,OAAW;AACL,WAAK;AACL,UAAI,oBAAoB,GAAG;AAAE,iBAAS,MAAM;MAAE;IACpD;AACI,WAAO,OAAO,YAAY;AACxB,SAAG,KAAK,EAAE;AACV,WAAK,MAAM,OAAO,WAAW;AAC7B,UAAI,OAAO,KAAK,EAAE,GAAG;AACnB;MACR,OAAa;AACL,aAAK;AACL,YAAI,oBAAoB,GAAG;AAAE,mBAAS,MAAM;QAAE;MACtD;IACA;AACI,QAAI,MAAM,WAAW,WAAW,MAAM,IAAI;AACxC,WAAK;AACL;IACN,OAAW;AACL,WAAK;AACL,UAAI,oBAAoB,GAAG;AAAE,iBAAS,OAAO;MAAE;IACrD;AACI,QAAI,OAAO,YAAY;AACrB,WAAK,WAAU;AACf,WAAK,CAAA;AACL,WAAK,MAAM,OAAO,WAAW;AAC7B,UAAI,OAAO,KAAK,EAAE,GAAG;AACnB;MACR,OAAa;AACL,aAAK;AACL,YAAI,oBAAoB,GAAG;AAAE,mBAAS,OAAO;QAAE;MACvD;AACM,aAAO,OAAO,YAAY;AACxB,WAAG,KAAK,EAAE;AACV,aAAK,MAAM,OAAO,WAAW;AAC7B,YAAI,OAAO,KAAK,EAAE,GAAG;AACnB;QACV,OAAe;AACL,eAAK;AACL,cAAI,oBAAoB,GAAG;AAAE,qBAAS,OAAO;UAAE;QACzD;MACA;AACM,WAAK,CAAC,IAAI,IAAI,IAAI,EAAE;AACpB,WAAK;IACX,OAAW;AACL,oBAAc;AACd,WAAK;IACX;AACI;AACA,QAAI,OAAO,YAAY;AACrB,WAAK;AACL,UAAI,oBAAoB,GAAG;AAAE,iBAAS,MAAM;MAAE;IACpD;AAEI,WAAO;EACX;AAEE,WAAS,eAAe;AACtB,QAAI,IAAI,IAAI,IAAI,IAAI,IAAI;AAExB;AACA,SAAK;AACL,SAAK;AACL,QAAI,MAAM,OAAO,aAAa,CAAC,MAAM,QAAQ;AAC3C,WAAK;AACL,qBAAe;IACrB,OAAW;AACL,WAAK;AACL,UAAI,oBAAoB,GAAG;AAAE,iBAAS,OAAO;MAAE;IACrD;AACI,QAAI,OAAO,YAAY;AACrB,UAAI,MAAM,OAAO,aAAa,CAAC,MAAM,QAAQ;AAC3C,aAAK;AACL,uBAAe;MACvB,OAAa;AACL,aAAK;AACL,YAAI,oBAAoB,GAAG;AAAE,mBAAS,OAAO;QAAE;MACvD;AACM,UAAI,OAAO,YAAY;AACrB,YAAI,MAAM,OAAO,aAAa,CAAC,MAAM,QAAQ;AAC3C,eAAK;AACL,yBAAe;QACzB,OAAe;AACL,eAAK;AACL,cAAI,oBAAoB,GAAG;AAAE,qBAAS,OAAO;UAAE;QACzD;AACQ,YAAI,OAAO,YAAY;AACrB,cAAI,MAAM,OAAO,aAAa,CAAC,MAAM,QAAQ;AAC3C,iBAAK;AACL,2BAAe;UAC3B,OAAiB;AACL,iBAAK;AACL,gBAAI,oBAAoB,GAAG;AAAE,uBAAS,OAAO;YAAE;UAC3D;AACU,cAAI,OAAO,YAAY;AACrB,iBAAK;AACL,iBAAK,MAAM,OAAO,WAAW;AAC7B,gBAAI,OAAO,KAAK,EAAE,GAAG;AACnB;YACd,OAAmB;AACL,mBAAK;AACL,kBAAI,oBAAoB,GAAG;AAAE,yBAAS,MAAM;cAAE;YAC5D;AACY,gBAAI,OAAO,YAAY;AACrB,mBAAK,CAAA;AACL,mBAAK,MAAM,OAAO,WAAW;AAC7B,kBAAI,OAAO,KAAK,EAAE,GAAG;AACnB;cAChB,OAAqB;AACL,qBAAK;AACL,oBAAI,oBAAoB,GAAG;AAAE,2BAAS,OAAO;gBAAE;cAC/D;AACc,kBAAI,OAAO,YAAY;AACrB,uBAAO,OAAO,YAAY;AACxB,qBAAG,KAAK,EAAE;AACV,uBAAK,MAAM,OAAO,WAAW;AAC7B,sBAAI,OAAO,KAAK,EAAE,GAAG;AACnB;kBACpB,OAAyB;AACL,yBAAK;AACL,wBAAI,oBAAoB,GAAG;AAAE,+BAAS,OAAO;oBAAE;kBACnE;gBACA;cACA,OAAqB;AACL,qBAAK;cACrB;AACc,kBAAI,OAAO,YAAY;AACrB,qBAAK,CAAC,IAAI,EAAE;AACZ,qBAAK;cACrB,OAAqB;AACL,8BAAc;AACd,qBAAK;cACrB;YACA,OAAmB;AACL,4BAAc;AACd,mBAAK;YACnB;UACA;QACA;MACA;IACA;AACI,QAAI,OAAO,YAAY;AACrB,WAAK,MAAM,OAAO,WAAW;AAC7B,UAAI,OAAO,KAAK,EAAE,GAAG;AACnB;MACR,OAAa;AACL,aAAK;AACL,YAAI,oBAAoB,GAAG;AAAE,mBAAS,OAAO;QAAE;MACvD;AACM,UAAI,OAAO,YAAY;AACrB,aAAK;MACb;AACM,WAAK,CAAC,IAAI,EAAE;AACZ,WAAK;IACX,OAAW;AACL,oBAAc;AACd,WAAK;IACX;AACI,QAAI,OAAO,YAAY;AACrB,WAAK,MAAM,UAAU,IAAI,WAAW;IAC1C,OAAW;AACL,WAAK;IACX;AACI;AACA,QAAI,OAAO,YAAY;AACrB,WAAK;AACL,UAAI,oBAAoB,GAAG;AAAE,iBAAS,OAAO;MAAE;IACrD;AAEI,WAAO;EACX;AAEE,WAAS,4BAA4B;AACnC,QAAI,IAAI,IAAI;AAEZ;AACA,SAAK;AACL,SAAK,CAAA;AACL,SAAK,MAAM,OAAO,WAAW;AAC7B,QAAI,OAAO,KAAK,EAAE,GAAG;AACnB;IACN,OAAW;AACL,WAAK;AACL,UAAI,oBAAoB,GAAG;AAAE,iBAAS,OAAO;MAAE;IACrD;AACI,WAAO,OAAO,YAAY;AACxB,SAAG,KAAK,EAAE;AACV,UAAI,GAAG,UAAU,GAAG;AAClB,aAAK;MACb,OAAa;AACL,aAAK,MAAM,OAAO,WAAW;AAC7B,YAAI,OAAO,KAAK,EAAE,GAAG;AACnB;QACV,OAAe;AACL,eAAK;AACL,cAAI,oBAAoB,GAAG;AAAE,qBAAS,OAAO;UAAE;QACzD;MACA;IACA;AACI,QAAI,GAAG,SAAS,GAAG;AACjB,oBAAc;AACd,WAAK;IACX,OAAW;AACL,WAAK;IACX;AACI;AACA,QAAI,OAAO,YAAY;AACrB,WAAK;AACL,UAAI,oBAAoB,GAAG;AAAE,iBAAS,OAAO;MAAE;IACrD;AAEI,WAAO;EACX;AAEE,WAAS,eAAe;AACnB,QAAC,IAAQ,IAAI,IAAI,IAAI;AAExB;AACA,SAAK;AACA,eAAU;AACf,QAAI,MAAM,WAAW,WAAW,MAAM,IAAI;AACxC,WAAK;AACL;IACN,OAAW;AACL,WAAK;AACL,UAAI,oBAAoB,GAAG;AAAE,iBAAS,OAAO;MAAE;IACrD;AACI,QAAI,OAAO,YAAY;AACrB,WAAK;AACL,WAAK,CAAA;AACL,WAAK,MAAM,OAAO,WAAW;AAC7B,UAAI,OAAO,KAAK,EAAE,GAAG;AACnB;MACR,OAAa;AACL,aAAK;AACL,YAAI,oBAAoB,GAAG;AAAE,mBAAS,MAAM;QAAE;MACtD;AACM,UAAI,OAAO,YAAY;AACrB,eAAO,OAAO,YAAY;AACxB,aAAG,KAAK,EAAE;AACV,eAAK,MAAM,OAAO,WAAW;AAC7B,cAAI,OAAO,KAAK,EAAE,GAAG;AACnB;UACZ,OAAiB;AACL,iBAAK;AACL,gBAAI,oBAAoB,GAAG;AAAE,uBAAS,MAAM;YAAE;UAC1D;QACA;MACA,OAAa;AACL,aAAK;MACb;AACM,UAAI,OAAO,YAAY;AACrB,aAAK,MAAM,UAAU,IAAI,WAAW;MAC5C,OAAa;AACL,aAAK;MACb;AACM,UAAI,OAAO,YAAY;AAErB,aAAK,OAAO,EAAE;MACtB,OAAa;AACL,sBAAc;AACd,aAAK;MACb;IACA,OAAW;AACL,oBAAc;AACd,WAAK;IACX;AACI;AACA,QAAI,OAAO,YAAY;AAErB,UAAI,oBAAoB,GAAG;AAAE,iBAAS,OAAO;MAAE;IACrD;AAEI,WAAO;EACX;AAEE,WAAS,mBAAmB;AAC1B,QAAI;AAEJ,SAAK,sBAAqB;AAC1B,QAAI,OAAO,YAAY;AACrB,WAAK,2BAA0B;IACrC;AAEI,WAAO;EACX;AAEE,WAAS,wBAAwB;AAC/B,QAAI,IAAI,IAAI,IAAI,IAAI;AAEpB;AACA,SAAK;AACL,QAAI,MAAM,WAAW,WAAW,MAAM,KAAK;AACzC,WAAK;AACL;IACN,OAAW;AACL,WAAK;AACL,UAAI,oBAAoB,GAAG;AAAE,iBAAS,OAAO;MAAE;IACrD;AACI,QAAI,OAAO,YAAY;AACrB,WAAK;AACL,WAAK,CAAA;AACL,WAAK,MAAM,OAAO,WAAW;AAC7B,UAAI,OAAO,KAAK,EAAE,GAAG;AACnB;MACR,OAAa;AACL,aAAK;AACL,YAAI,oBAAoB,GAAG;AAAE,mBAAS,OAAO;QAAE;MACvD;AACM,aAAO,OAAO,YAAY;AACxB,WAAG,KAAK,EAAE;AACV,aAAK,MAAM,OAAO,WAAW;AAC7B,YAAI,OAAO,KAAK,EAAE,GAAG;AACnB;QACV,OAAe;AACL,eAAK;AACL,cAAI,oBAAoB,GAAG;AAAE,qBAAS,OAAO;UAAE;QACzD;MACA;AACM,WAAK,MAAM,UAAU,IAAI,WAAW;AACpC,UAAI,MAAM,WAAW,WAAW,MAAM,KAAK;AACzC,aAAK;AACL;MACR,OAAa;AACL,aAAK;AACL,YAAI,oBAAoB,GAAG;AAAE,mBAAS,OAAO;QAAE;MACvD;AACM,UAAI,OAAO,YAAY;AAErB,aAAK,OAAO,EAAE;MACtB,OAAa;AACL,sBAAc;AACd,aAAK;MACb;IACA,OAAW;AACL,oBAAc;AACd,WAAK;IACX;AACI;AACA,QAAI,OAAO,YAAY;AACrB,WAAK;AACL,UAAI,oBAAoB,GAAG;AAAE,iBAAS,OAAO;MAAE;IACrD;AAEI,WAAO;EACX;AAEE,WAAS,6BAA6B;AACpC,QAAI,IAAI,IAAI,IAAI,IAAI;AAEpB;AACA,SAAK;AACL,QAAI,MAAM,WAAW,WAAW,MAAM,IAAI;AACxC,WAAK;AACL;IACN,OAAW;AACL,WAAK;AACL,UAAI,oBAAoB,GAAG;AAAE,iBAAS,OAAO;MAAE;IACrD;AACI,QAAI,OAAO,YAAY;AACrB,WAAK;AACL,WAAK,CAAA;AACL,WAAK,MAAM,OAAO,WAAW;AAC7B,UAAI,OAAO,KAAK,EAAE,GAAG;AACnB;MACR,OAAa;AACL,aAAK;AACL,YAAI,oBAAoB,GAAG;AAAE,mBAAS,OAAO;QAAE;MACvD;AACM,aAAO,OAAO,YAAY;AACxB,WAAG,KAAK,EAAE;AACV,aAAK,MAAM,OAAO,WAAW;AAC7B,YAAI,OAAO,KAAK,EAAE,GAAG;AACnB;QACV,OAAe;AACL,eAAK;AACL,cAAI,oBAAoB,GAAG;AAAE,qBAAS,OAAO;UAAE;QACzD;MACA;AACM,WAAK,MAAM,UAAU,IAAI,WAAW;AAEpC,WAAK,OAAO,EAAE;IACpB,OAAW;AACL,oBAAc;AACd,WAAK;IACX;AACI;AACA,QAAI,OAAO,YAAY;AACrB,WAAK;AACL,UAAI,oBAAoB,GAAG;AAAE,iBAAS,OAAO;MAAE;IACrD;AAEI,WAAO;EACX;AAEE,WAAS,qBAAqB;AACzB,QAAC,IAAQ,IAAI,IAAQ;AAExB;AACA,SAAK;AACA,eAAU;AACf,QAAI,MAAM,WAAW,WAAW,MAAM,IAAI;AACxC,WAAK;AACL;IACN,OAAW;AACL,WAAK;AACL,UAAI,oBAAoB,GAAG;AAAE,iBAAS,OAAO;MAAE;IACrD;AACI,QAAI,OAAO,YAAY;AACrB,WAAK,cAAa;AAClB,UAAI,OAAO,YAAY;AAChB,mBAAU;AACf,YAAI,MAAM,WAAW,WAAW,MAAM,IAAI;AACxC,eAAK;AACL;QACV,OAAe;AACL,eAAK;AACL,cAAI,oBAAoB,GAAG;AAAE,qBAAS,OAAO;UAAE;QACzD;AACQ,YAAI,OAAO,YAAY;AAErB,eAAK,OAAO,EAAE;QACxB,OAAe;AACL,wBAAc;AACd,eAAK;QACf;MACA,OAAa;AACL,sBAAc;AACd,aAAK;MACb;IACA,OAAW;AACL,oBAAc;AACd,WAAK;IACX;AACI;AACA,QAAI,OAAO,YAAY;AAErB,UAAI,oBAAoB,GAAG;AAAE,iBAAS,OAAO;MAAE;IACrD;AAEI,WAAO;EACX;AAEE,WAAS,iCAAiC;AACrC,QAAC,IAAI,IAAQ;AAEhB;AACA,SAAK;AACL,QAAI,MAAM,OAAO,aAAa,CAAC,MAAM,SAAS;AAC5C,WAAK;AACL,qBAAe;IACrB,OAAW;AACL,WAAK;AACL,UAAI,oBAAoB,GAAG;AAAE,iBAAS,OAAO;MAAE;IACrD;AACI,QAAI,OAAO,YAAY;AACrB,UAAI,MAAM,OAAO,aAAa,CAAC,MAAM,SAAS;AAC5C,aAAK;AACL,uBAAe;MACvB,OAAa;AACL,aAAK;AACL,YAAI,oBAAoB,GAAG;AAAE,mBAAS,OAAO;QAAE;MACvD;AACM,UAAI,OAAO,YAAY;AACrB,YAAI,MAAM,OAAO,aAAa,CAAC,MAAM,SAAS;AAC5C,eAAK;AACL,yBAAe;QACzB,OAAe;AACL,eAAK;AACL,cAAI,oBAAoB,GAAG;AAAE,qBAAS,OAAO;UAAE;QACzD;AACQ,YAAI,OAAO,YAAY;AACrB,cAAI,MAAM,WAAW,WAAW,MAAM,IAAI;AACxC,iBAAK;AACL;UACZ,OAAiB;AACL,iBAAK;AACL,gBAAI,oBAAoB,GAAG;AAAE,uBAAS,OAAO;YAAE;UAC3D;QACA;MACA;IACA;AACI,QAAI,OAAO,YAAY;AAChB,iBAAU;AACf,WAAK,iBAAgB;AACrB,UAAI,OAAO,YAAY;AACrB,aAAK;MACb;AAEM,WAAK,QAAQ,IAAI,EAAE;IACzB,OAAW;AACL,oBAAc;AACd,WAAK;IACX;AACI;AACA,QAAI,OAAO,YAAY;AACrB,WAAK;AACL,UAAI,oBAAoB,GAAG;AAAE,iBAAS,OAAO;MAAE;IACrD;AAEI,WAAO;EACX;AAEE,WAAS,aAAa;AACpB,QAAI,IAAI;AAER;AACA,SAAK,CAAA;AACL,SAAK,MAAM,OAAO,WAAW;AAC7B,QAAI,OAAO,KAAK,EAAE,GAAG;AACnB;IACN,OAAW;AACL,WAAK;AACL,UAAI,oBAAoB,GAAG;AAAE,iBAAS,OAAO;MAAE;IACrD;AACI,WAAO,OAAO,YAAY;AACxB,SAAG,KAAK,EAAE;AACV,WAAK,MAAM,OAAO,WAAW;AAC7B,UAAI,OAAO,KAAK,EAAE,GAAG;AACnB;MACR,OAAa;AACL,aAAK;AACL,YAAI,oBAAoB,GAAG;AAAE,mBAAS,OAAO;QAAE;MACvD;IACA;AACI;AACA,SAAK;AACL,QAAI,oBAAoB,GAAG;AAAE,eAAS,OAAO;IAAE;AAE/C,WAAO;EACX;AAEE,eAAa,sBAAqB;AAElC,MAAI,QAAQ,aAAa;AACvB;;MAA2B;QACzB;QACA;QACA;QACA;QACA;MACN;;EACA;AACE,MAAI,eAAe,cAAc,gBAAgB,MAAM,QAAQ;AAC7D,WAAO;EACX,OAAS;AACL,QAAI,eAAe,cAAc,cAAc,MAAM,QAAQ;AAC3D,eAAS,mBAAkB,CAAE;IACnC;AAEI,UAAM;MACJ;MACA,iBAAiB,MAAM,SAAS,MAAM,OAAO,cAAc,IAAI;MAC/D,iBAAiB,MAAM,SACnB,oBAAoB,gBAAgB,iBAAiB,CAAC,IACtD,oBAAoB,gBAAgB,cAAc;IAC5D;EACA;AACA;ACzvCA,IAAM,SAAS;AAEf,SAAS,KAAK,GAAW,GAAS;AAChC,UAAS,KAAK,IAAM,KAAM,MAAM,KAAO;AACzC;AAEA,SAAS,YAAY,GAAW,GAAS;AACvC,SAAQ,IAAI,IAAK;AACnB;AAGM,SAAU,aAAa,OAAa;AACxC,SAAO,WAAA;AACL,QAAI,KAAK,OAAO,QAAQ,MAAM;AAC9B,QAAI,KAAK,OAAQ,SAAS,MAAO,MAAM;AAEvC,UAAM,SAAS,YAAY,KAAK,YAAY,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE;AAE5D,UAAM;AACN,UAAM,KAAK,IAAI,GAAG,IAAI,KAAM,MAAM,OAAQ;AAC1C,SAAK,KAAK,IAAI,GAAG;AAEjB,YAAS,MAAM,MAAO;AAEtB,WAAO;EACT;AACF;AAEA,IAAM,OAAO,aAAa,mCAAmC;AAE7D,IAAM,aAAa,MAAM,KAAK,EAAE,QAAQ,EAAC,GAAI,MAC3C,MAAM,KAAK,EAAE,QAAQ,EAAC,GAAI,MAAM,MAAM,KAAK,EAAE,QAAQ,IAAG,GAAI,MAAM,KAAI,CAAE,CAAC,CAAC;AAG5E,IAAM,UAAU,MAAM,KAAK,EAAE,QAAQ,EAAC,GAAI,MAAM,KAAI,CAAE;AAEtD,IAAM,gBAAgB,MAAM,KAAK,EAAE,QAAQ,GAAE,GAAI,MAAM,KAAI,CAAE;AAE7D,IAAM,WAAW,KAAI;AAEd,IAAM,QAAQ;AACd,IAAM,QAAQ;AAEd,IAAM,OAAO;AACb,IAAM,SAAS;AACf,IAAM,SAAS;AACf,IAAM,OAAO;AACb,IAAM,QAAQ;AACd,IAAM,OAAO;AAgBb,IAAM,mBACX;IA2BW,aAAI;EAqBf,YAAYC,QAAc,UAAsB;AApBhD;AACA;AACA;AACA;AACA;AACA;AAQA;;;;;;;AAEA;AACA;AACA;AACA;AAGE,UAAM,EAAE,OAAO,OAAO,MAAM,IAAI,OAAO,UAAU,UAAS,IAAK;AAE/D,UAAM,gBAAgB,UAAU,IAAI;AACpC,UAAM,cAAc,UAAU,EAAE;AAEhC,SAAK,QAAQ;AACb,SAAK,QAAQ;AACb,SAAK,OAAO;AACZ,SAAK,KAAK;AAQV,SAAK,MAAMA,OAAM,YAAY,EAAE,UAAUA,OAAM,QAAQ,EAAE,EAAE,OAAO,KAAI,CAAE,CAAC;AACzE,SAAK,MAAM,gBAAgB;AAC3B,SAAK,SAASA,OAAM,IAAG;AAGvB,IAAAA,OAAM,WAAW,EAAE,QAAQ;AAC3B,SAAK,QAAQA,OAAM,IAAG;AACtB,IAAAA,OAAM,WAAW,EAAC;AAGlB,SAAK,QAAQ;AACb,eAAW,QAAQ,MAAM;AACvB,UAAI,KAAK,IAAI,IAAI,OAAO;AACtB,aAAK,SAAS,MAAM,IAAI;MACzB;IACF;AAED,QAAI,UAAU;AACZ,WAAK,WAAW;IACjB;AAED,QAAI,WAAW;AACb,WAAK,YAAY;AACjB,WAAK,OAAO;IACb;;EAGH,YAAS;AACP,WAAO,KAAK,MAAM,QAAQ,MAAM,SAAS,CAAC,IAAI;;EAGhD,cAAW;AACT,WAAO,KAAK,MAAM,QAAQ,MAAM,WAAW,CAAC,IAAI;;EAGlD,cAAW;AACT,WAAO,KAAK,MAAM,QAAQ,MAAM,YAAY,CAAC,IAAI;;EAGnD,mBAAgB;AACd,WAAO,KAAK,MAAM,QAAQ,MAAM,cAAc,CAAC,IAAI;;EAGrD,oBAAiB;AACf,WAAO,KAAK,MAAM,QAAQ,MAAM,cAAc,CAAC,IAAI;;EAGrD,YAAS;AACP,WAAO,KAAK,MAAM,QAAQ,MAAM,UAAU,CAAC,IAAI;;AAElD;AAED,IAAM,QAAQ;AAEd,IAAM,QAAgC;EACpC,QAAQ;EACR,SAAS;EACT,UAAU;EACV,YAAY;EACZ,WAAW;EACX,cAAc;EACd,cAAc;EACd,WAAW;;AAeb,IAAM,OAA+B;EACnC,QAAQ;EACR,SAAS;EACT,UAAU;EACV,YAAY;EACZ,WAAW;EACX,cAAc;EACd,cAAc;EACd,WAAW;;AAMA,IAAA,mBAA2C;EACtD,OAAO;EACP,MAAM;EACN,MAAM;EACN,OAAO;EACP,OAAO;EACP,OAAO;EACP,QAAQ;;AAOV,IAAM,mBAAkD;EACtD,YAAY;EACZ,YAAY;EACZ,UAAU;EACV,UAAU;EACV,WAAW;EACX,WAAW;EACX,SAAS;EACT,SAAS;EACT,WAAW;EACX,WAAW;EACX,WAAW;EACX,cAAc;EACd,SAAS;EACT,OAAO;EACP,OAAO;EACP,SAAS;EACT,WAAW;EACX,cAAc;EACd,KAAK;EACL,KAAK;EACL,MAAM;EACN,SAAS;EACT,SAAS;EACT,aAAa;EACb,OAAO;EACP,KAAK;EACL,aAAa;EACb,WAAW;EACX,MAAM;EACN,UAAU;;AAGZ,IAAM,kBAAkB;EACtB,GAAG;EACH,GAAG;;AA6CL,IAAM,OAA+B;EACnC,IAAM;EAAG,IAAM;EAAG,IAAM;EAAG,IAAM;EAAG,IAAM;EAAG,IAAM;EAAG,IAAM;EAAG,IAAM;EACrE,IAAK;EAAI,IAAK;EAAI,IAAK;EAAI,IAAK;EAAI,IAAK;EAAI,IAAK;EAAI,IAAK;EAAI,IAAK;EACpE,IAAK;EAAI,IAAK;EAAI,IAAK;EAAI,IAAK;EAAI,IAAK;EAAI,IAAK;EAAI,IAAK;EAAI,IAAK;EACpE,IAAK;EAAI,IAAK;EAAI,IAAK;EAAI,IAAK;EAAI,IAAK;EAAI,IAAK;EAAI,IAAK;EAAI,IAAK;EACpE,IAAK;EAAI,IAAK;EAAI,IAAK;EAAI,IAAK;EAAI,IAAK;EAAI,IAAK;EAAI,IAAK;EAAI,IAAK;EACpE,IAAK;EAAI,IAAK;EAAI,IAAK;EAAI,IAAK;EAAI,IAAK;EAAI,IAAK;EAAI,IAAK;EAAI,IAAK;EACpE,IAAK;EAAI,IAAK;EAAI,IAAK;EAAI,IAAK;EAAI,IAAI;EAAK,IAAI;EAAK,IAAI;EAAK,IAAI;EACnE,IAAI;EAAK,IAAI;EAAK,IAAI;EAAK,IAAI;EAAK,IAAI;EAAK,IAAI;EAAK,IAAI;EAAK,IAAI;;AAGrE,IAAM,eAAe;EACnB,GAAG,CAAC,IAAI,IAAI,IAAI,EAAE;EAClB,GAAG,CAAC,KAAK,KAAK,KAAK,GAAG;;AAGxB,IAAM,gBAAgB;EACpB,GAAG,CAAC,KAAK,KAAK,KAAK,KAAK,IAAI,IAAI,IAAI,EAAE;EACtC,GAAG,CAAC,KAAK,KAAK,IAAI,EAAE;EACpB,GAAG,CAAC,KAAK,GAAG,IAAI,EAAE;EAClB,GAAG,CAAC,KAAK,KAAK,KAAK,GAAG,IAAI,IAAI,IAAI,EAAE;EACpC,GAAG,CAAC,KAAK,KAAK,KAAK,GAAG,IAAI,IAAI,IAAI,EAAE;;AAItC,IAAM,UAAU;EACd;EAAI;EAAG;EAAG;EAAG;EAAG;EAAG;EAAG;EAAK;EAAG;EAAG;EAAG;EAAG;EAAG;EAAE;EAAI;EAC/C;EAAE;EAAI;EAAG;EAAG;EAAG;EAAG;EAAG;EAAK;EAAG;EAAG;EAAG;EAAG;EAAE;EAAI;EAAG;EAC/C;EAAG;EAAE;EAAI;EAAG;EAAG;EAAG;EAAG;EAAK;EAAG;EAAG;EAAG;EAAE;EAAI;EAAG;EAAG;EAC/C;EAAG;EAAG;EAAE;EAAI;EAAG;EAAG;EAAG;EAAK;EAAG;EAAG;EAAE;EAAI;EAAG;EAAG;EAAG;EAC/C;EAAG;EAAG;EAAG;EAAE;EAAI;EAAG;EAAG;EAAK;EAAG;EAAE;EAAI;EAAG;EAAG;EAAG;EAAG;EAC/C;EAAG;EAAG;EAAG;EAAG;EAAE;EAAI;EAAG;EAAK;EAAE;EAAI;EAAG;EAAG;EAAG;EAAG;EAAG;EAC/C;EAAG;EAAG;EAAG;EAAG;EAAG;EAAE;EAAI;EAAI;EAAI;EAAG;EAAG;EAAG;EAAG;EAAG;EAAG;EAChD;EAAG;EAAG;EAAG;EAAG;EAAG;EAAG;EAAK;EAAG;EAAG;EAAG;EAAG;EAAG;EAAG;EAAG;EAAI;EAC/C;EAAG;EAAG;EAAG;EAAG;EAAG;EAAE;EAAI;EAAI;EAAI;EAAG;EAAG;EAAG;EAAG;EAAG;EAAG;EAC/C;EAAG;EAAG;EAAG;EAAG;EAAE;EAAI;EAAG;EAAK;EAAE;EAAI;EAAG;EAAG;EAAG;EAAG;EAAG;EAC/C;EAAG;EAAG;EAAG;EAAE;EAAI;EAAG;EAAG;EAAK;EAAG;EAAE;EAAI;EAAG;EAAG;EAAG;EAAG;EAC/C;EAAG;EAAG;EAAE;EAAI;EAAG;EAAG;EAAG;EAAK;EAAG;EAAG;EAAE;EAAI;EAAG;EAAG;EAAG;EAC/C;EAAG;EAAE;EAAI;EAAG;EAAG;EAAG;EAAG;EAAK;EAAG;EAAG;EAAG;EAAE;EAAI;EAAG;EAAG;EAC/C;EAAE;EAAI;EAAG;EAAG;EAAG;EAAG;EAAG;EAAK;EAAG;EAAG;EAAG;EAAG;EAAE;EAAI;EAAG;EAChD;EAAI;EAAG;EAAG;EAAG;EAAG;EAAG;EAAG;EAAK;EAAG;EAAG;EAAG;EAAG;EAAG;EAAE;;AAI9C,IAAM,OAAO;EACV;EAAK;EAAI;EAAI;EAAI;EAAI;EAAI;EAAG;EAAK;EAAI;EAAI;EAAI;EAAI;EAAI;EAAG;EAAI;EAC3D;EAAG;EAAK;EAAI;EAAI;EAAI;EAAI;EAAG;EAAK;EAAI;EAAI;EAAI;EAAI;EAAG;EAAK;EAAG;EAC3D;EAAI;EAAG;EAAK;EAAI;EAAI;EAAI;EAAG;EAAK;EAAI;EAAI;EAAI;EAAG;EAAK;EAAI;EAAG;EAC3D;EAAI;EAAI;EAAG;EAAK;EAAI;EAAI;EAAG;EAAK;EAAI;EAAI;EAAG;EAAK;EAAI;EAAI;EAAG;EAC3D;EAAI;EAAI;EAAI;EAAG;EAAK;EAAI;EAAG;EAAK;EAAI;EAAG;EAAK;EAAI;EAAI;EAAI;EAAG;EAC3D;EAAI;EAAI;EAAI;EAAI;EAAG;EAAK;EAAG;EAAK;EAAG;EAAK;EAAI;EAAI;EAAI;EAAI;EAAG;EAC3D;EAAI;EAAI;EAAI;EAAI;EAAI;EAAG;EAAI;EAAI;EAAK;EAAI;EAAI;EAAI;EAAI;EAAI;EAAG;EAC3D;EAAI;EAAI;EAAI;EAAI;EAAI;EAAI;EAAI;EAAG;EAAI;EAAK;EAAG;EAAI;EAAI;EAAI;EAAI;EAC3D;EAAI;EAAI;EAAI;EAAI;EAAI;EAAE;EAAI;EAAI;EAAM;EAAI;EAAI;EAAI;EAAI;EAAI;EAAG;EAC3D;EAAI;EAAI;EAAI;EAAI;EAAE;EAAM;EAAE;EAAM;EAAE;EAAM;EAAI;EAAI;EAAI;EAAI;EAAG;EAC3D;EAAI;EAAI;EAAI;EAAE;EAAM;EAAI;EAAE;EAAM;EAAI;EAAE;EAAM;EAAI;EAAI;EAAI;EAAG;EAC3D;EAAI;EAAI;EAAE;EAAM;EAAI;EAAI;EAAE;EAAM;EAAI;EAAI;EAAE;EAAM;EAAI;EAAI;EAAG;EAC3D;EAAI;EAAE;EAAM;EAAI;EAAI;EAAI;EAAE;EAAM;EAAI;EAAI;EAAI;EAAE;EAAM;EAAI;EAAG;EAC3D;EAAE;EAAM;EAAI;EAAI;EAAI;EAAI;EAAE;EAAM;EAAI;EAAI;EAAI;EAAI;EAAE;EAAM;EAAG;EAC7D;EAAM;EAAI;EAAI;EAAI;EAAI;EAAI;EAAE;EAAM;EAAI;EAAI;EAAI;EAAI;EAAI;EAAE;;AAG1D,IAAM,cAAc,EAAE,GAAG,GAAK,GAAG,GAAK,GAAG,GAAK,GAAG,GAAK,GAAG,IAAM,GAAG,GAAI;AAEtE,IAAM,UAAU;AAEhB,IAAM,aAA4B,CAAC,QAAQ,QAAQ,MAAM,KAAK;AAE9D,IAAM,SAAS;AACf,IAAM,SAAS;AAOf,IAAM,SAAS;AACf,IAAM,SAAS;AAEf,IAAM,QAAQ;EACZ,CAAC,IAAI,GAAG,KAAK;EACb,CAAC,KAAK,GAAG,KAAK;;AAGhB,IAAM,QAAQ;EACZ,GAAG;IACD,EAAE,QAAQ,KAAK,IAAI,MAAM,KAAK,aAAY;IAC1C,EAAE,QAAQ,KAAK,IAAI,MAAM,KAAK,aAAY;EAC3C;EACD,GAAG;IACD,EAAE,QAAQ,KAAK,IAAI,MAAM,KAAK,aAAY;IAC1C,EAAE,QAAQ,KAAK,IAAI,MAAM,KAAK,aAAY;EAC3C;;AAGH,IAAM,cAAc,EAAE,GAAG,QAAQ,GAAG,OAAM;AAI1C,IAAM,eAAe;AAGrB,SAAS,KAAK,QAAc;AAC1B,SAAO,UAAU;AACnB;AAGA,SAAS,KAAK,QAAc;AAC1B,SAAO,SAAS;AAClB;AAEA,SAAS,QAAQ,GAAS;AACxB,SAAO,aAAa,QAAQ,CAAC,MAAM;AACrC;AAGA,SAAS,UAAU,QAAc;AAC/B,QAAM,IAAI,KAAK,MAAM;AACrB,QAAM,IAAI,KAAK,MAAM;AACrB,SAAQ,WAAW,UAAU,GAAG,IAAI,CAAC,IACnC,WAAW,UAAU,GAAG,IAAI,CAAC;AACjC;AAEA,SAAS,UAAU,OAAY;AAC7B,SAAO,UAAU,QAAQ,QAAQ;AACnC;AAEM,SAAU,YAAY,KAAW;AAErC,QAAM,SAAS,IAAI,MAAM,KAAK;AAC9B,MAAI,OAAO,WAAW,GAAG;AACvB,WAAO;MACL,IAAI;MACJ,OAAO;;EAEV;AAGD,QAAM,aAAa,SAAS,OAAO,CAAC,GAAG,EAAE;AACzC,MAAI,MAAM,UAAU,KAAK,cAAc,GAAG;AACxC,WAAO;MACL,IAAI;MACJ,OAAO;;EAEV;AAGD,QAAM,YAAY,SAAS,OAAO,CAAC,GAAG,EAAE;AACxC,MAAI,MAAM,SAAS,KAAK,YAAY,GAAG;AACrC,WAAO;MACL,IAAI;MACJ,OACE;;EAEL;AAGD,MAAI,CAAC,uBAAuB,KAAK,OAAO,CAAC,CAAC,GAAG;AAC3C,WAAO,EAAE,IAAI,OAAO,OAAO,4CAA2C;EACvE;AAGD,MAAI,WAAW,KAAK,OAAO,CAAC,CAAC,GAAG;AAC9B,WAAO,EAAE,IAAI,OAAO,OAAO,gDAA+C;EAC3E;AAGD,MAAI,CAAC,UAAU,KAAK,OAAO,CAAC,CAAC,GAAG;AAC9B,WAAO,EAAE,IAAI,OAAO,OAAO,uCAAsC;EAClE;AAGD,QAAM,OAAO,OAAO,CAAC,EAAE,MAAM,GAAG;AAChC,MAAI,KAAK,WAAW,GAAG;AACrB,WAAO;MACL,IAAI;MACJ,OAAO;;EAEV;AAGD,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AAEpC,QAAI,YAAY;AAChB,QAAI,oBAAoB;AAExB,aAAS,IAAI,GAAG,IAAI,KAAK,CAAC,EAAE,QAAQ,KAAK;AACvC,UAAI,QAAQ,KAAK,CAAC,EAAE,CAAC,CAAC,GAAG;AACvB,YAAI,mBAAmB;AACrB,iBAAO;YACL,IAAI;YACJ,OAAO;;QAEV;AACD,qBAAa,SAAS,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE;AACpC,4BAAoB;MACrB,OAAM;AACL,YAAI,CAAC,mBAAmB,KAAK,KAAK,CAAC,EAAE,CAAC,CAAC,GAAG;AACxC,iBAAO;YACL,IAAI;YACJ,OAAO;;QAEV;AACD,qBAAa;AACb,4BAAoB;MACrB;IACF;AACD,QAAI,cAAc,GAAG;AACnB,aAAO;QACL,IAAI;QACJ,OAAO;;IAEV;EACF;AAGD,MACG,OAAO,CAAC,EAAE,CAAC,KAAK,OAAO,OAAO,CAAC,KAAK,OACpC,OAAO,CAAC,EAAE,CAAC,KAAK,OAAO,OAAO,CAAC,KAAK,KACrC;AACA,WAAO,EAAE,IAAI,OAAO,OAAO,yCAAwC;EACpE;AAGD,QAAM,QAAQ;IACZ,EAAE,OAAO,SAAS,OAAO,KAAI;IAC7B,EAAE,OAAO,SAAS,OAAO,KAAI;;AAG/B,aAAW,EAAE,OAAO,MAAK,KAAM,OAAO;AACpC,QAAI,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,GAAG;AAC1B,aAAO,EAAE,IAAI,OAAO,OAAO,wBAAwB,KAAK,QAAO;IAChE;AAED,SAAK,OAAO,CAAC,EAAE,MAAM,KAAK,KAAK,CAAA,GAAI,SAAS,GAAG;AAC7C,aAAO,EAAE,IAAI,OAAO,OAAO,yBAAyB,KAAK,SAAQ;IAClE;EACF;AAGD,MACE,MAAM,KAAK,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,SAAS,KAAK,YAAW,MAAO,GAAG,GACvE;AACA,WAAO;MACL,IAAI;MACJ,OAAO;;EAEV;AAED,SAAO,EAAE,IAAI,KAAI;AACnB;AAGA,SAAS,iBAAiB,MAAoB,OAAqB;AACjE,QAAM,OAAO,KAAK;AAClB,QAAM,KAAK,KAAK;AAChB,QAAM,QAAQ,KAAK;AAEnB,MAAI,cAAc;AAClB,MAAI,WAAW;AACf,MAAI,WAAW;AAEf,WAAS,IAAI,GAAG,MAAM,MAAM,QAAQ,IAAI,KAAK,KAAK;AAChD,UAAM,YAAY,MAAM,CAAC,EAAE;AAC3B,UAAM,UAAU,MAAM,CAAC,EAAE;AACzB,UAAM,aAAa,MAAM,CAAC,EAAE;AAM5B,QAAI,UAAU,cAAc,SAAS,aAAa,OAAO,SAAS;AAChE;AAEA,UAAI,KAAK,IAAI,MAAM,KAAK,SAAS,GAAG;AAClC;MACD;AAED,UAAI,KAAK,IAAI,MAAM,KAAK,SAAS,GAAG;AAClC;MACD;IACF;EACF;AAED,MAAI,cAAc,GAAG;AACnB,QAAI,WAAW,KAAK,WAAW,GAAG;AAKhC,aAAO,UAAU,IAAI;IACtB,WAAU,WAAW,GAAG;AAKvB,aAAO,UAAU,IAAI,EAAE,OAAO,CAAC;IAChC,OAAM;AAEL,aAAO,UAAU,IAAI,EAAE,OAAO,CAAC;IAChC;EACF;AAED,SAAO;AACT;AAEA,SAAS,QACP,OACA,OACA,MACA,IACA,OACA,WAAoC,QACpC,QAAgB,KAAK,QAAM;AAE3B,QAAM,IAAI,KAAK,EAAE;AAEjB,MAAI,UAAU,SAAS,MAAM,UAAU,MAAM,SAAS;AACpD,aAAS,IAAI,GAAG,IAAI,WAAW,QAAQ,KAAK;AAC1C,YAAM,YAAY,WAAW,CAAC;AAC9B,YAAM,KAAK;QACT;QACA;QACA;QACA;QACA;QACA;QACA,OAAO,QAAQ,KAAK;MACrB,CAAA;IACF;EACF,OAAM;AACL,UAAM,KAAK;MACT;MACA;MACA;MACA;MACA;MACA;IACD,CAAA;EACF;AACH;AAEA,SAAS,eAAe,KAAW;AACjC,MAAI,YAAY,IAAI,OAAO,CAAC;AAC5B,MAAI,aAAa,OAAO,aAAa,KAAK;AACxC,UAAM,UAAU,IAAI,MAAM,kBAAkB;AAC5C,QAAI,SAAS;AACX,aAAO;IACR;AACD,WAAO;EACR;AACD,cAAY,UAAU,YAAW;AACjC,MAAI,cAAc,KAAK;AACrB,WAAO;EACR;AACD,SAAO;AACT;AAGA,SAAS,YAAY,MAAY;AAC/B,SAAO,KAAK,QAAQ,KAAK,EAAE,EAAE,QAAQ,eAAe,EAAE;AACxD;IAEa,cAAK;EAiBhB,YAAY,MAAM,kBAAkB,EAAE,iBAAiB,MAAK,IAAK,CAAA,GAAE;AAhB3D,kCAAS,IAAI,MAAa,GAAG;AAC7B,iCAAe;AACf,mCAAyC,CAAA;AACzC,kCAAgC,EAAE,GAAG,OAAO,GAAG,MAAK;AACpD,qCAAY;AACZ,sCAAa;AACb,uCAAc;AACd,oCAAsB,CAAA;AACtB,qCAAoC,CAAA;AACpC,qCAAmC,EAAE,GAAG,GAAG,GAAG,EAAC;AAE/C,iCAAQ;AAGR;0CAAiB,oBAAI,IAAG;AAG9B,SAAK,KAAK,KAAK,EAAE,eAAc,CAAE;;EAGnC,MAAM,EAAE,kBAAkB,MAAK,IAAK,CAAA,GAAE;AACpC,SAAK,SAAS,IAAI,MAAa,GAAG;AAClC,SAAK,SAAS,EAAE,GAAG,OAAO,GAAG,MAAK;AAClC,SAAK,QAAQ;AACb,SAAK,YAAY,EAAE,GAAG,GAAG,GAAG,EAAC;AAC7B,SAAK,YAAY;AACjB,SAAK,aAAa;AAClB,SAAK,cAAc;AACnB,SAAK,WAAW,CAAA;AAChB,SAAK,YAAY,CAAA;AACjB,SAAK,UAAU,kBAAkB,KAAK,UAAU,EAAE,GAAG,gBAAe;AACpE,SAAK,QAAQ,KAAK,aAAY;AAC9B,SAAK,iBAAiB,oBAAI,IAAG;AAO7B,SAAK,QAAQ,OAAO,IAAI;AACxB,SAAK,QAAQ,KAAK,IAAI;;EAGxB,KAAK,KAAa,EAAE,iBAAiB,OAAO,kBAAkB,MAAK,IAAK,CAAA,GAAE;AACxE,QAAI,SAAS,IAAI,MAAM,KAAK;AAG5B,QAAI,OAAO,UAAU,KAAK,OAAO,SAAS,GAAG;AAC3C,YAAM,cAAc,CAAC,KAAK,KAAK,KAAK,GAAG;AACvC,YAAM,OAAO,OAAO,YAAY,MAAM,EAAE,IAAI,OAAO,OAAO,CAAC,EAAE,KAAK,GAAG;IACtE;AAED,aAAS,IAAI,MAAM,KAAK;AAExB,QAAI,CAAC,gBAAgB;AACnB,YAAM,EAAE,IAAI,MAAK,IAAK,YAAY,GAAG;AACrC,UAAI,CAAC,IAAI;AACP,cAAM,IAAI,MAAM,KAAK;MACtB;IACF;AAED,UAAM,WAAW,OAAO,CAAC;AACzB,QAAI,SAAS;AAEb,SAAK,MAAM,EAAE,gBAAe,CAAE;AAE9B,aAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;AACxC,YAAM,QAAQ,SAAS,OAAO,CAAC;AAE/B,UAAI,UAAU,KAAK;AACjB,kBAAU;MACX,WAAU,QAAQ,KAAK,GAAG;AACzB,kBAAU,SAAS,OAAO,EAAE;MAC7B,OAAM;AACL,cAAM,QAAQ,QAAQ,MAAM,QAAQ;AACpC,aAAK,KACH,EAAE,MAAM,MAAM,YAAW,GAAmB,MAAK,GACjD,UAAU,MAAM,CAAC;AAEnB;MACD;IACF;AAED,SAAK,QAAQ,OAAO,CAAC;AAErB,QAAI,OAAO,CAAC,EAAE,QAAQ,GAAG,IAAI,IAAI;AAC/B,WAAK,UAAU,KAAK,KAAK;IAC1B;AACD,QAAI,OAAO,CAAC,EAAE,QAAQ,GAAG,IAAI,IAAI;AAC/B,WAAK,UAAU,KAAK,KAAK;IAC1B;AACD,QAAI,OAAO,CAAC,EAAE,QAAQ,GAAG,IAAI,IAAI;AAC/B,WAAK,UAAU,KAAK,KAAK;IAC1B;AACD,QAAI,OAAO,CAAC,EAAE,QAAQ,GAAG,IAAI,IAAI;AAC/B,WAAK,UAAU,KAAK,KAAK;IAC1B;AAED,SAAK,YAAY,OAAO,CAAC,MAAM,MAAM,QAAQ,KAAK,OAAO,CAAC,CAAW;AACrE,SAAK,aAAa,SAAS,OAAO,CAAC,GAAG,EAAE;AACxC,SAAK,cAAc,SAAS,OAAO,CAAC,GAAG,EAAE;AAEzC,SAAK,QAAQ,KAAK,aAAY;AAC9B,SAAK,aAAa,GAAG;AACrB,SAAK,kBAAiB;;EAGxB,IAAI,EACF,uBAAuB,MAAK,IACU,CAAA,GAAE;AACxC,QAAI,QAAQ;AACZ,QAAI,MAAM;AAEV,aAAS,IAAI,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK;AACvC,UAAI,KAAK,OAAO,CAAC,GAAG;AAClB,YAAI,QAAQ,GAAG;AACb,iBAAO;AACP,kBAAQ;QACT;AACD,cAAM,EAAE,OAAO,MAAM,MAAK,IAAK,KAAK,OAAO,CAAC;AAE5C,eAAO,UAAU,QAAQ,MAAM,YAAW,IAAK,MAAM,YAAW;MACjE,OAAM;AACL;MACD;AAED,UAAK,IAAI,IAAK,KAAM;AAClB,YAAI,QAAQ,GAAG;AACb,iBAAO;QACR;AAED,YAAI,MAAM,KAAK,IAAI;AACjB,iBAAO;QACR;AAED,gBAAQ;AACR,aAAK;MACN;IACF;AAED,QAAI,WAAW;AACf,QAAI,KAAK,UAAU,KAAK,IAAI,KAAK,cAAc;AAC7C,kBAAY;IACb;AACD,QAAI,KAAK,UAAU,KAAK,IAAI,KAAK,cAAc;AAC7C,kBAAY;IACb;AACD,QAAI,KAAK,UAAU,KAAK,IAAI,KAAK,cAAc;AAC7C,kBAAY;IACb;AACD,QAAI,KAAK,UAAU,KAAK,IAAI,KAAK,cAAc;AAC7C,kBAAY;IACb;AAGD,eAAW,YAAY;AAEvB,QAAI,WAAW;AAKf,QAAI,KAAK,cAAc,OAAO;AAC5B,UAAI,sBAAsB;AACxB,mBAAW,UAAU,KAAK,SAAS;MACpC,OAAM;AACL,cAAM,gBAAgB,KAAK,aAAa,KAAK,UAAU,QAAQ,KAAK;AACpE,cAAM,UAAU,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;AAErD,mBAAW,UAAU,SAAS;AAE5B,cAAI,SAAS,KAAM;AACjB;UACD;AAED,gBAAM,QAAQ,KAAK;AAGnB,cACE,KAAK,OAAO,MAAM,GAAG,UAAU,SAC/B,KAAK,OAAO,MAAM,GAAG,SAAS,MAC9B;AAEA,iBAAK,UAAU;cACb;cACA,MAAM;cACN,IAAI,KAAK;cACT,OAAO;cACP,UAAU;cACV,OAAO,KAAK;YACb,CAAA;AACD,kBAAM,UAAU,CAAC,KAAK,gBAAgB,KAAK;AAC3C,iBAAK,UAAS;AAGd,gBAAI,SAAS;AACX,yBAAW,UAAU,KAAK,SAAS;AACnC;YACD;UACF;QACF;MACF;IACF;AAED,WAAO;MACL;MACA,KAAK;MACL;MACA;MACA,KAAK;MACL,KAAK;IACN,EAAC,KAAK,GAAG;;EAGJ,UAAU,GAAS;AACzB,QAAI,CAAC,KAAK,OAAO,CAAC,GAAG;AACnB,aAAO;IACR;AAED,UAAM,EAAE,OAAO,KAAI,IAAK,KAAK,OAAO,CAAC;AAErC,UAAM,aAAa;MACjB,GAAG;MACH,GAAG;MACH,KAAK;AAEP,UAAM,YAAY;MAChB,GAAG;MACH,GAAG;MACH,GAAG;MACH,GAAG;MACH,GAAG;MACH,GAAG;MACH,IAAI;AAEN,WAAO,WAAW,UAAU,EAAE,SAAS,EAAE,CAAC;;EAGpC,SAAM;AACZ,WAAO,KAAK,cAAc,QAAQ,KAAK,QAAQ,KAAK,YAAY,CAAC;;EAG3D,eAAY;AAClB,UAAM,QAAS,KAAK,UAAU,KAAK,IAAM,KAAK,UAAU,KAAK;AAC7D,WAAO,cAAc,KAAK;;EAGpB,eAAY;AAClB,QAAI,OAAO;AAEX,aAAS,IAAI,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK;AAEvC,UAAI,IAAI,KAAM;AACZ,aAAK;AACL;MACD;AAED,UAAI,KAAK,OAAO,CAAC,GAAG;AAClB,gBAAQ,KAAK,UAAU,CAAC;MACzB;IACF;AAED,YAAQ,KAAK,OAAM;AACnB,YAAQ,KAAK,aAAY;AAEzB,QAAI,KAAK,UAAU,KAAK;AACtB,cAAQ;IACT;AAED,WAAO;;;;;;;;EASD,aAAa,KAAW;AAC9B,QAAI,KAAK,SAAS,SAAS;AAAG;AAE9B,QAAI,QAAQ,kBAAkB;AAC5B,WAAK,QAAQ,OAAO,IAAI;AACxB,WAAK,QAAQ,KAAK,IAAI;IACvB,OAAM;AACL,WAAK,QAAQ,OAAO,IAAI;AACxB,WAAK,QAAQ,KAAK,IAAI;IACvB;;EAGH,QAAK;AACH,SAAK,KAAK,gBAAgB;;EAG5B,IAAI,QAAc;AAChB,WAAO,KAAK,OAAO,KAAK,MAAM,CAAC;;EAGjC,UAAU,OAAY;AACpB,UAAM,UAAoB,CAAA;AAC1B,aAAS,IAAI,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK;AAEvC,UAAI,IAAI,KAAM;AACZ,aAAK;AACL;MACD;AAGD,UAAI,CAAC,KAAK,OAAO,CAAC,KAAK,KAAK,OAAO,CAAC,GAAG,UAAU,MAAM,OAAO;AAC5D;MACD;AAGD,UACE,KAAK,OAAO,CAAC,EAAE,UAAU,MAAM,SAC/B,KAAK,OAAO,CAAC,EAAE,SAAS,MAAM,MAC9B;AACA,gBAAQ,KAAK,UAAU,CAAC,CAAC;MAC1B;IACF;AAED,WAAO;;EAGT,IACE,EAAE,MAAM,MAAK,GACb,QAAc;AAEd,QAAI,KAAK,KAAK,EAAE,MAAM,MAAK,GAAI,MAAM,GAAG;AACtC,WAAK,sBAAqB;AAC1B,WAAK,uBAAsB;AAC3B,WAAK,aAAa,KAAK,IAAG,CAAE;AAC5B,aAAO;IACR;AACD,WAAO;;EAGD,KAAK,IAAY,OAAY;AACnC,SAAK,SAAS,KAAK,UAAU,EAAE;AAC/B,SAAK,OAAO,EAAE,IAAI;AAClB,SAAK,SAAS,KAAK,UAAU,EAAE;;EAGzB,KACN,EAAE,MAAM,MAAK,GACb,QAAc;AAGd,QAAI,QAAQ,QAAQ,KAAK,YAAW,CAAE,MAAM,IAAI;AAC9C,aAAO;IACR;AAGD,QAAI,EAAE,UAAU,OAAO;AACrB,aAAO;IACR;AAED,UAAM,KAAK,KAAK,MAAM;AAGtB,QACE,QAAQ,QACR,EAAE,KAAK,OAAO,KAAK,KAAK,SAAS,KAAK,OAAO,KAAK,KAAK,KACvD;AACA,aAAO;IACR;AAED,UAAM,uBAAuB,KAAK,OAAO,EAAE;AAG3C,QAAI,wBAAwB,qBAAqB,SAAS,MAAM;AAC9D,WAAK,OAAO,qBAAqB,KAAK,IAAI;IAC3C;AAED,SAAK,KAAK,IAAI,EAAE,MAA2B,MAAqB,CAAE;AAElE,QAAI,SAAS,MAAM;AACjB,WAAK,OAAO,KAAK,IAAI;IACtB;AAED,WAAO;;EAGD,OAAO,IAAU;AACvB,SAAK,SAAS,KAAK,UAAU,EAAE;AAC/B,WAAO,KAAK,OAAO,EAAE;;EAGvB,OAAO,QAAc;AACnB,UAAM,QAAQ,KAAK,IAAI,MAAM;AAC7B,SAAK,OAAO,KAAK,MAAM,CAAC;AACxB,QAAI,SAAS,MAAM,SAAS,MAAM;AAChC,WAAK,OAAO,MAAM,KAAK,IAAI;IAC5B;AAED,SAAK,sBAAqB;AAC1B,SAAK,uBAAsB;AAC3B,SAAK,aAAa,KAAK,IAAG,CAAE;AAE5B,WAAO;;EAGD,wBAAqB;AAC3B,SAAK,SAAS,KAAK,aAAY;AAE/B,UAAM,mBACJ,KAAK,OAAO,KAAK,EAAE,GAAG,SAAS,QAC/B,KAAK,OAAO,KAAK,EAAE,GAAG,UAAU;AAClC,UAAM,mBACJ,KAAK,OAAO,KAAK,EAAE,GAAG,SAAS,QAC/B,KAAK,OAAO,KAAK,EAAE,GAAG,UAAU;AAElC,QACE,CAAC,oBACD,KAAK,OAAO,KAAK,EAAE,GAAG,SAAS,QAC/B,KAAK,OAAO,KAAK,EAAE,GAAG,UAAU,OAChC;AACA,WAAK,UAAU,KAAK;IACrB;AAED,QACE,CAAC,oBACD,KAAK,OAAO,KAAK,EAAE,GAAG,SAAS,QAC/B,KAAK,OAAO,KAAK,EAAE,GAAG,UAAU,OAChC;AACA,WAAK,UAAU,KAAK;IACrB;AAED,QACE,CAAC,oBACD,KAAK,OAAO,KAAK,EAAE,GAAG,SAAS,QAC/B,KAAK,OAAO,KAAK,EAAE,GAAG,UAAU,OAChC;AACA,WAAK,UAAU,KAAK;IACrB;AAED,QACE,CAAC,oBACD,KAAK,OAAO,KAAK,EAAE,GAAG,SAAS,QAC/B,KAAK,OAAO,KAAK,EAAE,GAAG,UAAU,OAChC;AACA,WAAK,UAAU,KAAK;IACrB;AAED,SAAK,SAAS,KAAK,aAAY;;EAGzB,yBAAsB;AAC5B,QAAI,KAAK,cAAc,OAAO;AAC5B;IACD;AAED,UAAM,cAAc,KAAK,aAAa,KAAK,UAAU,QAAQ,MAAM;AACnE,UAAM,gBAAgB,KAAK,aAAa,KAAK,UAAU,QAAQ,KAAK;AACpE,UAAM,YAAY,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;AAEvD,QACE,KAAK,OAAO,WAAW,MAAM,QAC7B,KAAK,OAAO,KAAK,SAAS,MAAM,QAChC,KAAK,OAAO,aAAa,GAAG,UAAU,UAAU,KAAK,KAAK,KAC1D,KAAK,OAAO,aAAa,GAAG,SAAS,MACrC;AACA,WAAK,SAAS,KAAK,OAAM;AACzB,WAAK,YAAY;AACjB;IACD;AAED,UAAM,aAAa,CAAC,WAClB,EAAE,SAAS,QACX,KAAK,OAAO,MAAM,GAAG,UAAU,KAAK,SACpC,KAAK,OAAO,MAAM,GAAG,SAAS;AAEhC,QAAI,CAAC,UAAU,KAAK,UAAU,GAAG;AAC/B,WAAK,SAAS,KAAK,OAAM;AACzB,WAAK,YAAY;IAClB;;EAMK,UAAU,OAAc,QAAgB,SAAiB;AAC/D,UAAM,YAAsB,CAAA;AAC5B,aAAS,IAAI,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK;AAEvC,UAAI,IAAI,KAAM;AACZ,aAAK;AACL;MACD;AAGD,UAAI,KAAK,OAAO,CAAC,MAAM,UAAa,KAAK,OAAO,CAAC,EAAE,UAAU,OAAO;AAClE;MACD;AAED,YAAM,QAAQ,KAAK,OAAO,CAAC;AAC3B,YAAM,aAAa,IAAI;AAGvB,UAAI,eAAe,GAAG;AACpB;MACD;AAED,YAAM,QAAQ,aAAa;AAE3B,UAAI,QAAQ,KAAK,IAAI,YAAY,MAAM,IAAI,GAAG;AAC5C,YAAI,MAAM,SAAS,MAAM;AACvB,cACG,aAAa,KAAK,MAAM,UAAU,SAClC,cAAc,KAAK,MAAM,UAAU,OACpC;AACA,gBAAI,CAAC,SAAS;AACZ,qBAAO;YACR,OAAM;AACL,wBAAU,KAAK,UAAU,CAAC,CAAC;YAC5B;UACF;AACD;QACD;AAGD,YAAI,MAAM,SAAS,OAAO,MAAM,SAAS,KAAK;AAC5C,cAAI,CAAC,SAAS;AACZ,mBAAO;UACR,OAAM;AACL,sBAAU,KAAK,UAAU,CAAC,CAAC;AAC3B;UACD;QACF;AAED,cAAM,SAAS,KAAK,KAAK;AACzB,YAAI,IAAI,IAAI;AAEZ,YAAI,UAAU;AACd,eAAO,MAAM,QAAQ;AACnB,cAAI,KAAK,OAAO,CAAC,KAAK,MAAM;AAC1B,sBAAU;AACV;UACD;AACD,eAAK;QACN;AAED,YAAI,CAAC,SAAS;AACZ,cAAI,CAAC,SAAS;AACZ,mBAAO;UACR,OAAM;AACL,sBAAU,KAAK,UAAU,CAAC,CAAC;AAC3B;UACD;QACF;MACF;IACF;AAED,QAAI,SAAS;AACX,aAAO;IACR,OAAM;AACL,aAAO;IACR;;EAGH,UAAU,QAAgB,YAAkB;AAC1C,QAAI,CAAC,YAAY;AACf,aAAO,KAAK,UAAU,KAAK,OAAO,KAAK,MAAM,GAAG,IAAI;IACrD,OAAM;AACL,aAAO,KAAK,UAAU,YAAY,KAAK,MAAM,GAAG,IAAI;IACrD;;EAGK,gBAAgB,OAAY;AAClC,UAAM,SAAS,KAAK,OAAO,KAAK;AAChC,WAAO,WAAW,KAAK,QAAQ,KAAK,UAAU,UAAU,KAAK,GAAG,MAAM;;EAGxE,OAAI;AACF,WAAO,KAAK,MAAM,SAAS,EAAE;;EAG/B,WAAW,QAAgB,YAAiB;AAC1C,WAAO,KAAK,UAAU,YAAY,KAAK,MAAM,CAAC;;EAGhD,UAAO;AACL,WAAO,KAAK,gBAAgB,KAAK,KAAK;;EAGxC,UAAO;AACL,WAAO,KAAK,QAAO;;EAGrB,cAAW;AACT,WAAO,KAAK,QAAO,KAAM,KAAK,OAAM,EAAG,WAAW;;EAGpD,cAAW;AACT,WAAO,CAAC,KAAK,QAAO,KAAM,KAAK,OAAM,EAAG,WAAW;;EAGrD,yBAAsB;AAQpB,UAAM,SAAsC;MAC1C,GAAG;MACH,GAAG;MACH,GAAG;MACH,GAAG;MACH,GAAG;MACH,GAAG;;AAEL,UAAM,UAAU,CAAA;AAChB,QAAI,YAAY;AAChB,QAAI,cAAc;AAElB,aAAS,IAAI,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK;AACvC,qBAAe,cAAc,KAAK;AAClC,UAAI,IAAI,KAAM;AACZ,aAAK;AACL;MACD;AAED,YAAM,QAAQ,KAAK,OAAO,CAAC;AAC3B,UAAI,OAAO;AACT,eAAO,MAAM,IAAI,IAAI,MAAM,QAAQ,SAAS,OAAO,MAAM,IAAI,IAAI,IAAI;AACrE,YAAI,MAAM,SAAS,QAAQ;AACzB,kBAAQ,KAAK,WAAW;QACzB;AACD;MACD;IACF;AAGD,QAAI,cAAc,GAAG;AACnB,aAAO;IACR;;MAEC,cAAc,MACb,OAAO,MAAM,MAAM,KAAK,OAAO,MAAM,MAAM;MAC5C;AACA,aAAO;IACR,WAAU,cAAc,OAAO,MAAM,IAAI,GAAG;AAE3C,UAAI,MAAM;AACV,YAAM,MAAM,QAAQ;AACpB,eAAS,IAAI,GAAG,IAAI,KAAK,KAAK;AAC5B,eAAO,QAAQ,CAAC;MACjB;AACD,UAAI,QAAQ,KAAK,QAAQ,KAAK;AAC5B,eAAO;MACR;IACF;AAED,WAAO;;EAGT,wBAAqB;AACnB,WAAO,KAAK,kBAAkB,KAAK,KAAK,KAAK;;EAG/C,qBAAkB;AAChB,WAAO,KAAK,cAAc;;EAG5B,SAAM;AACJ,WACE,KAAK,mBAAkB,KACvB,KAAK,YAAW,KAChB,KAAK,uBAAsB,KAC3B,KAAK,sBAAqB;;EAI9B,aAAU;AACR,WAAO,KAAK,YAAW,KAAM,KAAK,OAAM;;EA2D1C,MAAM,EACJ,UAAU,OACV,SAAS,QACT,QAAQ,OAAS,IAC8C,CAAA,GAAE;AACjE,UAAM,QAAQ,KAAK,OAAO,EAAE,QAAQ,MAAK,CAAE;AAE3C,QAAI,SAAS;AACX,aAAO,MAAM,IAAI,CAAC,SAAS,IAAI,KAAK,MAAM,IAAI,CAAC;IAChD,OAAM;AACL,aAAO,MAAM,IAAI,CAAC,SAAS,KAAK,WAAW,MAAM,KAAK,CAAC;IACxD;;EAGK,OAAO,EACb,QAAQ,MACR,QAAQ,QACR,SAAS,OAAS,IAKhB,CAAA,GAAE;AACJ,UAAM,YAAY,SAAU,OAAO,YAAW,IAAgB;AAC9D,UAAM,WAAW,OAAO,YAAW;AAEnC,UAAM,QAAwB,CAAA;AAC9B,UAAM,KAAK,KAAK;AAChB,UAAM,OAAO,UAAU,EAAE;AAEzB,QAAI,cAAc,KAAK;AACvB,QAAI,aAAa,KAAK;AACtB,QAAI,eAAe;AAGnB,QAAI,WAAW;AAEb,UAAI,EAAE,aAAa,OAAO;AACxB,eAAO,CAAA;MACR,OAAM;AACL,sBAAc,aAAa,KAAK,SAAS;AACzC,uBAAe;MAChB;IACF;AAED,aAAS,OAAO,aAAa,QAAQ,YAAY,QAAQ;AAEvD,UAAI,OAAO,KAAM;AACf,gBAAQ;AACR;MACD;AAGD,UAAI,CAAC,KAAK,OAAO,IAAI,KAAK,KAAK,OAAO,IAAI,EAAE,UAAU,MAAM;AAC1D;MACD;AACD,YAAM,EAAE,KAAI,IAAK,KAAK,OAAO,IAAI;AAEjC,UAAI;AACJ,UAAI,SAAS,MAAM;AACjB,YAAI,YAAY,aAAa;AAAM;AAGnC,aAAK,OAAO,aAAa,EAAE,EAAE,CAAC;AAC9B,YAAI,CAAC,KAAK,OAAO,EAAE,GAAG;AACpB,kBAAQ,OAAO,IAAI,MAAM,IAAI,IAAI;AAGjC,eAAK,OAAO,aAAa,EAAE,EAAE,CAAC;AAC9B,cAAI,YAAY,EAAE,MAAM,KAAK,IAAI,KAAK,CAAC,KAAK,OAAO,EAAE,GAAG;AACtD,oBAAQ,OAAO,IAAI,MAAM,IAAI,MAAM,QAAW,KAAK,QAAQ;UAC5D;QACF;AAGD,iBAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,eAAK,OAAO,aAAa,EAAE,EAAE,CAAC;AAC9B,cAAI,KAAK;AAAM;AAEf,cAAI,KAAK,OAAO,EAAE,GAAG,UAAU,MAAM;AACnC,oBACE,OACA,IACA,MACA,IACA,MACA,KAAK,OAAO,EAAE,EAAE,MAChB,KAAK,OAAO;UAEf,WAAU,OAAO,KAAK,WAAW;AAChC,oBAAQ,OAAO,IAAI,MAAM,IAAI,MAAM,MAAM,KAAK,UAAU;UACzD;QACF;MACF,OAAM;AACL,YAAI,YAAY,aAAa;AAAM;AAEnC,iBAAS,IAAI,GAAG,MAAM,cAAc,IAAI,EAAE,QAAQ,IAAI,KAAK,KAAK;AAC9D,gBAAM,SAAS,cAAc,IAAI,EAAE,CAAC;AACpC,eAAK;AAEL,iBAAO,MAAM;AACX,kBAAM;AACN,gBAAI,KAAK;AAAM;AAEf,gBAAI,CAAC,KAAK,OAAO,EAAE,GAAG;AACpB,sBAAQ,OAAO,IAAI,MAAM,IAAI,IAAI;YAClC,OAAM;AAEL,kBAAI,KAAK,OAAO,EAAE,EAAE,UAAU;AAAI;AAElC,sBACE,OACA,IACA,MACA,IACA,MACA,KAAK,OAAO,EAAE,EAAE,MAChB,KAAK,OAAO;AAEd;YACD;AAGD,gBAAI,SAAS,UAAU,SAAS;AAAM;UACvC;QACF;MACF;IACF;AAQD,QAAI,aAAa,UAAa,aAAa,MAAM;AAC/C,UAAI,CAAC,gBAAgB,eAAe,KAAK,OAAO,EAAE,GAAG;AAEnD,YAAI,KAAK,UAAU,EAAE,IAAI,KAAK,cAAc;AAC1C,gBAAM,eAAe,KAAK,OAAO,EAAE;AACnC,gBAAM,aAAa,eAAe;AAElC,cACE,CAAC,KAAK,OAAO,eAAe,CAAC,KAC7B,CAAC,KAAK,OAAO,UAAU,KACvB,CAAC,KAAK,UAAU,MAAM,KAAK,OAAO,EAAE,CAAC,KACrC,CAAC,KAAK,UAAU,MAAM,eAAe,CAAC,KACtC,CAAC,KAAK,UAAU,MAAM,UAAU,GAChC;AACA,oBACE,OACA,IACA,KAAK,OAAO,EAAE,GACd,YACA,MACA,QACA,KAAK,YAAY;UAEpB;QACF;AAGD,YAAI,KAAK,UAAU,EAAE,IAAI,KAAK,cAAc;AAC1C,gBAAM,eAAe,KAAK,OAAO,EAAE;AACnC,gBAAM,aAAa,eAAe;AAElC,cACE,CAAC,KAAK,OAAO,eAAe,CAAC,KAC7B,CAAC,KAAK,OAAO,eAAe,CAAC,KAC7B,CAAC,KAAK,OAAO,eAAe,CAAC,KAC7B,CAAC,KAAK,UAAU,MAAM,KAAK,OAAO,EAAE,CAAC,KACrC,CAAC,KAAK,UAAU,MAAM,eAAe,CAAC,KACtC,CAAC,KAAK,UAAU,MAAM,UAAU,GAChC;AACA,oBACE,OACA,IACA,KAAK,OAAO,EAAE,GACd,YACA,MACA,QACA,KAAK,YAAY;UAEpB;QACF;MACF;IACF;AAMD,QAAI,CAAC,SAAS,KAAK,OAAO,EAAE,MAAM,IAAI;AACpC,aAAO;IACR;AAGD,UAAMC,cAAa,CAAA;AAEnB,aAAS,IAAI,GAAG,MAAM,MAAM,QAAQ,IAAI,KAAK,KAAK;AAChD,WAAK,UAAU,MAAM,CAAC,CAAC;AACvB,UAAI,CAAC,KAAK,gBAAgB,EAAE,GAAG;AAC7B,QAAAA,YAAW,KAAK,MAAM,CAAC,CAAC;MACzB;AACD,WAAK,UAAS;IACf;AAED,WAAOA;;EAGT,KACE,MACA,EAAE,SAAS,MAAK,IAA2B,CAAA,GAAE;AAgB7C,QAAI,UAAU;AAEd,QAAI,OAAO,SAAS,UAAU;AAC5B,gBAAU,KAAK,aAAa,MAAM,MAAM;IACzC,WAAU,SAAS,MAAM;AACxB,gBAAU,KAAK,aAAa,cAAc,MAAM;IACjD,WAAU,OAAO,SAAS,UAAU;AACnC,YAAM,QAAQ,KAAK,OAAM;AAGzB,eAAS,IAAI,GAAG,MAAM,MAAM,QAAQ,IAAI,KAAK,KAAK;AAChD,YACE,KAAK,SAAS,UAAU,MAAM,CAAC,EAAE,IAAI,KACrC,KAAK,OAAO,UAAU,MAAM,CAAC,EAAE,EAAE,MAChC,EAAE,eAAe,MAAM,CAAC,MAAM,KAAK,cAAc,MAAM,CAAC,EAAE,YAC3D;AACA,oBAAU,MAAM,CAAC;AACjB;QACD;MACF;IACF;AAGD,QAAI,CAAC,SAAS;AACZ,UAAI,OAAO,SAAS,UAAU;AAC5B,cAAM,IAAI,MAAM,iBAAiB,IAAI,EAAE;MACxC,OAAM;AACL,cAAM,IAAI,MAAM,iBAAiB,KAAK,UAAU,IAAI,CAAC,EAAE;MACxD;IACF;AAGD,QAAI,KAAK,QAAO,KAAM,QAAQ,QAAQ,KAAK,WAAW;AACpD,YAAM,IAAI,MAAM,qCAAqC;IACtD;AAMD,UAAM,aAAa,IAAI,KAAK,MAAM,OAAO;AAEzC,SAAK,UAAU,OAAO;AACtB,SAAK,kBAAiB;AACtB,WAAO;;EAGD,MAAM,MAAkB;AAC9B,SAAK,SAAS,KAAK;MACjB;MACA,OAAO,EAAE,GAAG,KAAK,OAAO,GAAG,GAAG,KAAK,OAAO,EAAC;MAC3C,MAAM,KAAK;MACX,UAAU,EAAE,GAAG,KAAK,UAAU,GAAG,GAAG,KAAK,UAAU,EAAC;MACpD,UAAU,KAAK;MACf,WAAW,KAAK;MAChB,YAAY,KAAK;IAClB,CAAA;;EAGK,WAAW,MAAc,IAAU;AACzC,SAAK,SAAS,KAAK,UAAU,IAAI;AAEjC,SAAK,OAAO,EAAE,IAAI,KAAK,OAAO,IAAI;AAClC,WAAO,KAAK,OAAO,IAAI;AAEvB,SAAK,SAAS,KAAK,UAAU,EAAE;;EAGzB,UAAU,MAAkB;AAClC,UAAM,KAAK,KAAK;AAChB,UAAM,OAAO,UAAU,EAAE;AACzB,SAAK,MAAM,IAAI;AAEf,QAAI,KAAK,QAAQ,KAAK,WAAW;AAC/B,UAAI,OAAO,OAAO;AAChB,aAAK;MACN;AACD,WAAK;AACL,WAAK,QAAQ;AAEb,WAAK,YAAY;AAEjB;IACD;AAED,SAAK,SAAS,KAAK,OAAM;AACzB,SAAK,SAAS,KAAK,aAAY;AAE/B,QAAI,KAAK,UAAU;AACjB,WAAK,SAAS,KAAK,UAAU,KAAK,EAAE;IACrC;AAED,SAAK,WAAW,KAAK,MAAM,KAAK,EAAE;AAGlC,QAAI,KAAK,QAAQ,KAAK,YAAY;AAChC,UAAI,KAAK,UAAU,OAAO;AACxB,aAAK,OAAO,KAAK,KAAK,EAAE;MACzB,OAAM;AACL,aAAK,OAAO,KAAK,KAAK,EAAE;MACzB;IACF;AAGD,QAAI,KAAK,WAAW;AAClB,WAAK,OAAO,KAAK,EAAE;AACnB,WAAK,KAAK,KAAK,IAAI,EAAE,MAAM,KAAK,WAAW,OAAO,GAAE,CAAE;IACvD;AAGD,QAAI,KAAK,OAAO,KAAK,EAAE,EAAE,SAAS,MAAM;AACtC,WAAK,OAAO,EAAE,IAAI,KAAK;AAGvB,UAAI,KAAK,QAAQ,KAAK,cAAc;AAClC,cAAM,aAAa,KAAK,KAAK;AAC7B,cAAM,eAAe,KAAK,KAAK;AAC/B,aAAK,WAAW,cAAc,UAAU;MACzC,WAAU,KAAK,QAAQ,KAAK,cAAc;AACzC,cAAM,aAAa,KAAK,KAAK;AAC7B,cAAM,eAAe,KAAK,KAAK;AAC/B,aAAK,WAAW,cAAc,UAAU;MACzC;AAGD,WAAK,UAAU,EAAE,IAAI;IACtB;AAGD,QAAI,KAAK,UAAU,EAAE,GAAG;AACtB,eAAS,IAAI,GAAG,MAAM,MAAM,EAAE,EAAE,QAAQ,IAAI,KAAK,KAAK;AACpD,YACE,KAAK,SAAS,MAAM,EAAE,EAAE,CAAC,EAAE,UAC3B,KAAK,UAAU,EAAE,IAAI,MAAM,EAAE,EAAE,CAAC,EAAE,MAClC;AACA,eAAK,UAAU,EAAE,KAAK,MAAM,EAAE,EAAE,CAAC,EAAE;AACnC;QACD;MACF;IACF;AAGD,QAAI,KAAK,UAAU,IAAI,GAAG;AACxB,eAAS,IAAI,GAAG,MAAM,MAAM,IAAI,EAAE,QAAQ,IAAI,KAAK,KAAK;AACtD,YACE,KAAK,OAAO,MAAM,IAAI,EAAE,CAAC,EAAE,UAC3B,KAAK,UAAU,IAAI,IAAI,MAAM,IAAI,EAAE,CAAC,EAAE,MACtC;AACA,eAAK,UAAU,IAAI,KAAK,MAAM,IAAI,EAAE,CAAC,EAAE;AACvC;QACD;MACF;IACF;AAED,SAAK,SAAS,KAAK,aAAY;AAG/B,QAAI,KAAK,QAAQ,KAAK,UAAU;AAC9B,UAAI;AAEJ,UAAI,OAAO,OAAO;AAChB,mBAAW,KAAK,KAAK;MACtB,OAAM;AACL,mBAAW,KAAK,KAAK;MACtB;AAED,UACG,EAAG,KAAK,KAAK,IAAK,QACjB,KAAK,OAAO,KAAK,KAAK,CAAC,GAAG,SAAS,QACnC,KAAK,OAAO,KAAK,KAAK,CAAC,GAAG,UAAU,QACrC,EAAG,KAAK,KAAK,IAAK,QACjB,KAAK,OAAO,KAAK,KAAK,CAAC,GAAG,SAAS,QACnC,KAAK,OAAO,KAAK,KAAK,CAAC,GAAG,UAAU,MACtC;AACA,aAAK,YAAY;AACjB,aAAK,SAAS,KAAK,OAAM;MAC1B,OAAM;AACL,aAAK,YAAY;MAClB;IACF,OAAM;AACL,WAAK,YAAY;IAClB;AAGD,QAAI,KAAK,UAAU,MAAM;AACvB,WAAK,aAAa;IACnB,WAAU,KAAK,SAAS,KAAK,UAAU,KAAK,aAAa;AACxD,WAAK,aAAa;IACnB,OAAM;AACL,WAAK;IACN;AAED,QAAI,OAAO,OAAO;AAChB,WAAK;IACN;AAED,SAAK,QAAQ;AACb,SAAK,SAAS;;EAGhB,OAAI;AACF,UAAM,OAAO,KAAK;AAClB,UAAM,OAAO,KAAK,UAAS;AAC3B,QAAI,MAAM;AACR,YAAM,aAAa,IAAI,KAAK,MAAM,IAAI;AACtC,WAAK,kBAAkB,IAAI;AAC3B,aAAO;IACR;AACD,WAAO;;EAGD,YAAS;AACf,UAAM,MAAM,KAAK,SAAS,IAAG;AAC7B,QAAI,QAAQ,QAAW;AACrB,aAAO;IACR;AAED,SAAK,SAAS,KAAK,OAAM;AACzB,SAAK,SAAS,KAAK,aAAY;AAE/B,UAAM,OAAO,IAAI;AAEjB,SAAK,SAAS,IAAI;AAClB,SAAK,QAAQ,IAAI;AACjB,SAAK,YAAY,IAAI;AACrB,SAAK,YAAY,IAAI;AACrB,SAAK,aAAa,IAAI;AACtB,SAAK,cAAc,IAAI;AAEvB,SAAK,SAAS,KAAK,OAAM;AACzB,SAAK,SAAS,KAAK,aAAY;AAC/B,SAAK,SAAS;AAEd,UAAM,KAAK,KAAK;AAChB,UAAM,OAAO,UAAU,EAAE;AAEzB,QAAI,KAAK,QAAQ,KAAK,WAAW;AAC/B,aAAO;IACR;AAED,SAAK,WAAW,KAAK,IAAI,KAAK,IAAI;AAGlC,QAAI,KAAK,OAAO;AACd,WAAK,OAAO,KAAK,IAAI;AACrB,WAAK,KAAK,KAAK,MAAM,EAAE,MAAM,KAAK,OAAO,OAAO,GAAE,CAAE;IACrD;AAED,QAAI,KAAK,UAAU;AACjB,UAAI,KAAK,QAAQ,KAAK,YAAY;AAEhC,YAAI;AACJ,YAAI,OAAO,OAAO;AAChB,kBAAQ,KAAK,KAAK;QACnB,OAAM;AACL,kBAAQ,KAAK,KAAK;QACnB;AACD,aAAK,KAAK,OAAO,EAAE,MAAM,MAAM,OAAO,KAAI,CAAE;MAC7C,OAAM;AAEL,aAAK,KAAK,KAAK,IAAI,EAAE,MAAM,KAAK,UAAU,OAAO,KAAI,CAAE;MACxD;IACF;AAED,QAAI,KAAK,SAAS,KAAK,eAAe,KAAK,eAAe;AACxD,UAAI,YAAoB;AACxB,UAAI,KAAK,QAAQ,KAAK,cAAc;AAClC,qBAAa,KAAK,KAAK;AACvB,uBAAe,KAAK,KAAK;MAC1B,OAAM;AACL,qBAAa,KAAK,KAAK;AACvB,uBAAe,KAAK,KAAK;MAC1B;AACD,WAAK,WAAW,cAAc,UAAU;IACzC;AAED,WAAO;;EAGT,IAAI,EACF,UAAU,MACV,WAAW,EAAC,IAC+B,CAAA,GAAE;AAM7C,UAAM,SAAmB,CAAA;AACzB,QAAI,eAAe;AAGnB,eAAW,KAAK,KAAK,SAAS;AAQ5B,YAAM,YAAY,KAAK,QAAQ,CAAC;AAChC,UAAI;AAAW,eAAO,KAAK,IAAI,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,OAAO,OAAO;AAClE,qBAAe;IAChB;AAED,QAAI,gBAAgB,KAAK,SAAS,QAAQ;AACxC,aAAO,KAAK,OAAO;IACpB;AAED,UAAM,gBAAgB,CAACC,gBAAsB;AAC3C,YAAM,UAAU,KAAK,UAAU,KAAK,IAAG,CAAE;AACzC,UAAI,OAAO,YAAY,aAAa;AAClC,cAAM,YAAYA,YAAW,SAAS,IAAI,MAAM;AAChD,QAAAA,cAAa,GAAGA,WAAU,GAAG,SAAS,IAAI,OAAO;MAClD;AACD,aAAOA;IACT;AAGA,UAAM,kBAAkB,CAAA;AACxB,WAAO,KAAK,SAAS,SAAS,GAAG;AAC/B,sBAAgB,KAAK,KAAK,UAAS,CAAE;IACtC;AAED,UAAM,QAAQ,CAAA;AACd,QAAI,aAAa;AAGjB,QAAI,gBAAgB,WAAW,GAAG;AAChC,YAAM,KAAK,cAAc,EAAE,CAAC;IAC7B;AAGD,WAAO,gBAAgB,SAAS,GAAG;AACjC,mBAAa,cAAc,UAAU;AACrC,YAAM,OAAO,gBAAgB,IAAG;AAGhC,UAAI,CAAC,MAAM;AACT;MACD;AAGD,UAAI,CAAC,KAAK,SAAS,UAAU,KAAK,UAAU,KAAK;AAC/C,cAAM,SAAS,GAAG,KAAK,WAAW;AAElC,qBAAa,aAAa,GAAG,UAAU,IAAI,MAAM,KAAK;MACvD,WAAU,KAAK,UAAU,KAAK;AAE7B,YAAI,WAAW,QAAQ;AACrB,gBAAM,KAAK,UAAU;QACtB;AACD,qBAAa,KAAK,cAAc;MACjC;AAED,mBACE,aAAa,MAAM,KAAK,WAAW,MAAM,KAAK,OAAO,EAAE,OAAO,KAAI,CAAE,CAAC;AACvE,WAAK,UAAU,IAAI;IACpB;AAGD,QAAI,WAAW,QAAQ;AACrB,YAAM,KAAK,cAAc,UAAU,CAAC;IACrC;AAGD,UAAM,KAAK,KAAK,QAAQ,UAAU,GAAG;AAMrC,QAAI,aAAa,GAAG;AAClB,aAAO,OAAO,KAAK,EAAE,IAAI,MAAM,KAAK,GAAG;IACxC;AAGD,UAAM,QAAQ,WAAA;AACZ,UAAI,OAAO,SAAS,KAAK,OAAO,OAAO,SAAS,CAAC,MAAM,KAAK;AAC1D,eAAO,IAAG;AACV,eAAO;MACR;AACD,aAAO;IACT;AAGA,UAAM,cAAc,SAAU,OAAe,MAAY;AACvD,iBAAW,SAAS,KAAK,MAAM,GAAG,GAAG;AACnC,YAAI,CAAC,OAAO;AACV;QACD;AACD,YAAI,QAAQ,MAAM,SAAS,UAAU;AACnC,iBAAO,MAAK,GAAI;AACd;UACD;AACD,iBAAO,KAAK,OAAO;AACnB,kBAAQ;QACT;AACD,eAAO,KAAK,KAAK;AACjB,iBAAS,MAAM;AACf,eAAO,KAAK,GAAG;AACf;MACD;AACD,UAAI,MAAK,GAAI;AACX;MACD;AACD,aAAO;IACT;AAGA,QAAI,eAAe;AACnB,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAI,eAAe,MAAM,CAAC,EAAE,SAAS,UAAU;AAC7C,YAAI,MAAM,CAAC,EAAE,SAAS,GAAG,GAAG;AAC1B,yBAAe,YAAY,cAAc,MAAM,CAAC,CAAC;AACjD;QACD;MACF;AAED,UAAI,eAAe,MAAM,CAAC,EAAE,SAAS,YAAY,MAAM,GAAG;AAExD,YAAI,OAAO,OAAO,SAAS,CAAC,MAAM,KAAK;AACrC,iBAAO,IAAG;QACX;AAED,eAAO,KAAK,OAAO;AACnB,uBAAe;MAChB,WAAU,MAAM,GAAG;AAClB,eAAO,KAAK,GAAG;AACf;MACD;AACD,aAAO,KAAK,MAAM,CAAC,CAAC;AACpB,sBAAgB,MAAM,CAAC,EAAE;IAC1B;AAED,WAAO,OAAO,KAAK,EAAE;;;;;EAMvB,UAAU,MAAc;AACtB,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK,GAAG;AACvC,UAAI,OAAO,KAAK,CAAC,MAAM,YAAY,OAAO,KAAK,IAAI,CAAC,MAAM,UAAU;AAClE,aAAK,QAAQ,KAAK,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC;MACnC;IACF;AACD,WAAO,KAAK;;;EAId,UAAU,KAAa,OAAa;AAClC,SAAK,QAAQ,GAAG,IAAI,SAAS,iBAAiB,GAAG,KAAK;AACtD,WAAO,KAAK,WAAU;;EAGxB,aAAa,KAAW;AACtB,QAAI,OAAO,KAAK,SAAS;AACvB,WAAK,QAAQ,GAAG,IAAI,iBAAiB,GAAG,KAAK;AAC7C,aAAO;IACR;AACD,WAAO;;;EAIT,aAAU;AACR,UAAM,iBAAyC,CAAA;AAC/C,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,OAAO,GAAG;AACvD,UAAI,UAAU,MAAM;AAClB,uBAAe,GAAG,IAAI;MACvB;IACF;AACD,WAAO;;EAGT,QACEC,MACA,EACE,SAAS,OACT,cAAc,QAAO,IACyB,CAAA,GAAE;AAGlD,QAAI,gBAAgB,SAAS;AAC3B,MAAAA,OAAMA,KAAI,QAAQ,IAAI,OAAO,aAAa,GAAG,GAAG,IAAI;IACrD;AAED,UAAM,YAAYC,UAAMD,IAAG;AAG3B,SAAK,MAAK;AAGV,UAAM,UAAU,UAAU;AAC1B,QAAI,MAAM;AAEV,eAAW,OAAO,SAAS;AAEzB,UAAI,IAAI,YAAW,MAAO,OAAO;AAC/B,cAAM,QAAQ,GAAG;MAClB;AAED,WAAK,OAAO,KAAK,QAAQ,GAAG,CAAC;IAC9B;AAMD,QAAI,CAAC,QAAQ;AACX,UAAI,KAAK;AACP,aAAK,KAAK,KAAK,EAAE,iBAAiB,KAAI,CAAE;MACzC;IACF,OAAM;AAKL,UAAI,QAAQ,OAAO,MAAM,KAAK;AAC5B,YAAI,EAAE,SAAS,UAAU;AACvB,gBAAM,IAAI,MACR,sDAAsD;QAEzD;AAED,aAAK,KAAK,QAAQ,KAAK,GAAG,EAAE,iBAAiB,KAAI,CAAE;MACpD;IACF;AAED,QAAIE,QAAO,UAAU;AAErB,WAAOA,OAAM;AACX,UAAIA,MAAK,MAAM;AACb,cAAM,OAAO,KAAK,aAAaA,MAAK,MAAM,MAAM;AAEhD,YAAI,QAAQ,MAAM;AAChB,gBAAM,IAAI,MAAM,wBAAwBA,MAAK,IAAI,EAAE;QACpD,OAAM;AACL,eAAK,UAAU,IAAI;AACnB,eAAK,kBAAiB;QACvB;MACF;AAED,UAAIA,MAAK,YAAY,QAAW;AAC9B,aAAK,UAAU,KAAK,IAAG,CAAE,IAAIA,MAAK;MACnC;AAED,MAAAA,QAAOA,MAAK,WAAW,CAAC;IACzB;AAQD,UAAM,SAAS,UAAU;AACzB,QACE,UACA,OAAO,KAAK,KAAK,OAAO,EAAE,UAC1B,KAAK,QAAQ,QAAQ,MAAM,QAC3B;AACA,WAAK,UAAU,UAAU,MAAM;IAChC;;;;;;;;;;;;;EAeK,WAAW,MAAoB,OAAqB;AAC1D,QAAI,SAAS;AAEb,QAAI,KAAK,QAAQ,KAAK,cAAc;AAClC,eAAS;IACV,WAAU,KAAK,QAAQ,KAAK,cAAc;AACzC,eAAS;IACV,WAAU,KAAK,QAAQ,KAAK,WAAW;AACtC,aAAO;IACR,OAAM;AACL,UAAI,KAAK,UAAU,MAAM;AACvB,cAAM,gBAAgB,iBAAiB,MAAM,KAAK;AAClD,kBAAU,KAAK,MAAM,YAAW,IAAK;MACtC;AAED,UAAI,KAAK,SAAS,KAAK,UAAU,KAAK,aAAa;AACjD,YAAI,KAAK,UAAU,MAAM;AACvB,oBAAU,UAAU,KAAK,IAAI,EAAE,CAAC;QACjC;AACD,kBAAU;MACX;AAED,gBAAU,UAAU,KAAK,EAAE;AAE3B,UAAI,KAAK,WAAW;AAClB,kBAAU,MAAM,KAAK,UAAU,YAAW;MAC3C;IACF;AAED,SAAK,UAAU,IAAI;AACnB,QAAI,KAAK,QAAO,GAAI;AAClB,UAAI,KAAK,YAAW,GAAI;AACtB,kBAAU;MACX,OAAM;AACL,kBAAU;MACX;IACF;AACD,SAAK,UAAS;AAEd,WAAO;;;EAID,aAAa,MAAc,SAAS,OAAK;AAE/C,QAAI,YAAY,YAAY,IAAI;AAEhC,QAAI,CAAC,QAAQ;AACX,UAAI,cAAc,OAAO;AACvB,oBAAY;MACb,WAAU,cAAc,SAAS;AAChC,oBAAY;MACb;IACF;AAGD,QAAI,aAAa,cAAc;AAC7B,YAAM,MAAoB;QACxB,OAAO,KAAK;QACZ,MAAM;QACN,IAAI;QACJ,OAAO;QACP,OAAO,KAAK;;AAEd,aAAO;IACR;AAED,QAAI,YAAY,eAAe,SAAS;AACxC,QAAI,QAAQ,KAAK,OAAO,EAAE,OAAO,MAAM,OAAO,UAAS,CAAE;AAGzD,aAAS,IAAI,GAAG,MAAM,MAAM,QAAQ,IAAI,KAAK,KAAK;AAChD,UAAI,cAAc,YAAY,KAAK,WAAW,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG;AAC/D,eAAO,MAAM,CAAC;MACf;IACF;AAGD,QAAI,QAAQ;AACV,aAAO;IACR;AAED,QAAI,QAAQ;AACZ,QAAI,UAAU;AACd,QAAI,OAAO;AACX,QAAI,KAAK;AACT,QAAI,YAAY;AAmBhB,QAAI,sBAAsB;AAE1B,cAAU,UAAU,MAClB,4DAA4D;AAI9D,QAAI,SAAS;AACX,cAAQ,QAAQ,CAAC;AACjB,aAAO,QAAQ,CAAC;AAChB,WAAK,QAAQ,CAAC;AACd,kBAAY,QAAQ,CAAC;AAErB,UAAI,KAAK,UAAU,GAAG;AACpB,8BAAsB;MACvB;IACF,OAAM;AAQL,gBAAU,UAAU,MAClB,8DAA8D;AAGhE,UAAI,SAAS;AACX,gBAAQ,QAAQ,CAAC;AACjB,eAAO,QAAQ,CAAC;AAChB,aAAK,QAAQ,CAAC;AACd,oBAAY,QAAQ,CAAC;AAErB,YAAI,KAAK,UAAU,GAAG;AACpB,gCAAsB;QACvB;MACF;IACF;AAED,gBAAY,eAAe,SAAS;AACpC,YAAQ,KAAK,OAAO;MAClB,OAAO;MACP,OAAO,QAAS,QAAwB;IACzC,CAAA;AAED,QAAI,CAAC,IAAI;AACP,aAAO;IACR;AAED,aAAS,IAAI,GAAG,MAAM,MAAM,QAAQ,IAAI,KAAK,KAAK;AAChD,UAAI,CAAC,MAAM;AAET,YACE,cACA,YAAY,KAAK,WAAW,MAAM,CAAC,GAAG,KAAK,CAAC,EAAE,QAAQ,KAAK,EAAE,GAC7D;AACA,iBAAO,MAAM,CAAC;QACf;MAEF,YACE,CAAC,SAAS,MAAM,YAAW,KAAM,MAAM,CAAC,EAAE,UAC3C,KAAK,IAAI,KAAK,MAAM,CAAC,EAAE,QACvB,KAAK,EAAE,KAAK,MAAM,CAAC,EAAE,OACpB,CAAC,aAAa,UAAU,YAAW,KAAM,MAAM,CAAC,EAAE,YACnD;AACA,eAAO,MAAM,CAAC;MACf,WAAU,qBAAqB;AAM9B,cAAM,SAAS,UAAU,MAAM,CAAC,EAAE,IAAI;AACtC,aACG,CAAC,SAAS,MAAM,YAAW,KAAM,MAAM,CAAC,EAAE,UAC3C,KAAK,EAAE,KAAK,MAAM,CAAC,EAAE,OACpB,QAAQ,OAAO,CAAC,KAAK,QAAQ,OAAO,CAAC,OACrC,CAAC,aAAa,UAAU,YAAW,KAAM,MAAM,CAAC,EAAE,YACnD;AACA,iBAAO,MAAM,CAAC;QACf;MACF;IACF;AAED,WAAO;;EAGT,QAAK;AACH,QAAI,IAAI;AACR,aAAS,IAAI,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK;AAEvC,UAAI,KAAK,CAAC,MAAM,GAAG;AACjB,aAAK,MAAM,WAAW,KAAK,CAAC,CAAC,IAAI;MAClC;AAED,UAAI,KAAK,OAAO,CAAC,GAAG;AAClB,cAAM,QAAQ,KAAK,OAAO,CAAC,EAAE;AAC7B,cAAM,QAAQ,KAAK,OAAO,CAAC,EAAE;AAC7B,cAAM,SACJ,UAAU,QAAQ,MAAM,YAAW,IAAK,MAAM,YAAW;AAC3D,aAAK,MAAM,SAAS;MACrB,OAAM;AACL,aAAK;MACN;AAED,UAAK,IAAI,IAAK,KAAM;AAClB,aAAK;AACL,aAAK;MACN;IACF;AACD,SAAK;AACL,SAAK;AAEL,WAAO;;EAGT,MAAM,OAAa;AACjB,UAAM,QAAQ,KAAK,OAAO,EAAE,OAAO,MAAK,CAAE;AAC1C,QAAI,QAAQ;AACZ,UAAM,QAAQ,KAAK;AAEnB,aAAS,IAAI,GAAG,MAAM,MAAM,QAAQ,IAAI,KAAK,KAAK;AAChD,WAAK,UAAU,MAAM,CAAC,CAAC;AACvB,UAAI,CAAC,KAAK,gBAAgB,KAAK,GAAG;AAChC,YAAI,QAAQ,IAAI,GAAG;AACjB,mBAAS,KAAK,MAAM,QAAQ,CAAC;QAC9B,OAAM;AACL;QACD;MACF;AACD,WAAK,UAAS;IACf;AAED,WAAO;;EAGT,QAAQ,OAAY;AAClB,QAAI,KAAK,SAAS,OAAO;AACvB,aAAO;IACR;AAED,SAAK,KAAK,IAAI;AACd,WAAO;;EAGT,OAAI;AACF,WAAO,KAAK;;EAGd,QAAK;AACH,UAAM,SAAS,CAAA;AACf,QAAI,MAAM,CAAA;AAEV,aAAS,IAAI,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK;AACvC,UAAI,KAAK,OAAO,CAAC,KAAK,MAAM;AAC1B,YAAI,KAAK,IAAI;MACd,OAAM;AACL,YAAI,KAAK;UACP,QAAQ,UAAU,CAAC;UACnB,MAAM,KAAK,OAAO,CAAC,EAAE;UACrB,OAAO,KAAK,OAAO,CAAC,EAAE;QACvB,CAAA;MACF;AACD,UAAK,IAAI,IAAK,KAAM;AAClB,eAAO,KAAK,GAAG;AACf,cAAM,CAAA;AACN,aAAK;MACN;IACF;AAED,WAAO;;EAGT,YAAY,QAAc;AACxB,QAAI,UAAU,MAAM;AAClB,YAAM,KAAK,KAAK,MAAM;AACtB,cAAQ,KAAK,EAAE,IAAI,KAAK,EAAE,KAAK,MAAM,IAAI,UAAU;IACpD;AAED,WAAO;;EAOT,QAAQ,EAAE,UAAU,MAAK,IAA4B,CAAA,GAAE;AACrD,UAAM,kBAAkB,CAAA;AACxB,UAAM,cAAc,CAAA;AAEpB,WAAO,KAAK,SAAS,SAAS,GAAG;AAC/B,sBAAgB,KAAK,KAAK,UAAS,CAAE;IACtC;AAED,WAAO,MAAM;AACX,YAAM,OAAO,gBAAgB,IAAG;AAChC,UAAI,CAAC,MAAM;AACT;MACD;AAED,UAAI,SAAS;AACX,oBAAY,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;MACtC,OAAM;AACL,oBAAY,KAAK,KAAK,WAAW,MAAM,KAAK,OAAM,CAAE,CAAC;MACtD;AACD,WAAK,UAAU,IAAI;IACpB;AAED,WAAO;;;;;;EAOD,kBAAkB,MAAY;AACpC,WAAO,KAAK,eAAe,IAAI,IAAI,KAAK;;EAGlC,oBAAiB;AACvB,SAAK,eAAe,IAClB,KAAK,QACJ,KAAK,eAAe,IAAI,KAAK,KAAK,KAAK,KAAK,CAAC;;EAI1C,kBAAkB,MAAY;AACpC,UAAM,eAAe,KAAK,eAAe,IAAI,IAAI,KAAK;AAEtD,QAAI,iBAAiB,GAAG;AACtB,WAAK,eAAe,OAAO,IAAI;IAChC,OAAM;AACL,WAAK,eAAe,IAAI,MAAM,eAAe,CAAC;IAC/C;;EAGK,iBAAc;AACpB,UAAM,kBAAkB,CAAA;AACxB,UAAM,kBAA0C,CAAA;AAEhD,UAAM,cAAc,CAAC,QAAe;AAClC,UAAI,OAAO,KAAK,WAAW;AACzB,wBAAgB,GAAG,IAAI,KAAK,UAAU,GAAG;MAC1C;IACH;AAEA,WAAO,KAAK,SAAS,SAAS,GAAG;AAC/B,sBAAgB,KAAK,KAAK,UAAS,CAAE;IACtC;AAED,gBAAY,KAAK,IAAG,CAAE;AAEtB,WAAO,MAAM;AACX,YAAM,OAAO,gBAAgB,IAAG;AAChC,UAAI,CAAC,MAAM;AACT;MACD;AACD,WAAK,UAAU,IAAI;AACnB,kBAAY,KAAK,IAAG,CAAE;IACvB;AACD,SAAK,YAAY;;EAGnB,aAAU;AACR,WAAO,KAAK,UAAU,KAAK,IAAG,CAAE;;EAGlC,WAAW,SAAe;AACxB,SAAK,UAAU,KAAK,IAAG,CAAE,IAAI,QAAQ,QAAQ,KAAK,GAAG,EAAE,QAAQ,KAAK,GAAG;;;;;EAMzE,gBAAa;AACX,WAAO,KAAK,cAAa;;EAG3B,gBAAa;AACX,UAAM,UAAU,KAAK,UAAU,KAAK,IAAG,CAAE;AACzC,WAAO,KAAK,UAAU,KAAK,IAAG,CAAE;AAChC,WAAO;;EAGT,cAAW;AACT,SAAK,eAAc;AACnB,WAAO,OAAO,KAAK,KAAK,SAAS,EAAE,IAAI,CAAC,QAAe;AACrD,aAAO,EAAE,KAAU,SAAS,KAAK,UAAU,GAAG,EAAC;IACjD,CAAC;;;;;EAMH,iBAAc;AACZ,WAAO,KAAK,eAAc;;EAG5B,iBAAc;AACZ,SAAK,eAAc;AACnB,WAAO,OAAO,KAAK,KAAK,SAAS,EAAE,IAAI,CAAC,QAAO;AAC7C,YAAM,UAAU,KAAK,UAAU,GAAG;AAClC,aAAO,KAAK,UAAU,GAAG;AACzB,aAAO,EAAE,KAAU,QAAgB;IACrC,CAAC;;EAGH,kBACE,OACA,QAA4D;AAE5D,eAAW,QAAQ,CAAC,MAAM,KAAK,GAAY;AACzC,UAAI,OAAO,IAAI,MAAM,QAAW;AAC9B,YAAI,OAAO,IAAI,GAAG;AAChB,eAAK,UAAU,KAAK,KAAK,MAAM,IAAI;QACpC,OAAM;AACL,eAAK,UAAU,KAAK,KAAK,CAAC,MAAM,IAAI;QACrC;MACF;IACF;AAED,SAAK,sBAAqB;AAC1B,UAAM,SAAS,KAAK,kBAAkB,KAAK;AAE3C,YACG,OAAO,IAAI,MAAM,UAAa,OAAO,IAAI,MAAM,OAAO,IAAI,OAC1D,OAAO,KAAK,MAAM,UAAa,OAAO,KAAK,MAAM,OAAO,KAAK;;EAIlE,kBAAkB,OAAY;AAC5B,WAAO;MACL,CAAC,IAAI,IAAI,KAAK,UAAU,KAAK,IAAI,MAAM,IAAI,OAAO;MAClD,CAAC,KAAK,IAAI,KAAK,UAAU,KAAK,IAAI,MAAM,KAAK,OAAO;;;EAIxD,aAAU;AACR,WAAO,KAAK;;AAEf;;;ACroFD,IAAM,QAAQ,IAAI,MAAM;AACxB,IAAM,aAAa,MAAM,MAAM,EAAE,SAAS,KAAK,CAAC;AAEhD,IAAO,sBAAQ,WAAW;AAAA,EACxB,CAAC,SAAS,KAAK,SAAS,QAAQ,KAAK,OAAO;AAC9C;\",\"names\":[\"node\",\"expected\",\"found\",\"chess\",\"legalMoves\",\"moveString\",\"pgn\",\"parse\",\"node\"],\"sources\":[\"../node_modules/.pnpm/chess.js@1.4.0/node_modules/chess.js/src/pgn.js\",\"../node_modules/.pnpm/chess.js@1.4.0/node_modules/src/chess.ts\",\"../libs/test-harness/fixtures/library-reuse/chess-entry.ts\"],\"sourcesContent\":[\"// @generated by Peggy 4.2.0.\\n//\\n// https://peggyjs.org/\\n\\n\\n\\n function rootNode(comment) {\\n \\treturn comment !== null ? { comment, variations: [] } : { variations: []}\\n }\\n\\n function node(move, suffix, nag, comment, variations) {\\n \\tconst node = { move, variations }\\n\\n if (suffix) {\\n \\tnode.suffix = suffix\\n }\\n\\n if (nag) {\\n \\tnode.nag = nag\\n }\\n\\n if (comment !== null) {\\n \\tnode.comment = comment\\n }\\n\\n return node\\n }\\n\\n function lineToTree(...nodes) {\\n \\tconst [root, ...rest] = nodes;\\n\\n let parent = root\\n\\n for (const child of rest) {\\n \\tif (child !== null) {\\n \\tparent.variations = [child, ...child.variations]\\n child.variations = []\\n parent = child\\n }\\n }\\n\\n \\treturn root\\n }\\n\\n function pgn(headers, game) {\\n \\tif (game.marker && game.marker.comment) {\\n \\tlet node = game.root\\n while (true) {\\n \\tconst next = node.variations[0]\\n if (!next) {\\n \\tnode.comment = game.marker.comment\\n \\tbreak\\n }\\n node = next\\n }\\n }\\n\\n \\treturn {\\n \\theaders,\\n root: game.root,\\n result: (game.marker && game.marker.result) ?? undefined\\n }\\n }\\n\\nfunction peg$subclass(child, parent) {\\n function C() { this.constructor = child; }\\n C.prototype = parent.prototype;\\n child.prototype = new C();\\n}\\n\\nfunction peg$SyntaxError(message, expected, found, location) {\\n var self = Error.call(this, message);\\n // istanbul ignore next Check is a necessary evil to support older environments\\n if (Object.setPrototypeOf) {\\n Object.setPrototypeOf(self, peg$SyntaxError.prototype);\\n }\\n self.expected = expected;\\n self.found = found;\\n self.location = location;\\n self.name = \\\"SyntaxError\\\";\\n return self;\\n}\\n\\npeg$subclass(peg$SyntaxError, Error);\\n\\nfunction peg$padEnd(str, targetLength, padString) {\\n padString = padString || \\\" \\\";\\n if (str.length > targetLength) { return str; }\\n targetLength -= str.length;\\n padString += padString.repeat(targetLength);\\n return str + padString.slice(0, targetLength);\\n}\\n\\npeg$SyntaxError.prototype.format = function(sources) {\\n var str = \\\"Error: \\\" + this.message;\\n if (this.location) {\\n var src = null;\\n var k;\\n for (k = 0; k < sources.length; k++) {\\n if (sources[k].source === this.location.source) {\\n src = sources[k].text.split(/\\\\r\\\\n|\\\\n|\\\\r/g);\\n break;\\n }\\n }\\n var s = this.location.start;\\n var offset_s = (this.location.source && (typeof this.location.source.offset === \\\"function\\\"))\\n ? this.location.source.offset(s)\\n : s;\\n var loc = this.location.source + \\\":\\\" + offset_s.line + \\\":\\\" + offset_s.column;\\n if (src) {\\n var e = this.location.end;\\n var filler = peg$padEnd(\\\"\\\", offset_s.line.toString().length, ' ');\\n var line = src[s.line - 1];\\n var last = s.line === e.line ? e.column : line.length + 1;\\n var hatLen = (last - s.column) || 1;\\n str += \\\"\\\\n --> \\\" + loc + \\\"\\\\n\\\"\\n + filler + \\\" |\\\\n\\\"\\n + offset_s.line + \\\" | \\\" + line + \\\"\\\\n\\\"\\n + filler + \\\" | \\\" + peg$padEnd(\\\"\\\", s.column - 1, ' ')\\n + peg$padEnd(\\\"\\\", hatLen, \\\"^\\\");\\n } else {\\n str += \\\"\\\\n at \\\" + loc;\\n }\\n }\\n return str;\\n};\\n\\npeg$SyntaxError.buildMessage = function(expected, found) {\\n var DESCRIBE_EXPECTATION_FNS = {\\n literal: function(expectation) {\\n return \\\"\\\\\\\"\\\" + literalEscape(expectation.text) + \\\"\\\\\\\"\\\";\\n },\\n\\n class: function(expectation) {\\n var escapedParts = expectation.parts.map(function(part) {\\n return Array.isArray(part)\\n ? classEscape(part[0]) + \\\"-\\\" + classEscape(part[1])\\n : classEscape(part);\\n });\\n\\n return \\\"[\\\" + (expectation.inverted ? \\\"^\\\" : \\\"\\\") + escapedParts.join(\\\"\\\") + \\\"]\\\";\\n },\\n\\n any: function() {\\n return \\\"any character\\\";\\n },\\n\\n end: function() {\\n return \\\"end of input\\\";\\n },\\n\\n other: function(expectation) {\\n return expectation.description;\\n }\\n };\\n\\n function hex(ch) {\\n return ch.charCodeAt(0).toString(16).toUpperCase();\\n }\\n\\n function literalEscape(s) {\\n return s\\n .replace(/\\\\\\\\/g, \\\"\\\\\\\\\\\\\\\\\\\")\\n .replace(/\\\"/g, \\\"\\\\\\\\\\\\\\\"\\\")\\n .replace(/\\\\0/g, \\\"\\\\\\\\0\\\")\\n .replace(/\\\\t/g, \\\"\\\\\\\\t\\\")\\n .replace(/\\\\n/g, \\\"\\\\\\\\n\\\")\\n .replace(/\\\\r/g, \\\"\\\\\\\\r\\\")\\n .replace(/[\\\\x00-\\\\x0F]/g, function(ch) { return \\\"\\\\\\\\x0\\\" + hex(ch); })\\n .replace(/[\\\\x10-\\\\x1F\\\\x7F-\\\\x9F]/g, function(ch) { return \\\"\\\\\\\\x\\\" + hex(ch); });\\n }\\n\\n function classEscape(s) {\\n return s\\n .replace(/\\\\\\\\/g, \\\"\\\\\\\\\\\\\\\\\\\")\\n .replace(/\\\\]/g, \\\"\\\\\\\\]\\\")\\n .replace(/\\\\^/g, \\\"\\\\\\\\^\\\")\\n .replace(/-/g, \\\"\\\\\\\\-\\\")\\n .replace(/\\\\0/g, \\\"\\\\\\\\0\\\")\\n .replace(/\\\\t/g, \\\"\\\\\\\\t\\\")\\n .replace(/\\\\n/g, \\\"\\\\\\\\n\\\")\\n .replace(/\\\\r/g, \\\"\\\\\\\\r\\\")\\n .replace(/[\\\\x00-\\\\x0F]/g, function(ch) { return \\\"\\\\\\\\x0\\\" + hex(ch); })\\n .replace(/[\\\\x10-\\\\x1F\\\\x7F-\\\\x9F]/g, function(ch) { return \\\"\\\\\\\\x\\\" + hex(ch); });\\n }\\n\\n function describeExpectation(expectation) {\\n return DESCRIBE_EXPECTATION_FNS[expectation.type](expectation);\\n }\\n\\n function describeExpected(expected) {\\n var descriptions = expected.map(describeExpectation);\\n var i, j;\\n\\n descriptions.sort();\\n\\n if (descriptions.length > 0) {\\n for (i = 1, j = 1; i < descriptions.length; i++) {\\n if (descriptions[i - 1] !== descriptions[i]) {\\n descriptions[j] = descriptions[i];\\n j++;\\n }\\n }\\n descriptions.length = j;\\n }\\n\\n switch (descriptions.length) {\\n case 1:\\n return descriptions[0];\\n\\n case 2:\\n return descriptions[0] + \\\" or \\\" + descriptions[1];\\n\\n default:\\n return descriptions.slice(0, -1).join(\\\", \\\")\\n + \\\", or \\\"\\n + descriptions[descriptions.length - 1];\\n }\\n }\\n\\n function describeFound(found) {\\n return found ? \\\"\\\\\\\"\\\" + literalEscape(found) + \\\"\\\\\\\"\\\" : \\\"end of input\\\";\\n }\\n\\n return \\\"Expected \\\" + describeExpected(expected) + \\\" but \\\" + describeFound(found) + \\\" found.\\\";\\n};\\n\\nfunction peg$parse(input, options) {\\n options = options !== undefined ? options : {};\\n\\n var peg$FAILED = {};\\n var peg$source = options.grammarSource;\\n\\n var peg$startRuleFunctions = { pgn: peg$parsepgn };\\n var peg$startRuleFunction = peg$parsepgn;\\n\\n var peg$c0 = \\\"[\\\";\\n var peg$c1 = \\\"\\\\\\\"\\\";\\n var peg$c2 = \\\"]\\\";\\n var peg$c3 = \\\".\\\";\\n var peg$c4 = \\\"O-O-O\\\";\\n var peg$c5 = \\\"O-O\\\";\\n var peg$c6 = \\\"0-0-0\\\";\\n var peg$c7 = \\\"0-0\\\";\\n var peg$c8 = \\\"$\\\";\\n var peg$c9 = \\\"{\\\";\\n var peg$c10 = \\\"}\\\";\\n var peg$c11 = \\\";\\\";\\n var peg$c12 = \\\"(\\\";\\n var peg$c13 = \\\")\\\";\\n var peg$c14 = \\\"1-0\\\";\\n var peg$c15 = \\\"0-1\\\";\\n var peg$c16 = \\\"1/2-1/2\\\";\\n var peg$c17 = \\\"*\\\";\\n\\n var peg$r0 = /^[a-zA-Z]/;\\n var peg$r1 = /^[^\\\"]/;\\n var peg$r2 = /^[0-9]/;\\n var peg$r3 = /^[.]/;\\n var peg$r4 = /^[a-zA-Z1-8\\\\-=]/;\\n var peg$r5 = /^[+#]/;\\n var peg$r6 = /^[!?]/;\\n var peg$r7 = /^[^}]/;\\n var peg$r8 = /^[^\\\\r\\\\n]/;\\n var peg$r9 = /^[ \\\\t\\\\r\\\\n]/;\\n\\n var peg$e0 = peg$otherExpectation(\\\"tag pair\\\");\\n var peg$e1 = peg$literalExpectation(\\\"[\\\", false);\\n var peg$e2 = peg$literalExpectation(\\\"\\\\\\\"\\\", false);\\n var peg$e3 = peg$literalExpectation(\\\"]\\\", false);\\n var peg$e4 = peg$otherExpectation(\\\"tag name\\\");\\n var peg$e5 = peg$classExpectation([[\\\"a\\\", \\\"z\\\"], [\\\"A\\\", \\\"Z\\\"]], false, false);\\n var peg$e6 = peg$otherExpectation(\\\"tag value\\\");\\n var peg$e7 = peg$classExpectation([\\\"\\\\\\\"\\\"], true, false);\\n var peg$e8 = peg$otherExpectation(\\\"move number\\\");\\n var peg$e9 = peg$classExpectation([[\\\"0\\\", \\\"9\\\"]], false, false);\\n var peg$e10 = peg$literalExpectation(\\\".\\\", false);\\n var peg$e11 = peg$classExpectation([\\\".\\\"], false, false);\\n var peg$e12 = peg$otherExpectation(\\\"standard algebraic notation\\\");\\n var peg$e13 = peg$literalExpectation(\\\"O-O-O\\\", false);\\n var peg$e14 = peg$literalExpectation(\\\"O-O\\\", false);\\n var peg$e15 = peg$literalExpectation(\\\"0-0-0\\\", false);\\n var peg$e16 = peg$literalExpectation(\\\"0-0\\\", false);\\n var peg$e17 = peg$classExpectation([[\\\"a\\\", \\\"z\\\"], [\\\"A\\\", \\\"Z\\\"], [\\\"1\\\", \\\"8\\\"], \\\"-\\\", \\\"=\\\"], false, false);\\n var peg$e18 = peg$classExpectation([\\\"+\\\", \\\"#\\\"], false, false);\\n var peg$e19 = peg$otherExpectation(\\\"suffix annotation\\\");\\n var peg$e20 = peg$classExpectation([\\\"!\\\", \\\"?\\\"], false, false);\\n var peg$e21 = peg$otherExpectation(\\\"NAG\\\");\\n var peg$e22 = peg$literalExpectation(\\\"$\\\", false);\\n var peg$e23 = peg$otherExpectation(\\\"brace comment\\\");\\n var peg$e24 = peg$literalExpectation(\\\"{\\\", false);\\n var peg$e25 = peg$classExpectation([\\\"}\\\"], true, false);\\n var peg$e26 = peg$literalExpectation(\\\"}\\\", false);\\n var peg$e27 = peg$otherExpectation(\\\"rest of line comment\\\");\\n var peg$e28 = peg$literalExpectation(\\\";\\\", false);\\n var peg$e29 = peg$classExpectation([\\\"\\\\r\\\", \\\"\\\\n\\\"], true, false);\\n var peg$e30 = peg$otherExpectation(\\\"variation\\\");\\n var peg$e31 = peg$literalExpectation(\\\"(\\\", false);\\n var peg$e32 = peg$literalExpectation(\\\")\\\", false);\\n var peg$e33 = peg$otherExpectation(\\\"game termination marker\\\");\\n var peg$e34 = peg$literalExpectation(\\\"1-0\\\", false);\\n var peg$e35 = peg$literalExpectation(\\\"0-1\\\", false);\\n var peg$e36 = peg$literalExpectation(\\\"1/2-1/2\\\", false);\\n var peg$e37 = peg$literalExpectation(\\\"*\\\", false);\\n var peg$e38 = peg$otherExpectation(\\\"whitespace\\\");\\n var peg$e39 = peg$classExpectation([\\\" \\\", \\\"\\\\t\\\", \\\"\\\\r\\\", \\\"\\\\n\\\"], false, false);\\n\\n var peg$f0 = function(headers, game) { return pgn(headers, game) };\\n var peg$f1 = function(tagPairs) { return Object.fromEntries(tagPairs) };\\n var peg$f2 = function(tagName, tagValue) { return [tagName, tagValue] };\\n var peg$f3 = function(root, marker) { return { root, marker} };\\n var peg$f4 = function(comment, moves) { return lineToTree(rootNode(comment), ...moves.flat()) };\\n var peg$f5 = function(san, suffix, nag, comment, variations) { return node(san, suffix, nag, comment, variations) };\\n var peg$f6 = function(nag) { return nag };\\n var peg$f7 = function(comment) { return comment.replace(/[\\\\r\\\\n]+/g, \\\" \\\") };\\n var peg$f8 = function(comment) { return comment.trim() };\\n var peg$f9 = function(line) { return line };\\n var peg$f10 = function(result, comment) { return { result, comment } };\\n var peg$currPos = options.peg$currPos | 0;\\n var peg$savedPos = peg$currPos;\\n var peg$posDetailsCache = [{ line: 1, column: 1 }];\\n var peg$maxFailPos = peg$currPos;\\n var peg$maxFailExpected = options.peg$maxFailExpected || [];\\n var peg$silentFails = options.peg$silentFails | 0;\\n\\n var peg$result;\\n\\n if (options.startRule) {\\n if (!(options.startRule in peg$startRuleFunctions)) {\\n throw new Error(\\\"Can't start parsing from rule \\\\\\\"\\\" + options.startRule + \\\"\\\\\\\".\\\");\\n }\\n\\n peg$startRuleFunction = peg$startRuleFunctions[options.startRule];\\n }\\n\\n function text() {\\n return input.substring(peg$savedPos, peg$currPos);\\n }\\n\\n function offset() {\\n return peg$savedPos;\\n }\\n\\n function range() {\\n return {\\n source: peg$source,\\n start: peg$savedPos,\\n end: peg$currPos\\n };\\n }\\n\\n function location() {\\n return peg$computeLocation(peg$savedPos, peg$currPos);\\n }\\n\\n function expected(description, location) {\\n location = location !== undefined\\n ? location\\n : peg$computeLocation(peg$savedPos, peg$currPos);\\n\\n throw peg$buildStructuredError(\\n [peg$otherExpectation(description)],\\n input.substring(peg$savedPos, peg$currPos),\\n location\\n );\\n }\\n\\n function error(message, location) {\\n location = location !== undefined\\n ? location\\n : peg$computeLocation(peg$savedPos, peg$currPos);\\n\\n throw peg$buildSimpleError(message, location);\\n }\\n\\n function peg$literalExpectation(text, ignoreCase) {\\n return { type: \\\"literal\\\", text: text, ignoreCase: ignoreCase };\\n }\\n\\n function peg$classExpectation(parts, inverted, ignoreCase) {\\n return { type: \\\"class\\\", parts: parts, inverted: inverted, ignoreCase: ignoreCase };\\n }\\n\\n function peg$anyExpectation() {\\n return { type: \\\"any\\\" };\\n }\\n\\n function peg$endExpectation() {\\n return { type: \\\"end\\\" };\\n }\\n\\n function peg$otherExpectation(description) {\\n return { type: \\\"other\\\", description: description };\\n }\\n\\n function peg$computePosDetails(pos) {\\n var details = peg$posDetailsCache[pos];\\n var p;\\n\\n if (details) {\\n return details;\\n } else {\\n if (pos >= peg$posDetailsCache.length) {\\n p = peg$posDetailsCache.length - 1;\\n } else {\\n p = pos;\\n while (!peg$posDetailsCache[--p]) {}\\n }\\n\\n details = peg$posDetailsCache[p];\\n details = {\\n line: details.line,\\n column: details.column\\n };\\n\\n while (p < pos) {\\n if (input.charCodeAt(p) === 10) {\\n details.line++;\\n details.column = 1;\\n } else {\\n details.column++;\\n }\\n\\n p++;\\n }\\n\\n peg$posDetailsCache[pos] = details;\\n\\n return details;\\n }\\n }\\n\\n function peg$computeLocation(startPos, endPos, offset) {\\n var startPosDetails = peg$computePosDetails(startPos);\\n var endPosDetails = peg$computePosDetails(endPos);\\n\\n var res = {\\n source: peg$source,\\n start: {\\n offset: startPos,\\n line: startPosDetails.line,\\n column: startPosDetails.column\\n },\\n end: {\\n offset: endPos,\\n line: endPosDetails.line,\\n column: endPosDetails.column\\n }\\n };\\n if (offset && peg$source && (typeof peg$source.offset === \\\"function\\\")) {\\n res.start = peg$source.offset(res.start);\\n res.end = peg$source.offset(res.end);\\n }\\n return res;\\n }\\n\\n function peg$fail(expected) {\\n if (peg$currPos < peg$maxFailPos) { return; }\\n\\n if (peg$currPos > peg$maxFailPos) {\\n peg$maxFailPos = peg$currPos;\\n peg$maxFailExpected = [];\\n }\\n\\n peg$maxFailExpected.push(expected);\\n }\\n\\n function peg$buildSimpleError(message, location) {\\n return new peg$SyntaxError(message, null, null, location);\\n }\\n\\n function peg$buildStructuredError(expected, found, location) {\\n return new peg$SyntaxError(\\n peg$SyntaxError.buildMessage(expected, found),\\n expected,\\n found,\\n location\\n );\\n }\\n\\n function peg$parsepgn() {\\n var s0, s1, s2;\\n\\n s0 = peg$currPos;\\n s1 = peg$parsetagPairSection();\\n s2 = peg$parsemoveTextSection();\\n peg$savedPos = s0;\\n s0 = peg$f0(s1, s2);\\n\\n return s0;\\n }\\n\\n function peg$parsetagPairSection() {\\n var s0, s1, s2;\\n\\n s0 = peg$currPos;\\n s1 = [];\\n s2 = peg$parsetagPair();\\n while (s2 !== peg$FAILED) {\\n s1.push(s2);\\n s2 = peg$parsetagPair();\\n }\\n s2 = peg$parse_();\\n peg$savedPos = s0;\\n s0 = peg$f1(s1);\\n\\n return s0;\\n }\\n\\n function peg$parsetagPair() {\\n var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10;\\n\\n peg$silentFails++;\\n s0 = peg$currPos;\\n s1 = peg$parse_();\\n if (input.charCodeAt(peg$currPos) === 91) {\\n s2 = peg$c0;\\n peg$currPos++;\\n } else {\\n s2 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e1); }\\n }\\n if (s2 !== peg$FAILED) {\\n s3 = peg$parse_();\\n s4 = peg$parsetagName();\\n if (s4 !== peg$FAILED) {\\n s5 = peg$parse_();\\n if (input.charCodeAt(peg$currPos) === 34) {\\n s6 = peg$c1;\\n peg$currPos++;\\n } else {\\n s6 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e2); }\\n }\\n if (s6 !== peg$FAILED) {\\n s7 = peg$parsetagValue();\\n if (input.charCodeAt(peg$currPos) === 34) {\\n s8 = peg$c1;\\n peg$currPos++;\\n } else {\\n s8 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e2); }\\n }\\n if (s8 !== peg$FAILED) {\\n s9 = peg$parse_();\\n if (input.charCodeAt(peg$currPos) === 93) {\\n s10 = peg$c2;\\n peg$currPos++;\\n } else {\\n s10 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e3); }\\n }\\n if (s10 !== peg$FAILED) {\\n peg$savedPos = s0;\\n s0 = peg$f2(s4, s7);\\n } else {\\n peg$currPos = s0;\\n s0 = peg$FAILED;\\n }\\n } else {\\n peg$currPos = s0;\\n s0 = peg$FAILED;\\n }\\n } else {\\n peg$currPos = s0;\\n s0 = peg$FAILED;\\n }\\n } else {\\n peg$currPos = s0;\\n s0 = peg$FAILED;\\n }\\n } else {\\n peg$currPos = s0;\\n s0 = peg$FAILED;\\n }\\n peg$silentFails--;\\n if (s0 === peg$FAILED) {\\n s1 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e0); }\\n }\\n\\n return s0;\\n }\\n\\n function peg$parsetagName() {\\n var s0, s1, s2;\\n\\n peg$silentFails++;\\n s0 = peg$currPos;\\n s1 = [];\\n s2 = input.charAt(peg$currPos);\\n if (peg$r0.test(s2)) {\\n peg$currPos++;\\n } else {\\n s2 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e5); }\\n }\\n if (s2 !== peg$FAILED) {\\n while (s2 !== peg$FAILED) {\\n s1.push(s2);\\n s2 = input.charAt(peg$currPos);\\n if (peg$r0.test(s2)) {\\n peg$currPos++;\\n } else {\\n s2 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e5); }\\n }\\n }\\n } else {\\n s1 = peg$FAILED;\\n }\\n if (s1 !== peg$FAILED) {\\n s0 = input.substring(s0, peg$currPos);\\n } else {\\n s0 = s1;\\n }\\n peg$silentFails--;\\n if (s0 === peg$FAILED) {\\n s1 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e4); }\\n }\\n\\n return s0;\\n }\\n\\n function peg$parsetagValue() {\\n var s0, s1, s2;\\n\\n peg$silentFails++;\\n s0 = peg$currPos;\\n s1 = [];\\n s2 = input.charAt(peg$currPos);\\n if (peg$r1.test(s2)) {\\n peg$currPos++;\\n } else {\\n s2 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e7); }\\n }\\n while (s2 !== peg$FAILED) {\\n s1.push(s2);\\n s2 = input.charAt(peg$currPos);\\n if (peg$r1.test(s2)) {\\n peg$currPos++;\\n } else {\\n s2 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e7); }\\n }\\n }\\n s0 = input.substring(s0, peg$currPos);\\n peg$silentFails--;\\n s1 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e6); }\\n\\n return s0;\\n }\\n\\n function peg$parsemoveTextSection() {\\n var s0, s1, s2, s3, s4;\\n\\n s0 = peg$currPos;\\n s1 = peg$parseline();\\n s2 = peg$parse_();\\n s3 = peg$parsegameTerminationMarker();\\n if (s3 === peg$FAILED) {\\n s3 = null;\\n }\\n s4 = peg$parse_();\\n peg$savedPos = s0;\\n s0 = peg$f3(s1, s3);\\n\\n return s0;\\n }\\n\\n function peg$parseline() {\\n var s0, s1, s2, s3;\\n\\n s0 = peg$currPos;\\n s1 = peg$parsecomment();\\n if (s1 === peg$FAILED) {\\n s1 = null;\\n }\\n s2 = [];\\n s3 = peg$parsemove();\\n while (s3 !== peg$FAILED) {\\n s2.push(s3);\\n s3 = peg$parsemove();\\n }\\n peg$savedPos = s0;\\n s0 = peg$f4(s1, s2);\\n\\n return s0;\\n }\\n\\n function peg$parsemove() {\\n var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10;\\n\\n s0 = peg$currPos;\\n s1 = peg$parse_();\\n s2 = peg$parsemoveNumber();\\n if (s2 === peg$FAILED) {\\n s2 = null;\\n }\\n s3 = peg$parse_();\\n s4 = peg$parsesan();\\n if (s4 !== peg$FAILED) {\\n s5 = peg$parsesuffixAnnotation();\\n if (s5 === peg$FAILED) {\\n s5 = null;\\n }\\n s6 = [];\\n s7 = peg$parsenag();\\n while (s7 !== peg$FAILED) {\\n s6.push(s7);\\n s7 = peg$parsenag();\\n }\\n s7 = peg$parse_();\\n s8 = peg$parsecomment();\\n if (s8 === peg$FAILED) {\\n s8 = null;\\n }\\n s9 = [];\\n s10 = peg$parsevariation();\\n while (s10 !== peg$FAILED) {\\n s9.push(s10);\\n s10 = peg$parsevariation();\\n }\\n peg$savedPos = s0;\\n s0 = peg$f5(s4, s5, s6, s8, s9);\\n } else {\\n peg$currPos = s0;\\n s0 = peg$FAILED;\\n }\\n\\n return s0;\\n }\\n\\n function peg$parsemoveNumber() {\\n var s0, s1, s2, s3, s4, s5;\\n\\n peg$silentFails++;\\n s0 = peg$currPos;\\n s1 = [];\\n s2 = input.charAt(peg$currPos);\\n if (peg$r2.test(s2)) {\\n peg$currPos++;\\n } else {\\n s2 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e9); }\\n }\\n while (s2 !== peg$FAILED) {\\n s1.push(s2);\\n s2 = input.charAt(peg$currPos);\\n if (peg$r2.test(s2)) {\\n peg$currPos++;\\n } else {\\n s2 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e9); }\\n }\\n }\\n if (input.charCodeAt(peg$currPos) === 46) {\\n s2 = peg$c3;\\n peg$currPos++;\\n } else {\\n s2 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e10); }\\n }\\n if (s2 !== peg$FAILED) {\\n s3 = peg$parse_();\\n s4 = [];\\n s5 = input.charAt(peg$currPos);\\n if (peg$r3.test(s5)) {\\n peg$currPos++;\\n } else {\\n s5 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e11); }\\n }\\n while (s5 !== peg$FAILED) {\\n s4.push(s5);\\n s5 = input.charAt(peg$currPos);\\n if (peg$r3.test(s5)) {\\n peg$currPos++;\\n } else {\\n s5 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e11); }\\n }\\n }\\n s1 = [s1, s2, s3, s4];\\n s0 = s1;\\n } else {\\n peg$currPos = s0;\\n s0 = peg$FAILED;\\n }\\n peg$silentFails--;\\n if (s0 === peg$FAILED) {\\n s1 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e8); }\\n }\\n\\n return s0;\\n }\\n\\n function peg$parsesan() {\\n var s0, s1, s2, s3, s4, s5;\\n\\n peg$silentFails++;\\n s0 = peg$currPos;\\n s1 = peg$currPos;\\n if (input.substr(peg$currPos, 5) === peg$c4) {\\n s2 = peg$c4;\\n peg$currPos += 5;\\n } else {\\n s2 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e13); }\\n }\\n if (s2 === peg$FAILED) {\\n if (input.substr(peg$currPos, 3) === peg$c5) {\\n s2 = peg$c5;\\n peg$currPos += 3;\\n } else {\\n s2 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e14); }\\n }\\n if (s2 === peg$FAILED) {\\n if (input.substr(peg$currPos, 5) === peg$c6) {\\n s2 = peg$c6;\\n peg$currPos += 5;\\n } else {\\n s2 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e15); }\\n }\\n if (s2 === peg$FAILED) {\\n if (input.substr(peg$currPos, 3) === peg$c7) {\\n s2 = peg$c7;\\n peg$currPos += 3;\\n } else {\\n s2 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e16); }\\n }\\n if (s2 === peg$FAILED) {\\n s2 = peg$currPos;\\n s3 = input.charAt(peg$currPos);\\n if (peg$r0.test(s3)) {\\n peg$currPos++;\\n } else {\\n s3 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e5); }\\n }\\n if (s3 !== peg$FAILED) {\\n s4 = [];\\n s5 = input.charAt(peg$currPos);\\n if (peg$r4.test(s5)) {\\n peg$currPos++;\\n } else {\\n s5 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e17); }\\n }\\n if (s5 !== peg$FAILED) {\\n while (s5 !== peg$FAILED) {\\n s4.push(s5);\\n s5 = input.charAt(peg$currPos);\\n if (peg$r4.test(s5)) {\\n peg$currPos++;\\n } else {\\n s5 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e17); }\\n }\\n }\\n } else {\\n s4 = peg$FAILED;\\n }\\n if (s4 !== peg$FAILED) {\\n s3 = [s3, s4];\\n s2 = s3;\\n } else {\\n peg$currPos = s2;\\n s2 = peg$FAILED;\\n }\\n } else {\\n peg$currPos = s2;\\n s2 = peg$FAILED;\\n }\\n }\\n }\\n }\\n }\\n if (s2 !== peg$FAILED) {\\n s3 = input.charAt(peg$currPos);\\n if (peg$r5.test(s3)) {\\n peg$currPos++;\\n } else {\\n s3 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e18); }\\n }\\n if (s3 === peg$FAILED) {\\n s3 = null;\\n }\\n s2 = [s2, s3];\\n s1 = s2;\\n } else {\\n peg$currPos = s1;\\n s1 = peg$FAILED;\\n }\\n if (s1 !== peg$FAILED) {\\n s0 = input.substring(s0, peg$currPos);\\n } else {\\n s0 = s1;\\n }\\n peg$silentFails--;\\n if (s0 === peg$FAILED) {\\n s1 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e12); }\\n }\\n\\n return s0;\\n }\\n\\n function peg$parsesuffixAnnotation() {\\n var s0, s1, s2;\\n\\n peg$silentFails++;\\n s0 = peg$currPos;\\n s1 = [];\\n s2 = input.charAt(peg$currPos);\\n if (peg$r6.test(s2)) {\\n peg$currPos++;\\n } else {\\n s2 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e20); }\\n }\\n while (s2 !== peg$FAILED) {\\n s1.push(s2);\\n if (s1.length >= 2) {\\n s2 = peg$FAILED;\\n } else {\\n s2 = input.charAt(peg$currPos);\\n if (peg$r6.test(s2)) {\\n peg$currPos++;\\n } else {\\n s2 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e20); }\\n }\\n }\\n }\\n if (s1.length < 1) {\\n peg$currPos = s0;\\n s0 = peg$FAILED;\\n } else {\\n s0 = s1;\\n }\\n peg$silentFails--;\\n if (s0 === peg$FAILED) {\\n s1 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e19); }\\n }\\n\\n return s0;\\n }\\n\\n function peg$parsenag() {\\n var s0, s1, s2, s3, s4, s5;\\n\\n peg$silentFails++;\\n s0 = peg$currPos;\\n s1 = peg$parse_();\\n if (input.charCodeAt(peg$currPos) === 36) {\\n s2 = peg$c8;\\n peg$currPos++;\\n } else {\\n s2 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e22); }\\n }\\n if (s2 !== peg$FAILED) {\\n s3 = peg$currPos;\\n s4 = [];\\n s5 = input.charAt(peg$currPos);\\n if (peg$r2.test(s5)) {\\n peg$currPos++;\\n } else {\\n s5 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e9); }\\n }\\n if (s5 !== peg$FAILED) {\\n while (s5 !== peg$FAILED) {\\n s4.push(s5);\\n s5 = input.charAt(peg$currPos);\\n if (peg$r2.test(s5)) {\\n peg$currPos++;\\n } else {\\n s5 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e9); }\\n }\\n }\\n } else {\\n s4 = peg$FAILED;\\n }\\n if (s4 !== peg$FAILED) {\\n s3 = input.substring(s3, peg$currPos);\\n } else {\\n s3 = s4;\\n }\\n if (s3 !== peg$FAILED) {\\n peg$savedPos = s0;\\n s0 = peg$f6(s3);\\n } else {\\n peg$currPos = s0;\\n s0 = peg$FAILED;\\n }\\n } else {\\n peg$currPos = s0;\\n s0 = peg$FAILED;\\n }\\n peg$silentFails--;\\n if (s0 === peg$FAILED) {\\n s1 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e21); }\\n }\\n\\n return s0;\\n }\\n\\n function peg$parsecomment() {\\n var s0;\\n\\n s0 = peg$parsebraceComment();\\n if (s0 === peg$FAILED) {\\n s0 = peg$parserestOfLineComment();\\n }\\n\\n return s0;\\n }\\n\\n function peg$parsebraceComment() {\\n var s0, s1, s2, s3, s4;\\n\\n peg$silentFails++;\\n s0 = peg$currPos;\\n if (input.charCodeAt(peg$currPos) === 123) {\\n s1 = peg$c9;\\n peg$currPos++;\\n } else {\\n s1 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e24); }\\n }\\n if (s1 !== peg$FAILED) {\\n s2 = peg$currPos;\\n s3 = [];\\n s4 = input.charAt(peg$currPos);\\n if (peg$r7.test(s4)) {\\n peg$currPos++;\\n } else {\\n s4 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e25); }\\n }\\n while (s4 !== peg$FAILED) {\\n s3.push(s4);\\n s4 = input.charAt(peg$currPos);\\n if (peg$r7.test(s4)) {\\n peg$currPos++;\\n } else {\\n s4 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e25); }\\n }\\n }\\n s2 = input.substring(s2, peg$currPos);\\n if (input.charCodeAt(peg$currPos) === 125) {\\n s3 = peg$c10;\\n peg$currPos++;\\n } else {\\n s3 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e26); }\\n }\\n if (s3 !== peg$FAILED) {\\n peg$savedPos = s0;\\n s0 = peg$f7(s2);\\n } else {\\n peg$currPos = s0;\\n s0 = peg$FAILED;\\n }\\n } else {\\n peg$currPos = s0;\\n s0 = peg$FAILED;\\n }\\n peg$silentFails--;\\n if (s0 === peg$FAILED) {\\n s1 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e23); }\\n }\\n\\n return s0;\\n }\\n\\n function peg$parserestOfLineComment() {\\n var s0, s1, s2, s3, s4;\\n\\n peg$silentFails++;\\n s0 = peg$currPos;\\n if (input.charCodeAt(peg$currPos) === 59) {\\n s1 = peg$c11;\\n peg$currPos++;\\n } else {\\n s1 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e28); }\\n }\\n if (s1 !== peg$FAILED) {\\n s2 = peg$currPos;\\n s3 = [];\\n s4 = input.charAt(peg$currPos);\\n if (peg$r8.test(s4)) {\\n peg$currPos++;\\n } else {\\n s4 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e29); }\\n }\\n while (s4 !== peg$FAILED) {\\n s3.push(s4);\\n s4 = input.charAt(peg$currPos);\\n if (peg$r8.test(s4)) {\\n peg$currPos++;\\n } else {\\n s4 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e29); }\\n }\\n }\\n s2 = input.substring(s2, peg$currPos);\\n peg$savedPos = s0;\\n s0 = peg$f8(s2);\\n } else {\\n peg$currPos = s0;\\n s0 = peg$FAILED;\\n }\\n peg$silentFails--;\\n if (s0 === peg$FAILED) {\\n s1 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e27); }\\n }\\n\\n return s0;\\n }\\n\\n function peg$parsevariation() {\\n var s0, s1, s2, s3, s4, s5;\\n\\n peg$silentFails++;\\n s0 = peg$currPos;\\n s1 = peg$parse_();\\n if (input.charCodeAt(peg$currPos) === 40) {\\n s2 = peg$c12;\\n peg$currPos++;\\n } else {\\n s2 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e31); }\\n }\\n if (s2 !== peg$FAILED) {\\n s3 = peg$parseline();\\n if (s3 !== peg$FAILED) {\\n s4 = peg$parse_();\\n if (input.charCodeAt(peg$currPos) === 41) {\\n s5 = peg$c13;\\n peg$currPos++;\\n } else {\\n s5 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e32); }\\n }\\n if (s5 !== peg$FAILED) {\\n peg$savedPos = s0;\\n s0 = peg$f9(s3);\\n } else {\\n peg$currPos = s0;\\n s0 = peg$FAILED;\\n }\\n } else {\\n peg$currPos = s0;\\n s0 = peg$FAILED;\\n }\\n } else {\\n peg$currPos = s0;\\n s0 = peg$FAILED;\\n }\\n peg$silentFails--;\\n if (s0 === peg$FAILED) {\\n s1 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e30); }\\n }\\n\\n return s0;\\n }\\n\\n function peg$parsegameTerminationMarker() {\\n var s0, s1, s2, s3;\\n\\n peg$silentFails++;\\n s0 = peg$currPos;\\n if (input.substr(peg$currPos, 3) === peg$c14) {\\n s1 = peg$c14;\\n peg$currPos += 3;\\n } else {\\n s1 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e34); }\\n }\\n if (s1 === peg$FAILED) {\\n if (input.substr(peg$currPos, 3) === peg$c15) {\\n s1 = peg$c15;\\n peg$currPos += 3;\\n } else {\\n s1 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e35); }\\n }\\n if (s1 === peg$FAILED) {\\n if (input.substr(peg$currPos, 7) === peg$c16) {\\n s1 = peg$c16;\\n peg$currPos += 7;\\n } else {\\n s1 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e36); }\\n }\\n if (s1 === peg$FAILED) {\\n if (input.charCodeAt(peg$currPos) === 42) {\\n s1 = peg$c17;\\n peg$currPos++;\\n } else {\\n s1 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e37); }\\n }\\n }\\n }\\n }\\n if (s1 !== peg$FAILED) {\\n s2 = peg$parse_();\\n s3 = peg$parsecomment();\\n if (s3 === peg$FAILED) {\\n s3 = null;\\n }\\n peg$savedPos = s0;\\n s0 = peg$f10(s1, s3);\\n } else {\\n peg$currPos = s0;\\n s0 = peg$FAILED;\\n }\\n peg$silentFails--;\\n if (s0 === peg$FAILED) {\\n s1 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e33); }\\n }\\n\\n return s0;\\n }\\n\\n function peg$parse_() {\\n var s0, s1;\\n\\n peg$silentFails++;\\n s0 = [];\\n s1 = input.charAt(peg$currPos);\\n if (peg$r9.test(s1)) {\\n peg$currPos++;\\n } else {\\n s1 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e39); }\\n }\\n while (s1 !== peg$FAILED) {\\n s0.push(s1);\\n s1 = input.charAt(peg$currPos);\\n if (peg$r9.test(s1)) {\\n peg$currPos++;\\n } else {\\n s1 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e39); }\\n }\\n }\\n peg$silentFails--;\\n s1 = peg$FAILED;\\n if (peg$silentFails === 0) { peg$fail(peg$e38); }\\n\\n return s0;\\n }\\n\\n peg$result = peg$startRuleFunction();\\n\\n if (options.peg$library) {\\n return /** @type {any} */ ({\\n peg$result,\\n peg$currPos,\\n peg$FAILED,\\n peg$maxFailExpected,\\n peg$maxFailPos\\n });\\n }\\n if (peg$result !== peg$FAILED && peg$currPos === input.length) {\\n return peg$result;\\n } else {\\n if (peg$result !== peg$FAILED && peg$currPos < input.length) {\\n peg$fail(peg$endExpectation());\\n }\\n\\n throw peg$buildStructuredError(\\n peg$maxFailExpected,\\n peg$maxFailPos < input.length ? input.charAt(peg$maxFailPos) : null,\\n peg$maxFailPos < input.length\\n ? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1)\\n : peg$computeLocation(peg$maxFailPos, peg$maxFailPos)\\n );\\n }\\n}\\n\\nconst peg$allowedStartRules = [\\n \\\"pgn\\\"\\n];\\n\\nexport {\\n peg$allowedStartRules as StartRules,\\n peg$SyntaxError as SyntaxError,\\n peg$parse as parse\\n};\\n\",null,\"import { Chess } from 'chess.js';\\n\\nconst chess = new Chess();\\nconst legalMoves = chess.moves({ verbose: true });\\n\\nexport default legalMoves.some(\\n (move) => move.from === 'e2' && move.to === 'e6',\\n);\\n\"],\"version\":3}", + "originMeta": { + "originalPath": "node_modules/.pnpm/chess.js@1.4.0/node_modules/chess.js/dist/esm/chess.js", + "packageName": "chess.js", + "packageVersion": "1.4.0", + "integrity": "483aad47a5ae3669a320d313a6ce1be9be705b5c52775cba1b4f45d1fada0562" + } + } + ], + "builderVersion": "deterministic-builder-v1", + "dependencyIntegrity": "483aad47a5ae3669a320d313a6ce1be9be705b5c52775cba1b4f45d1fada0562", + "diagnosticsMeta": { + "entryPath": "/workspace/libs/test-harness/fixtures/library-reuse/chess-entry.ts", + "modulePaths": [ + "./chess-entry.js" + ] + }, + "graphHash": "689f4980e43e34c287819a4445a4a2f32b61ea8714e9ff3edc909b76496de91f" + } + } + }, + "manifest": { + "abi_id": "Host.v1", + "abi_version": 1, + "functions": [ + { + "fn_id": 1, + "js_path": [ + "document", + "get" + ], + "effect": "READ", + "arity": 1, + "arg_schema": [ + { + "type": "string" + } + ], + "return_schema": { + "type": "dv" + }, + "gas": { + "schedule_id": "doc-read-v1", + "base": 20, + "k_arg_bytes": 1, + "k_ret_bytes": 1, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 4096, + "max_response_bytes": 262144, + "max_units": 1000, + "arg_utf8_max": [ + 2048 + ] + }, + "error_codes": [ + { + "code": "INVALID_PATH", + "tag": "host/invalid_path" + }, + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + }, + { + "code": "NOT_FOUND", + "tag": "host/not_found" + } + ] + }, + { + "fn_id": 2, + "js_path": [ + "document", + "getCanonical" + ], + "effect": "READ", + "arity": 1, + "arg_schema": [ + { + "type": "string" + } + ], + "return_schema": { + "type": "dv" + }, + "gas": { + "schedule_id": "doc-read-v1", + "base": 20, + "k_arg_bytes": 1, + "k_ret_bytes": 1, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 4096, + "max_response_bytes": 262144, + "max_units": 1000, + "arg_utf8_max": [ + 2048 + ] + }, + "error_codes": [ + { + "code": "INVALID_PATH", + "tag": "host/invalid_path" + }, + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + }, + { + "code": "NOT_FOUND", + "tag": "host/not_found" + } + ] + }, + { + "fn_id": 3, + "js_path": [ + "emit" + ], + "effect": "EMIT", + "arity": 1, + "arg_schema": [ + { + "type": "dv" + } + ], + "return_schema": { + "type": "null" + }, + "gas": { + "schedule_id": "emit-v1", + "base": 5, + "k_arg_bytes": 1, + "k_ret_bytes": 0, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 32768, + "max_response_bytes": 64, + "max_units": 1024 + }, + "error_codes": [ + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + } + ] + } + ] + } + }, + { + "id": "example-promises-async", + "title": "Promises / async / microtasks", + "kind": "example", + "badge": "Example 4", + "description": "Promise job draining under an explicitly compatible profile.", + "certified": true, + "executionProfile": "compat-general-v1", + "sourceKind": "script", + "abiId": "Host.v1", + "gasLimit": "50000", + "sourcePaths": [ + "examples/04-promises-async/program.js" + ], + "sourceText": "(() => Promise.resolve(40).then((value) => value + 2))();\n", + "hostPreset": "determinism", + "hostSummary": { + "label": "Determinism fixture host", + "description": "Provides stable Host.v1/Host.v2 document responses plus deterministic emit tape capture.", + "documents": [ + "path/to/doc", + "path/to/canonical", + "path/to/first", + "path/to/second", + "path/to/third", + "bytes/payload" + ] + }, + "docsLinks": [ + { + "label": "Learn path", + "href": "/docs/learn/README.md" + }, + { + "label": "Examples corpus", + "href": "/examples/README.md" + }, + { + "label": "Promises and microtasks", + "href": "/docs/learn/04-promises-async-and-microtasks.md" + } + ], + "supportsOogSearch": true, + "program": { + "version": 2, + "abiId": "Host.v1", + "abiVersion": 1, + "abiManifestHash": "e23b0b2ee169900bbde7aff78e6ce20fead1715c60f8a8e3106d9959450a3d34", + "executionProfile": "compat-general-v1", + "sourceKind": "script", + "source": { + "code": "(() => Promise.resolve(40).then((value) => value + 2))();\n" + }, + "engineBuildHash": "f91091cb7feb788df340305a877a9cadb0c6f4d13aea8a7da4040b6367d178ea", + "gasVersion": 8 + }, + "manifest": { + "abi_id": "Host.v1", + "abi_version": 1, + "functions": [ + { + "fn_id": 1, + "js_path": [ + "document", + "get" + ], + "effect": "READ", + "arity": 1, + "arg_schema": [ + { + "type": "string" + } + ], + "return_schema": { + "type": "dv" + }, + "gas": { + "schedule_id": "doc-read-v1", + "base": 20, + "k_arg_bytes": 1, + "k_ret_bytes": 1, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 4096, + "max_response_bytes": 262144, + "max_units": 1000, + "arg_utf8_max": [ + 2048 + ] + }, + "error_codes": [ + { + "code": "INVALID_PATH", + "tag": "host/invalid_path" + }, + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + }, + { + "code": "NOT_FOUND", + "tag": "host/not_found" + } + ] + }, + { + "fn_id": 2, + "js_path": [ + "document", + "getCanonical" + ], + "effect": "READ", + "arity": 1, + "arg_schema": [ + { + "type": "string" + } + ], + "return_schema": { + "type": "dv" + }, + "gas": { + "schedule_id": "doc-read-v1", + "base": 20, + "k_arg_bytes": 1, + "k_ret_bytes": 1, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 4096, + "max_response_bytes": 262144, + "max_units": 1000, + "arg_utf8_max": [ + 2048 + ] + }, + "error_codes": [ + { + "code": "INVALID_PATH", + "tag": "host/invalid_path" + }, + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + }, + { + "code": "NOT_FOUND", + "tag": "host/not_found" + } + ] + }, + { + "fn_id": 3, + "js_path": [ + "emit" + ], + "effect": "EMIT", + "arity": 1, + "arg_schema": [ + { + "type": "dv" + } + ], + "return_schema": { + "type": "null" + }, + "gas": { + "schedule_id": "emit-v1", + "base": 5, + "k_arg_bytes": 1, + "k_ret_bytes": 0, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 32768, + "max_response_bytes": 64, + "max_units": 1024 + }, + "error_codes": [ + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + } + ] + } + ] + } + }, + { + "id": "example-promises-library-host", + "title": "Promises + imported library + host call", + "kind": "example", + "badge": "Example 5", + "description": "Imported module code plus Promise jobs plus host interaction.", + "certified": true, + "executionProfile": "compat-general-v1", + "sourceKind": "module-pack", + "abiId": "Host.v1", + "gasLimit": "100000", + "sourcePaths": [ + "examples/05-promises-library-host/entry.js", + "examples/05-promises-library-host/lib.js" + ], + "sourceText": "import { plusOne } from './lib.js';\n\nexport default Promise.resolve(plusOne(41)).then((value) => {\n Host.v1.emit({ phase: 'async-lib', value });\n return value;\n});\n", + "hostPreset": "determinism", + "hostSummary": { + "label": "Determinism fixture host", + "description": "Provides stable Host.v1/Host.v2 document responses plus deterministic emit tape capture.", + "documents": [ + "path/to/doc", + "path/to/canonical", + "path/to/first", + "path/to/second", + "path/to/third", + "bytes/payload" + ] + }, + "docsLinks": [ + { + "label": "Learn path", + "href": "/docs/learn/README.md" + }, + { + "label": "Examples corpus", + "href": "/examples/README.md" + }, + { + "label": "Promises and microtasks", + "href": "/docs/learn/04-promises-async-and-microtasks.md" + } + ], + "supportsOogSearch": true, + "program": { + "version": 2, + "abiId": "Host.v1", + "abiVersion": 1, + "abiManifestHash": "e23b0b2ee169900bbde7aff78e6ce20fead1715c60f8a8e3106d9959450a3d34", + "engineBuildHash": "f91091cb7feb788df340305a877a9cadb0c6f4d13aea8a7da4040b6367d178ea", + "gasVersion": 8, + "executionProfile": "compat-general-v1", + "sourceKind": "module-pack", + "source": { + "modulePack": { + "version": 1, + "entrySpecifier": "./entry.js", + "entryExport": "default", + "modules": [ + { + "specifier": "./entry.js", + "source": "// examples/05-promises-library-host/lib.js\nvar plusOne = (value) => value + 1;\n\n// examples/05-promises-library-host/entry.js\nvar entry_default = Promise.resolve(plusOne(41)).then((value) => {\n Host.v1.emit({ phase: \"async-lib\", value });\n return value;\n});\nexport {\n entry_default as default\n};\n", + "sourceMap": "{\"mappings\":\";AAAO,IAAM,UAAU,CAAC,UAAU,QAAQ;;;ACE1C,IAAO,gBAAQ,QAAQ,QAAQ,QAAQ,EAAE,CAAC,EAAE,KAAK,CAAC,UAAU;AAC1D,OAAK,GAAG,KAAK,EAAE,OAAO,aAAa,MAAM,CAAC;AAC1C,SAAO;AACT,CAAC;\",\"names\":[],\"sources\":[\"../examples/05-promises-library-host/lib.js\",\"../examples/05-promises-library-host/entry.js\"],\"sourcesContent\":[\"export const plusOne = (value) => value + 1;\\n\",\"import { plusOne } from './lib.js';\\n\\nexport default Promise.resolve(plusOne(41)).then((value) => {\\n Host.v1.emit({ phase: 'async-lib', value });\\n return value;\\n});\\n\"],\"version\":3}", + "originMeta": { + "originalPath": "examples/05-promises-library-host/entry.js" + } + } + ], + "builderVersion": "deterministic-builder-v1", + "dependencyIntegrity": "483aad47a5ae3669a320d313a6ce1be9be705b5c52775cba1b4f45d1fada0562", + "diagnosticsMeta": { + "entryPath": "/workspace/examples/05-promises-library-host/entry.js", + "modulePaths": [ + "./entry.js" + ] + }, + "graphHash": "2cbcc7bf38d7b998a6e4e855e5f5a7bb9f77b0bb2f8434982409678812d39ec7" + } + } + }, + "manifest": { + "abi_id": "Host.v1", + "abi_version": 1, + "functions": [ + { + "fn_id": 1, + "js_path": [ + "document", + "get" + ], + "effect": "READ", + "arity": 1, + "arg_schema": [ + { + "type": "string" + } + ], + "return_schema": { + "type": "dv" + }, + "gas": { + "schedule_id": "doc-read-v1", + "base": 20, + "k_arg_bytes": 1, + "k_ret_bytes": 1, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 4096, + "max_response_bytes": 262144, + "max_units": 1000, + "arg_utf8_max": [ + 2048 + ] + }, + "error_codes": [ + { + "code": "INVALID_PATH", + "tag": "host/invalid_path" + }, + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + }, + { + "code": "NOT_FOUND", + "tag": "host/not_found" + } + ] + }, + { + "fn_id": 2, + "js_path": [ + "document", + "getCanonical" + ], + "effect": "READ", + "arity": 1, + "arg_schema": [ + { + "type": "string" + } + ], + "return_schema": { + "type": "dv" + }, + "gas": { + "schedule_id": "doc-read-v1", + "base": 20, + "k_arg_bytes": 1, + "k_ret_bytes": 1, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 4096, + "max_response_bytes": 262144, + "max_units": 1000, + "arg_utf8_max": [ + 2048 + ] + }, + "error_codes": [ + { + "code": "INVALID_PATH", + "tag": "host/invalid_path" + }, + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + }, + { + "code": "NOT_FOUND", + "tag": "host/not_found" + } + ] + }, + { + "fn_id": 3, + "js_path": [ + "emit" + ], + "effect": "EMIT", + "arity": 1, + "arg_schema": [ + { + "type": "dv" + } + ], + "return_schema": { + "type": "null" + }, + "gas": { + "schedule_id": "emit-v1", + "base": 5, + "k_arg_bytes": 1, + "k_ret_bytes": 0, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 32768, + "max_response_bytes": 64, + "max_units": 1024 + }, + "error_codes": [ + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + } + ] + } + ] + } + }, + { + "id": "example-binary-host-v2", + "title": "Binary / typed arrays / Host.v2 DV2", + "kind": "example", + "badge": "Example 6", + "description": "Typed-array and bytes boundary example using Host.v2 and DV2.", + "certified": true, + "executionProfile": "compat-binary-v1", + "sourceKind": "script", + "abiId": "Host.v2", + "gasLimit": "50000", + "sourcePaths": [ + "examples/06-binary-host-v2/program.js" + ], + "sourceText": "(() => {\n const payload = Host.v2.document.get('bytes/payload');\n Host.v2.emit(payload);\n let sum = 0;\n for (const byte of payload) {\n sum += byte;\n }\n return {\n length: payload.byteLength,\n first: payload[0],\n last: payload[payload.byteLength - 1],\n sum,\n };\n})();\n", + "hostPreset": "determinism", + "hostSummary": { + "label": "Determinism fixture host", + "description": "Provides stable Host.v1/Host.v2 document responses plus deterministic emit tape capture.", + "documents": [ + "path/to/doc", + "path/to/canonical", + "path/to/first", + "path/to/second", + "path/to/third", + "bytes/payload" + ] + }, + "docsLinks": [ + { + "label": "Learn path", + "href": "/docs/learn/README.md" + }, + { + "label": "Examples corpus", + "href": "/examples/README.md" + }, + { + "label": "Binary mode and Host.v2", + "href": "/docs/learn/05-binary-and-host-v2.md" + } + ], + "supportsOogSearch": true, + "program": { + "version": 2, + "abiId": "Host.v2", + "abiVersion": 2, + "abiManifestHash": "ec5c3df99a1b0ab84b692996193707ae6c931382e75c96c7c14b4f8baaae5af2", + "executionProfile": "compat-binary-v1", + "sourceKind": "script", + "source": { + "code": "(() => {\n const payload = Host.v2.document.get('bytes/payload');\n Host.v2.emit(payload);\n let sum = 0;\n for (const byte of payload) {\n sum += byte;\n }\n return {\n length: payload.byteLength,\n first: payload[0],\n last: payload[payload.byteLength - 1],\n sum,\n };\n})();\n" + }, + "engineBuildHash": "f91091cb7feb788df340305a877a9cadb0c6f4d13aea8a7da4040b6367d178ea", + "gasVersion": 8 + }, + "manifest": { + "abi_id": "Host.v2", + "abi_version": 2, + "functions": [ + { + "fn_id": 1, + "js_path": [ + "document", + "get" + ], + "effect": "READ", + "arity": 1, + "arg_schema": [ + { + "type": "string" + } + ], + "return_schema": { + "type": "dv" + }, + "gas": { + "schedule_id": "doc-read-v1", + "base": 20, + "k_arg_bytes": 1, + "k_ret_bytes": 1, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 4096, + "max_response_bytes": 262144, + "max_units": 1000, + "arg_utf8_max": [ + 2048 + ] + }, + "error_codes": [ + { + "code": "INVALID_PATH", + "tag": "host/invalid_path" + }, + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + }, + { + "code": "NOT_FOUND", + "tag": "host/not_found" + } + ] + }, + { + "fn_id": 2, + "js_path": [ + "document", + "getCanonical" + ], + "effect": "READ", + "arity": 1, + "arg_schema": [ + { + "type": "string" + } + ], + "return_schema": { + "type": "dv" + }, + "gas": { + "schedule_id": "doc-read-v1", + "base": 20, + "k_arg_bytes": 1, + "k_ret_bytes": 1, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 4096, + "max_response_bytes": 262144, + "max_units": 1000, + "arg_utf8_max": [ + 2048 + ] + }, + "error_codes": [ + { + "code": "INVALID_PATH", + "tag": "host/invalid_path" + }, + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + }, + { + "code": "NOT_FOUND", + "tag": "host/not_found" + } + ] + }, + { + "fn_id": 3, + "js_path": [ + "emit" + ], + "effect": "EMIT", + "arity": 1, + "arg_schema": [ + { + "type": "dv" + } + ], + "return_schema": { + "type": "null" + }, + "gas": { + "schedule_id": "emit-v1", + "base": 5, + "k_arg_bytes": 1, + "k_ret_bytes": 0, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 32768, + "max_response_bytes": 64, + "max_units": 1024 + }, + "error_codes": [ + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + } + ] + } + ] + } + }, + { + "id": "example-console-shim", + "title": "Console shim determinism", + "kind": "example", + "badge": "Example 7", + "description": "Deterministic console shimming routed through host tape.", + "certified": true, + "executionProfile": "compat-general-v1", + "sourceKind": "script", + "abiId": "Host.v1", + "gasLimit": "50000", + "sourcePaths": [ + "examples/07-console-shim/program.js" + ], + "sourceText": "(() => {\n console.info('deterministic', 7);\n return { ok: true };\n})();\n", + "hostPreset": "determinism", + "hostSummary": { + "label": "Determinism fixture host", + "description": "Provides stable Host.v1/Host.v2 document responses plus deterministic emit tape capture.", + "documents": [ + "path/to/doc", + "path/to/canonical", + "path/to/first", + "path/to/second", + "path/to/third", + "bytes/payload" + ] + }, + "docsLinks": [ + { + "label": "Learn path", + "href": "/docs/learn/README.md" + }, + { + "label": "Examples corpus", + "href": "/examples/README.md" + } + ], + "supportsOogSearch": true, + "program": { + "version": 2, + "abiId": "Host.v1", + "abiVersion": 1, + "abiManifestHash": "e23b0b2ee169900bbde7aff78e6ce20fead1715c60f8a8e3106d9959450a3d34", + "executionProfile": "compat-general-v1", + "sourceKind": "script", + "source": { + "code": "(() => {\n console.info('deterministic', 7);\n return { ok: true };\n})();\n" + }, + "engineBuildHash": "f91091cb7feb788df340305a877a9cadb0c6f4d13aea8a7da4040b6367d178ea", + "gasVersion": 8 + }, + "manifest": { + "abi_id": "Host.v1", + "abi_version": 1, + "functions": [ + { + "fn_id": 1, + "js_path": [ + "document", + "get" + ], + "effect": "READ", + "arity": 1, + "arg_schema": [ + { + "type": "string" + } + ], + "return_schema": { + "type": "dv" + }, + "gas": { + "schedule_id": "doc-read-v1", + "base": 20, + "k_arg_bytes": 1, + "k_ret_bytes": 1, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 4096, + "max_response_bytes": 262144, + "max_units": 1000, + "arg_utf8_max": [ + 2048 + ] + }, + "error_codes": [ + { + "code": "INVALID_PATH", + "tag": "host/invalid_path" + }, + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + }, + { + "code": "NOT_FOUND", + "tag": "host/not_found" + } + ] + }, + { + "fn_id": 2, + "js_path": [ + "document", + "getCanonical" + ], + "effect": "READ", + "arity": 1, + "arg_schema": [ + { + "type": "string" + } + ], + "return_schema": { + "type": "dv" + }, + "gas": { + "schedule_id": "doc-read-v1", + "base": 20, + "k_arg_bytes": 1, + "k_ret_bytes": 1, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 4096, + "max_response_bytes": 262144, + "max_units": 1000, + "arg_utf8_max": [ + 2048 + ] + }, + "error_codes": [ + { + "code": "INVALID_PATH", + "tag": "host/invalid_path" + }, + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + }, + { + "code": "NOT_FOUND", + "tag": "host/not_found" + } + ] + }, + { + "fn_id": 3, + "js_path": [ + "emit" + ], + "effect": "EMIT", + "arity": 1, + "arg_schema": [ + { + "type": "dv" + } + ], + "return_schema": { + "type": "null" + }, + "gas": { + "schedule_id": "emit-v1", + "base": 5, + "k_arg_bytes": 1, + "k_ret_bytes": 0, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 32768, + "max_response_bytes": 64, + "max_units": 1024 + }, + "error_codes": [ + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + } + ] + } + ] + } + }, + { + "id": "example-stable-sort", + "title": "Stable sort determinism", + "kind": "example", + "badge": "Example 8", + "description": "Compatibility profile example showing deterministic stable sort.", + "certified": true, + "executionProfile": "compat-general-v1", + "sourceKind": "script", + "abiId": "Host.v1", + "gasLimit": "100000", + "sourcePaths": [ + "examples/08-stable-sort/program.js" + ], + "sourceText": "(() => {\n const records = [\n { id: 'a', group: 1 },\n { id: 'b', group: 1 },\n { id: 'c', group: 2 },\n { id: 'd', group: 1 },\n ];\n records.sort((left, right) => left.group - right.group);\n return records.map((record) => record.id);\n})();\n", + "hostPreset": "determinism", + "hostSummary": { + "label": "Determinism fixture host", + "description": "Provides stable Host.v1/Host.v2 document responses plus deterministic emit tape capture.", + "documents": [ + "path/to/doc", + "path/to/canonical", + "path/to/first", + "path/to/second", + "path/to/third", + "bytes/payload" + ] + }, + "docsLinks": [ + { + "label": "Learn path", + "href": "/docs/learn/README.md" + }, + { + "label": "Examples corpus", + "href": "/examples/README.md" + } + ], + "supportsOogSearch": true, + "program": { + "version": 2, + "abiId": "Host.v1", + "abiVersion": 1, + "abiManifestHash": "e23b0b2ee169900bbde7aff78e6ce20fead1715c60f8a8e3106d9959450a3d34", + "executionProfile": "compat-general-v1", + "sourceKind": "script", + "source": { + "code": "(() => {\n const records = [\n { id: 'a', group: 1 },\n { id: 'b', group: 1 },\n { id: 'c', group: 2 },\n { id: 'd', group: 1 },\n ];\n records.sort((left, right) => left.group - right.group);\n return records.map((record) => record.id);\n})();\n" + }, + "engineBuildHash": "f91091cb7feb788df340305a877a9cadb0c6f4d13aea8a7da4040b6367d178ea", + "gasVersion": 8 + }, + "manifest": { + "abi_id": "Host.v1", + "abi_version": 1, + "functions": [ + { + "fn_id": 1, + "js_path": [ + "document", + "get" + ], + "effect": "READ", + "arity": 1, + "arg_schema": [ + { + "type": "string" + } + ], + "return_schema": { + "type": "dv" + }, + "gas": { + "schedule_id": "doc-read-v1", + "base": 20, + "k_arg_bytes": 1, + "k_ret_bytes": 1, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 4096, + "max_response_bytes": 262144, + "max_units": 1000, + "arg_utf8_max": [ + 2048 + ] + }, + "error_codes": [ + { + "code": "INVALID_PATH", + "tag": "host/invalid_path" + }, + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + }, + { + "code": "NOT_FOUND", + "tag": "host/not_found" + } + ] + }, + { + "fn_id": 2, + "js_path": [ + "document", + "getCanonical" + ], + "effect": "READ", + "arity": 1, + "arg_schema": [ + { + "type": "string" + } + ], + "return_schema": { + "type": "dv" + }, + "gas": { + "schedule_id": "doc-read-v1", + "base": 20, + "k_arg_bytes": 1, + "k_ret_bytes": 1, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 4096, + "max_response_bytes": 262144, + "max_units": 1000, + "arg_utf8_max": [ + 2048 + ] + }, + "error_codes": [ + { + "code": "INVALID_PATH", + "tag": "host/invalid_path" + }, + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + }, + { + "code": "NOT_FOUND", + "tag": "host/not_found" + } + ] + }, + { + "fn_id": 3, + "js_path": [ + "emit" + ], + "effect": "EMIT", + "arity": 1, + "arg_schema": [ + { + "type": "dv" + } + ], + "return_schema": { + "type": "null" + }, + "gas": { + "schedule_id": "emit-v1", + "base": 5, + "k_arg_bytes": 1, + "k_ret_bytes": 0, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 32768, + "max_response_bytes": 64, + "max_units": 1024 + }, + "error_codes": [ + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + } + ] + } + ] + } + }, + { + "id": "example-kitchen-sink", + "title": "Kitchen sink app", + "kind": "example", + "badge": "Example 9", + "description": "Composite example mixing modules, Promise jobs, host calls, and stable sort.", + "certified": true, + "executionProfile": "compat-general-v1", + "sourceKind": "module-pack", + "abiId": "Host.v1", + "gasLimit": "200000", + "sourcePaths": [ + "examples/09-kitchen-sink/entry.js", + "examples/09-kitchen-sink/workflow.js" + ], + "sourceText": "import { summarize } from './workflow.js';\n\nexport default (async () => {\n const doc = document('path/to/doc');\n const canonical = document.canonical('path/to/doc');\n const result = await summarize(doc.path, canonical.canonical);\n Host.v1.emit({ kind: 'kitchen', result });\n return result;\n})();\n", + "hostPreset": "determinism", + "hostSummary": { + "label": "Determinism fixture host", + "description": "Provides stable Host.v1/Host.v2 document responses plus deterministic emit tape capture.", + "documents": [ + "path/to/doc", + "path/to/canonical", + "path/to/first", + "path/to/second", + "path/to/third", + "bytes/payload" + ] + }, + "docsLinks": [ + { + "label": "Learn path", + "href": "/docs/learn/README.md" + }, + { + "label": "Examples corpus", + "href": "/examples/README.md" + } + ], + "supportsOogSearch": true, + "program": { + "version": 2, + "abiId": "Host.v1", + "abiVersion": 1, + "abiManifestHash": "e23b0b2ee169900bbde7aff78e6ce20fead1715c60f8a8e3106d9959450a3d34", + "engineBuildHash": "f91091cb7feb788df340305a877a9cadb0c6f4d13aea8a7da4040b6367d178ea", + "gasVersion": 8, + "executionProfile": "compat-general-v1", + "sourceKind": "module-pack", + "source": { + "modulePack": { + "version": 1, + "entrySpecifier": "./entry.js", + "entryExport": "default", + "modules": [ + { + "specifier": "./entry.js", + "source": "// examples/09-kitchen-sink/workflow.js\nasync function summarize(path, canonical) {\n const queue = [];\n queueMicrotask(() => queue.push(\"micro\"));\n await Promise.resolve();\n const records = [\n { id: \"b\", rank: 2 },\n { id: \"a\", rank: 1 },\n { id: \"c\", rank: 2 }\n ];\n records.sort((left, right) => left.rank - right.rank);\n return {\n path,\n canonical,\n order: records.map((record) => record.id).join(\",\"),\n queue: queue.join(\",\")\n };\n}\n\n// examples/09-kitchen-sink/entry.js\nvar entry_default = (async () => {\n const doc = document(\"path/to/doc\");\n const canonical = document.canonical(\"path/to/doc\");\n const result = await summarize(doc.path, canonical.canonical);\n Host.v1.emit({ kind: \"kitchen\", result });\n return result;\n})();\nexport {\n entry_default as default\n};\n", + "sourceMap": "{\"mappings\":\";AAAA,eAAsB,UAAU,MAAM,WAAW;AAC/C,QAAM,QAAQ,CAAC;AACf,iBAAe,MAAM,MAAM,KAAK,OAAO,CAAC;AACxC,QAAM,QAAQ,QAAQ;AACtB,QAAM,UAAU;AAAA,IACd,EAAE,IAAI,KAAK,MAAM,EAAE;AAAA,IACnB,EAAE,IAAI,KAAK,MAAM,EAAE;AAAA,IACnB,EAAE,IAAI,KAAK,MAAM,EAAE;AAAA,EACrB;AACA,UAAQ,KAAK,CAAC,MAAM,UAAU,KAAK,OAAO,MAAM,IAAI;AACpD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,OAAO,QAAQ,IAAI,CAAC,WAAW,OAAO,EAAE,EAAE,KAAK,GAAG;AAAA,IAClD,OAAO,MAAM,KAAK,GAAG;AAAA,EACvB;AACF;;;ACdA,IAAO,iBAAS,YAAY;AAC1B,QAAM,MAAM,SAAS,aAAa;AAClC,QAAM,YAAY,SAAS,UAAU,aAAa;AAClD,QAAM,SAAS,MAAM,UAAU,IAAI,MAAM,UAAU,SAAS;AAC5D,OAAK,GAAG,KAAK,EAAE,MAAM,WAAW,OAAO,CAAC;AACxC,SAAO;AACT,GAAG;\",\"names\":[],\"sources\":[\"../examples/09-kitchen-sink/workflow.js\",\"../examples/09-kitchen-sink/entry.js\"],\"sourcesContent\":[\"export async function summarize(path, canonical) {\\n const queue = [];\\n queueMicrotask(() => queue.push('micro'));\\n await Promise.resolve();\\n const records = [\\n { id: 'b', rank: 2 },\\n { id: 'a', rank: 1 },\\n { id: 'c', rank: 2 },\\n ];\\n records.sort((left, right) => left.rank - right.rank);\\n return {\\n path,\\n canonical,\\n order: records.map((record) => record.id).join(','),\\n queue: queue.join(','),\\n };\\n}\\n\",\"import { summarize } from './workflow.js';\\n\\nexport default (async () => {\\n const doc = document('path/to/doc');\\n const canonical = document.canonical('path/to/doc');\\n const result = await summarize(doc.path, canonical.canonical);\\n Host.v1.emit({ kind: 'kitchen', result });\\n return result;\\n})();\\n\"],\"version\":3}", + "originMeta": { + "originalPath": "examples/09-kitchen-sink/entry.js" + } + } + ], + "builderVersion": "deterministic-builder-v1", + "dependencyIntegrity": "483aad47a5ae3669a320d313a6ce1be9be705b5c52775cba1b4f45d1fada0562", + "diagnosticsMeta": { + "entryPath": "/workspace/examples/09-kitchen-sink/entry.js", + "modulePaths": [ + "./entry.js" + ] + }, + "graphHash": "d79be16d156f0ee1669d4d6d7d422e08d8c1d287039e46fad9aa65c81d754d91" + } + } + }, + "manifest": { + "abi_id": "Host.v1", + "abi_version": 1, + "functions": [ + { + "fn_id": 1, + "js_path": [ + "document", + "get" + ], + "effect": "READ", + "arity": 1, + "arg_schema": [ + { + "type": "string" + } + ], + "return_schema": { + "type": "dv" + }, + "gas": { + "schedule_id": "doc-read-v1", + "base": 20, + "k_arg_bytes": 1, + "k_ret_bytes": 1, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 4096, + "max_response_bytes": 262144, + "max_units": 1000, + "arg_utf8_max": [ + 2048 + ] + }, + "error_codes": [ + { + "code": "INVALID_PATH", + "tag": "host/invalid_path" + }, + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + }, + { + "code": "NOT_FOUND", + "tag": "host/not_found" + } + ] + }, + { + "fn_id": 2, + "js_path": [ + "document", + "getCanonical" + ], + "effect": "READ", + "arity": 1, + "arg_schema": [ + { + "type": "string" + } + ], + "return_schema": { + "type": "dv" + }, + "gas": { + "schedule_id": "doc-read-v1", + "base": 20, + "k_arg_bytes": 1, + "k_ret_bytes": 1, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 4096, + "max_response_bytes": 262144, + "max_units": 1000, + "arg_utf8_max": [ + 2048 + ] + }, + "error_codes": [ + { + "code": "INVALID_PATH", + "tag": "host/invalid_path" + }, + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + }, + { + "code": "NOT_FOUND", + "tag": "host/not_found" + } + ] + }, + { + "fn_id": 3, + "js_path": [ + "emit" + ], + "effect": "EMIT", + "arity": 1, + "arg_schema": [ + { + "type": "dv" + } + ], + "return_schema": { + "type": "null" + }, + "gas": { + "schedule_id": "emit-v1", + "base": 5, + "k_arg_bytes": 1, + "k_ret_bytes": 0, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 32768, + "max_response_bytes": 64, + "max_units": 1024 + }, + "error_codes": [ + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + } + ] + } + ] + } + }, + { + "id": "example-max-gas-policy", + "title": "Max-gas policy / OOG boundary", + "kind": "example", + "badge": "Example 10", + "description": "Shows how exact OOG boundaries are part of the release contract.", + "certified": true, + "executionProfile": "baseline-v1", + "sourceKind": "script", + "abiId": "Host.v1", + "gasLimit": "1000000", + "sourcePaths": [ + "examples/10-max-gas-policy/program.js" + ], + "sourceText": "(() => {\n let sum = 0;\n for (let i = 0; i < 10000; i += 1) {\n sum += i;\n }\n return sum;\n})();\n", + "hostPreset": "determinism", + "hostSummary": { + "label": "Determinism fixture host", + "description": "Provides stable Host.v1/Host.v2 document responses plus deterministic emit tape capture.", + "documents": [ + "path/to/doc", + "path/to/canonical", + "path/to/first", + "path/to/second", + "path/to/third", + "bytes/payload" + ] + }, + "docsLinks": [ + { + "label": "Learn path", + "href": "/docs/learn/README.md" + }, + { + "label": "Examples corpus", + "href": "/examples/README.md" + }, + { + "label": "Gas and OOG", + "href": "/docs/learn/06-gas-oog-and-max-gas-policies.md" + } + ], + "supportsOogSearch": true, + "program": { + "version": 2, + "abiId": "Host.v1", + "abiVersion": 1, + "abiManifestHash": "e23b0b2ee169900bbde7aff78e6ce20fead1715c60f8a8e3106d9959450a3d34", + "executionProfile": "baseline-v1", + "sourceKind": "script", + "source": { + "code": "(() => {\n let sum = 0;\n for (let i = 0; i < 10000; i += 1) {\n sum += i;\n }\n return sum;\n})();\n" + }, + "engineBuildHash": "f91091cb7feb788df340305a877a9cadb0c6f4d13aea8a7da4040b6367d178ea", + "gasVersion": 8 + }, + "manifest": { + "abi_id": "Host.v1", + "abi_version": 1, + "functions": [ + { + "fn_id": 1, + "js_path": [ + "document", + "get" + ], + "effect": "READ", + "arity": 1, + "arg_schema": [ + { + "type": "string" + } + ], + "return_schema": { + "type": "dv" + }, + "gas": { + "schedule_id": "doc-read-v1", + "base": 20, + "k_arg_bytes": 1, + "k_ret_bytes": 1, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 4096, + "max_response_bytes": 262144, + "max_units": 1000, + "arg_utf8_max": [ + 2048 + ] + }, + "error_codes": [ + { + "code": "INVALID_PATH", + "tag": "host/invalid_path" + }, + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + }, + { + "code": "NOT_FOUND", + "tag": "host/not_found" + } + ] + }, + { + "fn_id": 2, + "js_path": [ + "document", + "getCanonical" + ], + "effect": "READ", + "arity": 1, + "arg_schema": [ + { + "type": "string" + } + ], + "return_schema": { + "type": "dv" + }, + "gas": { + "schedule_id": "doc-read-v1", + "base": 20, + "k_arg_bytes": 1, + "k_ret_bytes": 1, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 4096, + "max_response_bytes": 262144, + "max_units": 1000, + "arg_utf8_max": [ + 2048 + ] + }, + "error_codes": [ + { + "code": "INVALID_PATH", + "tag": "host/invalid_path" + }, + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + }, + { + "code": "NOT_FOUND", + "tag": "host/not_found" + } + ] + }, + { + "fn_id": 3, + "js_path": [ + "emit" + ], + "effect": "EMIT", + "arity": 1, + "arg_schema": [ + { + "type": "dv" + } + ], + "return_schema": { + "type": "null" + }, + "gas": { + "schedule_id": "emit-v1", + "base": 5, + "k_arg_bytes": 1, + "k_ret_bytes": 0, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 32768, + "max_response_bytes": 64, + "max_units": 1024 + }, + "error_codes": [ + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + } + ] + } + ] + } + }, + { + "id": "green-semver", + "title": "semver constraint evaluation", + "kind": "ecosystem-green", + "badge": "Green ecosystem fixture", + "description": "Semver constraint evaluation from the certified green ecosystem corpus.", + "certified": true, + "executionProfile": "compat-general-v1", + "sourceKind": "module-pack", + "abiId": "Host.v1", + "gasLimit": "1000000", + "sourcePaths": [ + "apps/ecosystem-certifier/fixtures/positive/semver-entry.ts" + ], + "sourceText": "import { satisfies, valid } from 'semver';\n\nconst version = Host.v1.document.get('text/semver-case');\nconst ranges = ['>=1.2.0 <2.0.0', '^1.2.0', '~1.2.3'];\n\nexport default {\n version,\n valid: valid(version) !== null,\n checks: ranges.map((range) => ({ range, ok: satisfies(version, range) })),\n};\n", + "hostPreset": "certification", + "hostSummary": { + "label": "Certification host", + "description": "Provides the ecosystem-certifier text and binary documents used for workload certification.", + "documents": [ + "pack/metadata.json", + "pack/metadata.yaml", + "docs/a.md", + "docs/b.md", + "docs/c.md", + "docs/d.md", + "bytes/payload", + "bytes/flagship-extra", + "pack/attachment.deflated" + ] + }, + "docsLinks": [ + { + "label": "Workload certification", + "href": "/docs/workload-certification.md" + }, + { + "label": "Compatibility report", + "href": "/docs/ecosystem-compatibility-report.md" + } + ], + "supportsOogSearch": false, + "program": { + "version": 2, + "abiId": "Host.v1", + "abiVersion": 1, + "abiManifestHash": "e23b0b2ee169900bbde7aff78e6ce20fead1715c60f8a8e3106d9959450a3d34", + "engineBuildHash": "f91091cb7feb788df340305a877a9cadb0c6f4d13aea8a7da4040b6367d178ea", + "gasVersion": 8, + "executionProfile": "compat-general-v1", + "sourceKind": "module-pack", + "source": { + "modulePack": { + "version": 1, + "entrySpecifier": "./semver-entry.js", + "entryExport": "default", + "modules": [ + { + "specifier": "./semver-entry.js", + "source": "var __create = Object.create;\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __getProtoOf = Object.getPrototypeOf;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __commonJS = (cb, mod) => function __require() {\n return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(\n // If the importer is in node compatibility mode or this is not an ESM\n // file that has been converted to a CommonJS file using a Babel-\n // compatible transform (i.e. \"__esModule\" has not been set), then set\n // \"default\" to the CommonJS \"module.exports\" for node compatibility.\n isNodeMode || !mod || !mod.__esModule ? __defProp(target, \"default\", { value: mod, enumerable: true }) : target,\n mod\n));\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/constants.js\nvar require_constants = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/constants.js\"(exports, module) {\n \"use strict\";\n var SEMVER_SPEC_VERSION = \"2.0.0\";\n var MAX_LENGTH = 256;\n var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || /* istanbul ignore next */\n 9007199254740991;\n var MAX_SAFE_COMPONENT_LENGTH = 16;\n var MAX_SAFE_BUILD_LENGTH = MAX_LENGTH - 6;\n var RELEASE_TYPES = [\n \"major\",\n \"premajor\",\n \"minor\",\n \"preminor\",\n \"patch\",\n \"prepatch\",\n \"prerelease\"\n ];\n module.exports = {\n MAX_LENGTH,\n MAX_SAFE_COMPONENT_LENGTH,\n MAX_SAFE_BUILD_LENGTH,\n MAX_SAFE_INTEGER,\n RELEASE_TYPES,\n SEMVER_SPEC_VERSION,\n FLAG_INCLUDE_PRERELEASE: 1,\n FLAG_LOOSE: 2\n };\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/debug.js\nvar require_debug = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/debug.js\"(exports, module) {\n \"use strict\";\n var debug = typeof process === \"object\" && process.env && process.env.NODE_DEBUG && /\\bsemver\\b/i.test(process.env.NODE_DEBUG) ? (...args) => console.error(\"SEMVER\", ...args) : () => {\n };\n module.exports = debug;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/re.js\nvar require_re = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/re.js\"(exports, module) {\n \"use strict\";\n var {\n MAX_SAFE_COMPONENT_LENGTH,\n MAX_SAFE_BUILD_LENGTH,\n MAX_LENGTH\n } = require_constants();\n var debug = require_debug();\n exports = module.exports = {};\n var re = exports.re = [];\n var safeRe = exports.safeRe = [];\n var src = exports.src = [];\n var safeSrc = exports.safeSrc = [];\n var t = exports.t = {};\n var R = 0;\n var LETTERDASHNUMBER = \"[a-zA-Z0-9-]\";\n var safeRegexReplacements = [\n [\"\\\\s\", 1],\n [\"\\\\d\", MAX_LENGTH],\n [LETTERDASHNUMBER, MAX_SAFE_BUILD_LENGTH]\n ];\n var makeSafeRegex = (value) => {\n for (const [token, max] of safeRegexReplacements) {\n value = value.split(`${token}*`).join(`${token}{0,${max}}`).split(`${token}+`).join(`${token}{1,${max}}`);\n }\n return value;\n };\n var createToken = (name, value, isGlobal) => {\n const safe = makeSafeRegex(value);\n const index = R++;\n debug(name, index, value);\n t[name] = index;\n src[index] = value;\n safeSrc[index] = safe;\n re[index] = new RegExp(value, isGlobal ? \"g\" : void 0);\n safeRe[index] = new RegExp(safe, isGlobal ? \"g\" : void 0);\n };\n createToken(\"NUMERICIDENTIFIER\", \"0|[1-9]\\\\d*\");\n createToken(\"NUMERICIDENTIFIERLOOSE\", \"\\\\d+\");\n createToken(\"NONNUMERICIDENTIFIER\", `\\\\d*[a-zA-Z-]${LETTERDASHNUMBER}*`);\n createToken(\"MAINVERSION\", `(${src[t.NUMERICIDENTIFIER]})\\\\.(${src[t.NUMERICIDENTIFIER]})\\\\.(${src[t.NUMERICIDENTIFIER]})`);\n createToken(\"MAINVERSIONLOOSE\", `(${src[t.NUMERICIDENTIFIERLOOSE]})\\\\.(${src[t.NUMERICIDENTIFIERLOOSE]})\\\\.(${src[t.NUMERICIDENTIFIERLOOSE]})`);\n createToken(\"PRERELEASEIDENTIFIER\", `(?:${src[t.NONNUMERICIDENTIFIER]}|${src[t.NUMERICIDENTIFIER]})`);\n createToken(\"PRERELEASEIDENTIFIERLOOSE\", `(?:${src[t.NONNUMERICIDENTIFIER]}|${src[t.NUMERICIDENTIFIERLOOSE]})`);\n createToken(\"PRERELEASE\", `(?:-(${src[t.PRERELEASEIDENTIFIER]}(?:\\\\.${src[t.PRERELEASEIDENTIFIER]})*))`);\n createToken(\"PRERELEASELOOSE\", `(?:-?(${src[t.PRERELEASEIDENTIFIERLOOSE]}(?:\\\\.${src[t.PRERELEASEIDENTIFIERLOOSE]})*))`);\n createToken(\"BUILDIDENTIFIER\", `${LETTERDASHNUMBER}+`);\n createToken(\"BUILD\", `(?:\\\\+(${src[t.BUILDIDENTIFIER]}(?:\\\\.${src[t.BUILDIDENTIFIER]})*))`);\n createToken(\"FULLPLAIN\", `v?${src[t.MAINVERSION]}${src[t.PRERELEASE]}?${src[t.BUILD]}?`);\n createToken(\"FULL\", `^${src[t.FULLPLAIN]}$`);\n createToken(\"LOOSEPLAIN\", `[v=\\\\s]*${src[t.MAINVERSIONLOOSE]}${src[t.PRERELEASELOOSE]}?${src[t.BUILD]}?`);\n createToken(\"LOOSE\", `^${src[t.LOOSEPLAIN]}$`);\n createToken(\"GTLT\", \"((?:<|>)?=?)\");\n createToken(\"XRANGEIDENTIFIERLOOSE\", `${src[t.NUMERICIDENTIFIERLOOSE]}|x|X|\\\\*`);\n createToken(\"XRANGEIDENTIFIER\", `${src[t.NUMERICIDENTIFIER]}|x|X|\\\\*`);\n createToken(\"XRANGEPLAIN\", `[v=\\\\s]*(${src[t.XRANGEIDENTIFIER]})(?:\\\\.(${src[t.XRANGEIDENTIFIER]})(?:\\\\.(${src[t.XRANGEIDENTIFIER]})(?:${src[t.PRERELEASE]})?${src[t.BUILD]}?)?)?`);\n createToken(\"XRANGEPLAINLOOSE\", `[v=\\\\s]*(${src[t.XRANGEIDENTIFIERLOOSE]})(?:\\\\.(${src[t.XRANGEIDENTIFIERLOOSE]})(?:\\\\.(${src[t.XRANGEIDENTIFIERLOOSE]})(?:${src[t.PRERELEASELOOSE]})?${src[t.BUILD]}?)?)?`);\n createToken(\"XRANGE\", `^${src[t.GTLT]}\\\\s*${src[t.XRANGEPLAIN]}$`);\n createToken(\"XRANGELOOSE\", `^${src[t.GTLT]}\\\\s*${src[t.XRANGEPLAINLOOSE]}$`);\n createToken(\"COERCEPLAIN\", `${\"(^|[^\\\\d])(\\\\d{1,\"}${MAX_SAFE_COMPONENT_LENGTH}})(?:\\\\.(\\\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?(?:\\\\.(\\\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?`);\n createToken(\"COERCE\", `${src[t.COERCEPLAIN]}(?:$|[^\\\\d])`);\n createToken(\"COERCEFULL\", src[t.COERCEPLAIN] + `(?:${src[t.PRERELEASE]})?(?:${src[t.BUILD]})?(?:$|[^\\\\d])`);\n createToken(\"COERCERTL\", src[t.COERCE], true);\n createToken(\"COERCERTLFULL\", src[t.COERCEFULL], true);\n createToken(\"LONETILDE\", \"(?:~>?)\");\n createToken(\"TILDETRIM\", `(\\\\s*)${src[t.LONETILDE]}\\\\s+`, true);\n exports.tildeTrimReplace = \"$1~\";\n createToken(\"TILDE\", `^${src[t.LONETILDE]}${src[t.XRANGEPLAIN]}$`);\n createToken(\"TILDELOOSE\", `^${src[t.LONETILDE]}${src[t.XRANGEPLAINLOOSE]}$`);\n createToken(\"LONECARET\", \"(?:\\\\^)\");\n createToken(\"CARETTRIM\", `(\\\\s*)${src[t.LONECARET]}\\\\s+`, true);\n exports.caretTrimReplace = \"$1^\";\n createToken(\"CARET\", `^${src[t.LONECARET]}${src[t.XRANGEPLAIN]}$`);\n createToken(\"CARETLOOSE\", `^${src[t.LONECARET]}${src[t.XRANGEPLAINLOOSE]}$`);\n createToken(\"COMPARATORLOOSE\", `^${src[t.GTLT]}\\\\s*(${src[t.LOOSEPLAIN]})$|^$`);\n createToken(\"COMPARATOR\", `^${src[t.GTLT]}\\\\s*(${src[t.FULLPLAIN]})$|^$`);\n createToken(\"COMPARATORTRIM\", `(\\\\s*)${src[t.GTLT]}\\\\s*(${src[t.LOOSEPLAIN]}|${src[t.XRANGEPLAIN]})`, true);\n exports.comparatorTrimReplace = \"$1$2$3\";\n createToken(\"HYPHENRANGE\", `^\\\\s*(${src[t.XRANGEPLAIN]})\\\\s+-\\\\s+(${src[t.XRANGEPLAIN]})\\\\s*$`);\n createToken(\"HYPHENRANGELOOSE\", `^\\\\s*(${src[t.XRANGEPLAINLOOSE]})\\\\s+-\\\\s+(${src[t.XRANGEPLAINLOOSE]})\\\\s*$`);\n createToken(\"STAR\", \"(<|>)?=?\\\\s*\\\\*\");\n createToken(\"GTE0\", \"^\\\\s*>=\\\\s*0\\\\.0\\\\.0\\\\s*$\");\n createToken(\"GTE0PRE\", \"^\\\\s*>=\\\\s*0\\\\.0\\\\.0-0\\\\s*$\");\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/parse-options.js\nvar require_parse_options = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/parse-options.js\"(exports, module) {\n \"use strict\";\n var looseOption = Object.freeze({ loose: true });\n var emptyOpts = Object.freeze({});\n var parseOptions = (options) => {\n if (!options) {\n return emptyOpts;\n }\n if (typeof options !== \"object\") {\n return looseOption;\n }\n return options;\n };\n module.exports = parseOptions;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/identifiers.js\nvar require_identifiers = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/identifiers.js\"(exports, module) {\n \"use strict\";\n var numeric = /^[0-9]+$/;\n var compareIdentifiers = (a, b) => {\n if (typeof a === \"number\" && typeof b === \"number\") {\n return a === b ? 0 : a < b ? -1 : 1;\n }\n const anum = numeric.test(a);\n const bnum = numeric.test(b);\n if (anum && bnum) {\n a = +a;\n b = +b;\n }\n return a === b ? 0 : anum && !bnum ? -1 : bnum && !anum ? 1 : a < b ? -1 : 1;\n };\n var rcompareIdentifiers = (a, b) => compareIdentifiers(b, a);\n module.exports = {\n compareIdentifiers,\n rcompareIdentifiers\n };\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/classes/semver.js\nvar require_semver = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/classes/semver.js\"(exports, module) {\n \"use strict\";\n var debug = require_debug();\n var { MAX_LENGTH, MAX_SAFE_INTEGER } = require_constants();\n var { safeRe: re, t } = require_re();\n var parseOptions = require_parse_options();\n var { compareIdentifiers } = require_identifiers();\n var SemVer = class _SemVer {\n constructor(version2, options) {\n options = parseOptions(options);\n if (version2 instanceof _SemVer) {\n if (version2.loose === !!options.loose && version2.includePrerelease === !!options.includePrerelease) {\n return version2;\n } else {\n version2 = version2.version;\n }\n } else if (typeof version2 !== \"string\") {\n throw new TypeError(`Invalid version. Must be a string. Got type \"${typeof version2}\".`);\n }\n if (version2.length > MAX_LENGTH) {\n throw new TypeError(\n `version is longer than ${MAX_LENGTH} characters`\n );\n }\n debug(\"SemVer\", version2, options);\n this.options = options;\n this.loose = !!options.loose;\n this.includePrerelease = !!options.includePrerelease;\n const m = version2.trim().match(options.loose ? re[t.LOOSE] : re[t.FULL]);\n if (!m) {\n throw new TypeError(`Invalid Version: ${version2}`);\n }\n this.raw = version2;\n this.major = +m[1];\n this.minor = +m[2];\n this.patch = +m[3];\n if (this.major > MAX_SAFE_INTEGER || this.major < 0) {\n throw new TypeError(\"Invalid major version\");\n }\n if (this.minor > MAX_SAFE_INTEGER || this.minor < 0) {\n throw new TypeError(\"Invalid minor version\");\n }\n if (this.patch > MAX_SAFE_INTEGER || this.patch < 0) {\n throw new TypeError(\"Invalid patch version\");\n }\n if (!m[4]) {\n this.prerelease = [];\n } else {\n this.prerelease = m[4].split(\".\").map((id) => {\n if (/^[0-9]+$/.test(id)) {\n const num = +id;\n if (num >= 0 && num < MAX_SAFE_INTEGER) {\n return num;\n }\n }\n return id;\n });\n }\n this.build = m[5] ? m[5].split(\".\") : [];\n this.format();\n }\n format() {\n this.version = `${this.major}.${this.minor}.${this.patch}`;\n if (this.prerelease.length) {\n this.version += `-${this.prerelease.join(\".\")}`;\n }\n return this.version;\n }\n toString() {\n return this.version;\n }\n compare(other) {\n debug(\"SemVer.compare\", this.version, this.options, other);\n if (!(other instanceof _SemVer)) {\n if (typeof other === \"string\" && other === this.version) {\n return 0;\n }\n other = new _SemVer(other, this.options);\n }\n if (other.version === this.version) {\n return 0;\n }\n return this.compareMain(other) || this.comparePre(other);\n }\n compareMain(other) {\n if (!(other instanceof _SemVer)) {\n other = new _SemVer(other, this.options);\n }\n if (this.major < other.major) {\n return -1;\n }\n if (this.major > other.major) {\n return 1;\n }\n if (this.minor < other.minor) {\n return -1;\n }\n if (this.minor > other.minor) {\n return 1;\n }\n if (this.patch < other.patch) {\n return -1;\n }\n if (this.patch > other.patch) {\n return 1;\n }\n return 0;\n }\n comparePre(other) {\n if (!(other instanceof _SemVer)) {\n other = new _SemVer(other, this.options);\n }\n if (this.prerelease.length && !other.prerelease.length) {\n return -1;\n } else if (!this.prerelease.length && other.prerelease.length) {\n return 1;\n } else if (!this.prerelease.length && !other.prerelease.length) {\n return 0;\n }\n let i = 0;\n do {\n const a = this.prerelease[i];\n const b = other.prerelease[i];\n debug(\"prerelease compare\", i, a, b);\n if (a === void 0 && b === void 0) {\n return 0;\n } else if (b === void 0) {\n return 1;\n } else if (a === void 0) {\n return -1;\n } else if (a === b) {\n continue;\n } else {\n return compareIdentifiers(a, b);\n }\n } while (++i);\n }\n compareBuild(other) {\n if (!(other instanceof _SemVer)) {\n other = new _SemVer(other, this.options);\n }\n let i = 0;\n do {\n const a = this.build[i];\n const b = other.build[i];\n debug(\"build compare\", i, a, b);\n if (a === void 0 && b === void 0) {\n return 0;\n } else if (b === void 0) {\n return 1;\n } else if (a === void 0) {\n return -1;\n } else if (a === b) {\n continue;\n } else {\n return compareIdentifiers(a, b);\n }\n } while (++i);\n }\n // preminor will bump the version up to the next minor release, and immediately\n // down to pre-release. premajor and prepatch work the same way.\n inc(release, identifier, identifierBase) {\n if (release.startsWith(\"pre\")) {\n if (!identifier && identifierBase === false) {\n throw new Error(\"invalid increment argument: identifier is empty\");\n }\n if (identifier) {\n const match = `-${identifier}`.match(this.options.loose ? re[t.PRERELEASELOOSE] : re[t.PRERELEASE]);\n if (!match || match[1] !== identifier) {\n throw new Error(`invalid identifier: ${identifier}`);\n }\n }\n }\n switch (release) {\n case \"premajor\":\n this.prerelease.length = 0;\n this.patch = 0;\n this.minor = 0;\n this.major++;\n this.inc(\"pre\", identifier, identifierBase);\n break;\n case \"preminor\":\n this.prerelease.length = 0;\n this.patch = 0;\n this.minor++;\n this.inc(\"pre\", identifier, identifierBase);\n break;\n case \"prepatch\":\n this.prerelease.length = 0;\n this.inc(\"patch\", identifier, identifierBase);\n this.inc(\"pre\", identifier, identifierBase);\n break;\n // If the input is a non-prerelease version, this acts the same as\n // prepatch.\n case \"prerelease\":\n if (this.prerelease.length === 0) {\n this.inc(\"patch\", identifier, identifierBase);\n }\n this.inc(\"pre\", identifier, identifierBase);\n break;\n case \"release\":\n if (this.prerelease.length === 0) {\n throw new Error(`version ${this.raw} is not a prerelease`);\n }\n this.prerelease.length = 0;\n break;\n case \"major\":\n if (this.minor !== 0 || this.patch !== 0 || this.prerelease.length === 0) {\n this.major++;\n }\n this.minor = 0;\n this.patch = 0;\n this.prerelease = [];\n break;\n case \"minor\":\n if (this.patch !== 0 || this.prerelease.length === 0) {\n this.minor++;\n }\n this.patch = 0;\n this.prerelease = [];\n break;\n case \"patch\":\n if (this.prerelease.length === 0) {\n this.patch++;\n }\n this.prerelease = [];\n break;\n // This probably shouldn't be used publicly.\n // 1.0.0 'pre' would become 1.0.0-0 which is the wrong direction.\n case \"pre\": {\n const base = Number(identifierBase) ? 1 : 0;\n if (this.prerelease.length === 0) {\n this.prerelease = [base];\n } else {\n let i = this.prerelease.length;\n while (--i >= 0) {\n if (typeof this.prerelease[i] === \"number\") {\n this.prerelease[i]++;\n i = -2;\n }\n }\n if (i === -1) {\n if (identifier === this.prerelease.join(\".\") && identifierBase === false) {\n throw new Error(\"invalid increment argument: identifier already exists\");\n }\n this.prerelease.push(base);\n }\n }\n if (identifier) {\n let prerelease = [identifier, base];\n if (identifierBase === false) {\n prerelease = [identifier];\n }\n if (compareIdentifiers(this.prerelease[0], identifier) === 0) {\n if (isNaN(this.prerelease[1])) {\n this.prerelease = prerelease;\n }\n } else {\n this.prerelease = prerelease;\n }\n }\n break;\n }\n default:\n throw new Error(`invalid increment argument: ${release}`);\n }\n this.raw = this.format();\n if (this.build.length) {\n this.raw += `+${this.build.join(\".\")}`;\n }\n return this;\n }\n };\n module.exports = SemVer;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/parse.js\nvar require_parse = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/parse.js\"(exports, module) {\n \"use strict\";\n var SemVer = require_semver();\n var parse = (version2, options, throwErrors = false) => {\n if (version2 instanceof SemVer) {\n return version2;\n }\n try {\n return new SemVer(version2, options);\n } catch (er) {\n if (!throwErrors) {\n return null;\n }\n throw er;\n }\n };\n module.exports = parse;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/valid.js\nvar require_valid = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/valid.js\"(exports, module) {\n \"use strict\";\n var parse = require_parse();\n var valid2 = (version2, options) => {\n const v = parse(version2, options);\n return v ? v.version : null;\n };\n module.exports = valid2;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/clean.js\nvar require_clean = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/clean.js\"(exports, module) {\n \"use strict\";\n var parse = require_parse();\n var clean = (version2, options) => {\n const s = parse(version2.trim().replace(/^[=v]+/, \"\"), options);\n return s ? s.version : null;\n };\n module.exports = clean;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/inc.js\nvar require_inc = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/inc.js\"(exports, module) {\n \"use strict\";\n var SemVer = require_semver();\n var inc = (version2, release, options, identifier, identifierBase) => {\n if (typeof options === \"string\") {\n identifierBase = identifier;\n identifier = options;\n options = void 0;\n }\n try {\n return new SemVer(\n version2 instanceof SemVer ? version2.version : version2,\n options\n ).inc(release, identifier, identifierBase).version;\n } catch (er) {\n return null;\n }\n };\n module.exports = inc;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/diff.js\nvar require_diff = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/diff.js\"(exports, module) {\n \"use strict\";\n var parse = require_parse();\n var diff = (version1, version2) => {\n const v1 = parse(version1, null, true);\n const v2 = parse(version2, null, true);\n const comparison = v1.compare(v2);\n if (comparison === 0) {\n return null;\n }\n const v1Higher = comparison > 0;\n const highVersion = v1Higher ? v1 : v2;\n const lowVersion = v1Higher ? v2 : v1;\n const highHasPre = !!highVersion.prerelease.length;\n const lowHasPre = !!lowVersion.prerelease.length;\n if (lowHasPre && !highHasPre) {\n if (!lowVersion.patch && !lowVersion.minor) {\n return \"major\";\n }\n if (lowVersion.compareMain(highVersion) === 0) {\n if (lowVersion.minor && !lowVersion.patch) {\n return \"minor\";\n }\n return \"patch\";\n }\n }\n const prefix = highHasPre ? \"pre\" : \"\";\n if (v1.major !== v2.major) {\n return prefix + \"major\";\n }\n if (v1.minor !== v2.minor) {\n return prefix + \"minor\";\n }\n if (v1.patch !== v2.patch) {\n return prefix + \"patch\";\n }\n return \"prerelease\";\n };\n module.exports = diff;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/major.js\nvar require_major = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/major.js\"(exports, module) {\n \"use strict\";\n var SemVer = require_semver();\n var major = (a, loose) => new SemVer(a, loose).major;\n module.exports = major;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/minor.js\nvar require_minor = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/minor.js\"(exports, module) {\n \"use strict\";\n var SemVer = require_semver();\n var minor = (a, loose) => new SemVer(a, loose).minor;\n module.exports = minor;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/patch.js\nvar require_patch = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/patch.js\"(exports, module) {\n \"use strict\";\n var SemVer = require_semver();\n var patch = (a, loose) => new SemVer(a, loose).patch;\n module.exports = patch;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/prerelease.js\nvar require_prerelease = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/prerelease.js\"(exports, module) {\n \"use strict\";\n var parse = require_parse();\n var prerelease = (version2, options) => {\n const parsed = parse(version2, options);\n return parsed && parsed.prerelease.length ? parsed.prerelease : null;\n };\n module.exports = prerelease;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/compare.js\nvar require_compare = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/compare.js\"(exports, module) {\n \"use strict\";\n var SemVer = require_semver();\n var compare = (a, b, loose) => new SemVer(a, loose).compare(new SemVer(b, loose));\n module.exports = compare;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/rcompare.js\nvar require_rcompare = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/rcompare.js\"(exports, module) {\n \"use strict\";\n var compare = require_compare();\n var rcompare = (a, b, loose) => compare(b, a, loose);\n module.exports = rcompare;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/compare-loose.js\nvar require_compare_loose = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/compare-loose.js\"(exports, module) {\n \"use strict\";\n var compare = require_compare();\n var compareLoose = (a, b) => compare(a, b, true);\n module.exports = compareLoose;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/compare-build.js\nvar require_compare_build = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/compare-build.js\"(exports, module) {\n \"use strict\";\n var SemVer = require_semver();\n var compareBuild = (a, b, loose) => {\n const versionA = new SemVer(a, loose);\n const versionB = new SemVer(b, loose);\n return versionA.compare(versionB) || versionA.compareBuild(versionB);\n };\n module.exports = compareBuild;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/sort.js\nvar require_sort = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/sort.js\"(exports, module) {\n \"use strict\";\n var compareBuild = require_compare_build();\n var sort = (list, loose) => list.sort((a, b) => compareBuild(a, b, loose));\n module.exports = sort;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/rsort.js\nvar require_rsort = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/rsort.js\"(exports, module) {\n \"use strict\";\n var compareBuild = require_compare_build();\n var rsort = (list, loose) => list.sort((a, b) => compareBuild(b, a, loose));\n module.exports = rsort;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/gt.js\nvar require_gt = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/gt.js\"(exports, module) {\n \"use strict\";\n var compare = require_compare();\n var gt = (a, b, loose) => compare(a, b, loose) > 0;\n module.exports = gt;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/lt.js\nvar require_lt = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/lt.js\"(exports, module) {\n \"use strict\";\n var compare = require_compare();\n var lt = (a, b, loose) => compare(a, b, loose) < 0;\n module.exports = lt;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/eq.js\nvar require_eq = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/eq.js\"(exports, module) {\n \"use strict\";\n var compare = require_compare();\n var eq = (a, b, loose) => compare(a, b, loose) === 0;\n module.exports = eq;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/neq.js\nvar require_neq = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/neq.js\"(exports, module) {\n \"use strict\";\n var compare = require_compare();\n var neq = (a, b, loose) => compare(a, b, loose) !== 0;\n module.exports = neq;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/gte.js\nvar require_gte = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/gte.js\"(exports, module) {\n \"use strict\";\n var compare = require_compare();\n var gte = (a, b, loose) => compare(a, b, loose) >= 0;\n module.exports = gte;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/lte.js\nvar require_lte = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/lte.js\"(exports, module) {\n \"use strict\";\n var compare = require_compare();\n var lte = (a, b, loose) => compare(a, b, loose) <= 0;\n module.exports = lte;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/cmp.js\nvar require_cmp = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/cmp.js\"(exports, module) {\n \"use strict\";\n var eq = require_eq();\n var neq = require_neq();\n var gt = require_gt();\n var gte = require_gte();\n var lt = require_lt();\n var lte = require_lte();\n var cmp = (a, op, b, loose) => {\n switch (op) {\n case \"===\":\n if (typeof a === \"object\") {\n a = a.version;\n }\n if (typeof b === \"object\") {\n b = b.version;\n }\n return a === b;\n case \"!==\":\n if (typeof a === \"object\") {\n a = a.version;\n }\n if (typeof b === \"object\") {\n b = b.version;\n }\n return a !== b;\n case \"\":\n case \"=\":\n case \"==\":\n return eq(a, b, loose);\n case \"!=\":\n return neq(a, b, loose);\n case \">\":\n return gt(a, b, loose);\n case \">=\":\n return gte(a, b, loose);\n case \"<\":\n return lt(a, b, loose);\n case \"<=\":\n return lte(a, b, loose);\n default:\n throw new TypeError(`Invalid operator: ${op}`);\n }\n };\n module.exports = cmp;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/coerce.js\nvar require_coerce = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/coerce.js\"(exports, module) {\n \"use strict\";\n var SemVer = require_semver();\n var parse = require_parse();\n var { safeRe: re, t } = require_re();\n var coerce = (version2, options) => {\n if (version2 instanceof SemVer) {\n return version2;\n }\n if (typeof version2 === \"number\") {\n version2 = String(version2);\n }\n if (typeof version2 !== \"string\") {\n return null;\n }\n options = options || {};\n let match = null;\n if (!options.rtl) {\n match = version2.match(options.includePrerelease ? re[t.COERCEFULL] : re[t.COERCE]);\n } else {\n const coerceRtlRegex = options.includePrerelease ? re[t.COERCERTLFULL] : re[t.COERCERTL];\n let next;\n while ((next = coerceRtlRegex.exec(version2)) && (!match || match.index + match[0].length !== version2.length)) {\n if (!match || next.index + next[0].length !== match.index + match[0].length) {\n match = next;\n }\n coerceRtlRegex.lastIndex = next.index + next[1].length + next[2].length;\n }\n coerceRtlRegex.lastIndex = -1;\n }\n if (match === null) {\n return null;\n }\n const major = match[2];\n const minor = match[3] || \"0\";\n const patch = match[4] || \"0\";\n const prerelease = options.includePrerelease && match[5] ? `-${match[5]}` : \"\";\n const build = options.includePrerelease && match[6] ? `+${match[6]}` : \"\";\n return parse(`${major}.${minor}.${patch}${prerelease}${build}`, options);\n };\n module.exports = coerce;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/lrucache.js\nvar require_lrucache = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/lrucache.js\"(exports, module) {\n \"use strict\";\n var LRUCache = class {\n constructor() {\n this.max = 1e3;\n this.map = /* @__PURE__ */ new Map();\n }\n get(key) {\n const value = this.map.get(key);\n if (value === void 0) {\n return void 0;\n } else {\n this.map.delete(key);\n this.map.set(key, value);\n return value;\n }\n }\n delete(key) {\n return this.map.delete(key);\n }\n set(key, value) {\n const deleted = this.delete(key);\n if (!deleted && value !== void 0) {\n if (this.map.size >= this.max) {\n const firstKey = this.map.keys().next().value;\n this.delete(firstKey);\n }\n this.map.set(key, value);\n }\n return this;\n }\n };\n module.exports = LRUCache;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/classes/range.js\nvar require_range = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/classes/range.js\"(exports, module) {\n \"use strict\";\n var SPACE_CHARACTERS = /\\s+/g;\n var Range = class _Range {\n constructor(range, options) {\n options = parseOptions(options);\n if (range instanceof _Range) {\n if (range.loose === !!options.loose && range.includePrerelease === !!options.includePrerelease) {\n return range;\n } else {\n return new _Range(range.raw, options);\n }\n }\n if (range instanceof Comparator) {\n this.raw = range.value;\n this.set = [[range]];\n this.formatted = void 0;\n return this;\n }\n this.options = options;\n this.loose = !!options.loose;\n this.includePrerelease = !!options.includePrerelease;\n this.raw = range.trim().replace(SPACE_CHARACTERS, \" \");\n this.set = this.raw.split(\"||\").map((r) => this.parseRange(r.trim())).filter((c) => c.length);\n if (!this.set.length) {\n throw new TypeError(`Invalid SemVer Range: ${this.raw}`);\n }\n if (this.set.length > 1) {\n const first = this.set[0];\n this.set = this.set.filter((c) => !isNullSet(c[0]));\n if (this.set.length === 0) {\n this.set = [first];\n } else if (this.set.length > 1) {\n for (const c of this.set) {\n if (c.length === 1 && isAny(c[0])) {\n this.set = [c];\n break;\n }\n }\n }\n }\n this.formatted = void 0;\n }\n get range() {\n if (this.formatted === void 0) {\n this.formatted = \"\";\n for (let i = 0; i < this.set.length; i++) {\n if (i > 0) {\n this.formatted += \"||\";\n }\n const comps = this.set[i];\n for (let k = 0; k < comps.length; k++) {\n if (k > 0) {\n this.formatted += \" \";\n }\n this.formatted += comps[k].toString().trim();\n }\n }\n }\n return this.formatted;\n }\n format() {\n return this.range;\n }\n toString() {\n return this.range;\n }\n parseRange(range) {\n const memoOpts = (this.options.includePrerelease && FLAG_INCLUDE_PRERELEASE) | (this.options.loose && FLAG_LOOSE);\n const memoKey = memoOpts + \":\" + range;\n const cached = cache.get(memoKey);\n if (cached) {\n return cached;\n }\n const loose = this.options.loose;\n const hr = loose ? re[t.HYPHENRANGELOOSE] : re[t.HYPHENRANGE];\n range = range.replace(hr, hyphenReplace(this.options.includePrerelease));\n debug(\"hyphen replace\", range);\n range = range.replace(re[t.COMPARATORTRIM], comparatorTrimReplace);\n debug(\"comparator trim\", range);\n range = range.replace(re[t.TILDETRIM], tildeTrimReplace);\n debug(\"tilde trim\", range);\n range = range.replace(re[t.CARETTRIM], caretTrimReplace);\n debug(\"caret trim\", range);\n let rangeList = range.split(\" \").map((comp) => parseComparator(comp, this.options)).join(\" \").split(/\\s+/).map((comp) => replaceGTE0(comp, this.options));\n if (loose) {\n rangeList = rangeList.filter((comp) => {\n debug(\"loose invalid filter\", comp, this.options);\n return !!comp.match(re[t.COMPARATORLOOSE]);\n });\n }\n debug(\"range list\", rangeList);\n const rangeMap = /* @__PURE__ */ new Map();\n const comparators = rangeList.map((comp) => new Comparator(comp, this.options));\n for (const comp of comparators) {\n if (isNullSet(comp)) {\n return [comp];\n }\n rangeMap.set(comp.value, comp);\n }\n if (rangeMap.size > 1 && rangeMap.has(\"\")) {\n rangeMap.delete(\"\");\n }\n const result = [...rangeMap.values()];\n cache.set(memoKey, result);\n return result;\n }\n intersects(range, options) {\n if (!(range instanceof _Range)) {\n throw new TypeError(\"a Range is required\");\n }\n return this.set.some((thisComparators) => {\n return isSatisfiable(thisComparators, options) && range.set.some((rangeComparators) => {\n return isSatisfiable(rangeComparators, options) && thisComparators.every((thisComparator) => {\n return rangeComparators.every((rangeComparator) => {\n return thisComparator.intersects(rangeComparator, options);\n });\n });\n });\n });\n }\n // if ANY of the sets match ALL of its comparators, then pass\n test(version2) {\n if (!version2) {\n return false;\n }\n if (typeof version2 === \"string\") {\n try {\n version2 = new SemVer(version2, this.options);\n } catch (er) {\n return false;\n }\n }\n for (let i = 0; i < this.set.length; i++) {\n if (testSet(this.set[i], version2, this.options)) {\n return true;\n }\n }\n return false;\n }\n };\n module.exports = Range;\n var LRU = require_lrucache();\n var cache = new LRU();\n var parseOptions = require_parse_options();\n var Comparator = require_comparator();\n var debug = require_debug();\n var SemVer = require_semver();\n var {\n safeRe: re,\n t,\n comparatorTrimReplace,\n tildeTrimReplace,\n caretTrimReplace\n } = require_re();\n var { FLAG_INCLUDE_PRERELEASE, FLAG_LOOSE } = require_constants();\n var isNullSet = (c) => c.value === \"<0.0.0-0\";\n var isAny = (c) => c.value === \"\";\n var isSatisfiable = (comparators, options) => {\n let result = true;\n const remainingComparators = comparators.slice();\n let testComparator = remainingComparators.pop();\n while (result && remainingComparators.length) {\n result = remainingComparators.every((otherComparator) => {\n return testComparator.intersects(otherComparator, options);\n });\n testComparator = remainingComparators.pop();\n }\n return result;\n };\n var parseComparator = (comp, options) => {\n comp = comp.replace(re[t.BUILD], \"\");\n debug(\"comp\", comp, options);\n comp = replaceCarets(comp, options);\n debug(\"caret\", comp);\n comp = replaceTildes(comp, options);\n debug(\"tildes\", comp);\n comp = replaceXRanges(comp, options);\n debug(\"xrange\", comp);\n comp = replaceStars(comp, options);\n debug(\"stars\", comp);\n return comp;\n };\n var isX = (id) => !id || id.toLowerCase() === \"x\" || id === \"*\";\n var replaceTildes = (comp, options) => {\n return comp.trim().split(/\\s+/).map((c) => replaceTilde(c, options)).join(\" \");\n };\n var replaceTilde = (comp, options) => {\n const r = options.loose ? re[t.TILDELOOSE] : re[t.TILDE];\n return comp.replace(r, (_, M, m, p, pr) => {\n debug(\"tilde\", comp, _, M, m, p, pr);\n let ret;\n if (isX(M)) {\n ret = \"\";\n } else if (isX(m)) {\n ret = `>=${M}.0.0 <${+M + 1}.0.0-0`;\n } else if (isX(p)) {\n ret = `>=${M}.${m}.0 <${M}.${+m + 1}.0-0`;\n } else if (pr) {\n debug(\"replaceTilde pr\", pr);\n ret = `>=${M}.${m}.${p}-${pr} <${M}.${+m + 1}.0-0`;\n } else {\n ret = `>=${M}.${m}.${p} <${M}.${+m + 1}.0-0`;\n }\n debug(\"tilde return\", ret);\n return ret;\n });\n };\n var replaceCarets = (comp, options) => {\n return comp.trim().split(/\\s+/).map((c) => replaceCaret(c, options)).join(\" \");\n };\n var replaceCaret = (comp, options) => {\n debug(\"caret\", comp, options);\n const r = options.loose ? re[t.CARETLOOSE] : re[t.CARET];\n const z = options.includePrerelease ? \"-0\" : \"\";\n return comp.replace(r, (_, M, m, p, pr) => {\n debug(\"caret\", comp, _, M, m, p, pr);\n let ret;\n if (isX(M)) {\n ret = \"\";\n } else if (isX(m)) {\n ret = `>=${M}.0.0${z} <${+M + 1}.0.0-0`;\n } else if (isX(p)) {\n if (M === \"0\") {\n ret = `>=${M}.${m}.0${z} <${M}.${+m + 1}.0-0`;\n } else {\n ret = `>=${M}.${m}.0${z} <${+M + 1}.0.0-0`;\n }\n } else if (pr) {\n debug(\"replaceCaret pr\", pr);\n if (M === \"0\") {\n if (m === \"0\") {\n ret = `>=${M}.${m}.${p}-${pr} <${M}.${m}.${+p + 1}-0`;\n } else {\n ret = `>=${M}.${m}.${p}-${pr} <${M}.${+m + 1}.0-0`;\n }\n } else {\n ret = `>=${M}.${m}.${p}-${pr} <${+M + 1}.0.0-0`;\n }\n } else {\n debug(\"no pr\");\n if (M === \"0\") {\n if (m === \"0\") {\n ret = `>=${M}.${m}.${p}${z} <${M}.${m}.${+p + 1}-0`;\n } else {\n ret = `>=${M}.${m}.${p}${z} <${M}.${+m + 1}.0-0`;\n }\n } else {\n ret = `>=${M}.${m}.${p} <${+M + 1}.0.0-0`;\n }\n }\n debug(\"caret return\", ret);\n return ret;\n });\n };\n var replaceXRanges = (comp, options) => {\n debug(\"replaceXRanges\", comp, options);\n return comp.split(/\\s+/).map((c) => replaceXRange(c, options)).join(\" \");\n };\n var replaceXRange = (comp, options) => {\n comp = comp.trim();\n const r = options.loose ? re[t.XRANGELOOSE] : re[t.XRANGE];\n return comp.replace(r, (ret, gtlt, M, m, p, pr) => {\n debug(\"xRange\", comp, ret, gtlt, M, m, p, pr);\n const xM = isX(M);\n const xm = xM || isX(m);\n const xp = xm || isX(p);\n const anyX = xp;\n if (gtlt === \"=\" && anyX) {\n gtlt = \"\";\n }\n pr = options.includePrerelease ? \"-0\" : \"\";\n if (xM) {\n if (gtlt === \">\" || gtlt === \"<\") {\n ret = \"<0.0.0-0\";\n } else {\n ret = \"*\";\n }\n } else if (gtlt && anyX) {\n if (xm) {\n m = 0;\n }\n p = 0;\n if (gtlt === \">\") {\n gtlt = \">=\";\n if (xm) {\n M = +M + 1;\n m = 0;\n p = 0;\n } else {\n m = +m + 1;\n p = 0;\n }\n } else if (gtlt === \"<=\") {\n gtlt = \"<\";\n if (xm) {\n M = +M + 1;\n } else {\n m = +m + 1;\n }\n }\n if (gtlt === \"<\") {\n pr = \"-0\";\n }\n ret = `${gtlt + M}.${m}.${p}${pr}`;\n } else if (xm) {\n ret = `>=${M}.0.0${pr} <${+M + 1}.0.0-0`;\n } else if (xp) {\n ret = `>=${M}.${m}.0${pr} <${M}.${+m + 1}.0-0`;\n }\n debug(\"xRange return\", ret);\n return ret;\n });\n };\n var replaceStars = (comp, options) => {\n debug(\"replaceStars\", comp, options);\n return comp.trim().replace(re[t.STAR], \"\");\n };\n var replaceGTE0 = (comp, options) => {\n debug(\"replaceGTE0\", comp, options);\n return comp.trim().replace(re[options.includePrerelease ? t.GTE0PRE : t.GTE0], \"\");\n };\n var hyphenReplace = (incPr) => ($0, from, fM, fm, fp, fpr, fb, to, tM, tm, tp, tpr) => {\n if (isX(fM)) {\n from = \"\";\n } else if (isX(fm)) {\n from = `>=${fM}.0.0${incPr ? \"-0\" : \"\"}`;\n } else if (isX(fp)) {\n from = `>=${fM}.${fm}.0${incPr ? \"-0\" : \"\"}`;\n } else if (fpr) {\n from = `>=${from}`;\n } else {\n from = `>=${from}${incPr ? \"-0\" : \"\"}`;\n }\n if (isX(tM)) {\n to = \"\";\n } else if (isX(tm)) {\n to = `<${+tM + 1}.0.0-0`;\n } else if (isX(tp)) {\n to = `<${tM}.${+tm + 1}.0-0`;\n } else if (tpr) {\n to = `<=${tM}.${tm}.${tp}-${tpr}`;\n } else if (incPr) {\n to = `<${tM}.${tm}.${+tp + 1}-0`;\n } else {\n to = `<=${to}`;\n }\n return `${from} ${to}`.trim();\n };\n var testSet = (set, version2, options) => {\n for (let i = 0; i < set.length; i++) {\n if (!set[i].test(version2)) {\n return false;\n }\n }\n if (version2.prerelease.length && !options.includePrerelease) {\n for (let i = 0; i < set.length; i++) {\n debug(set[i].semver);\n if (set[i].semver === Comparator.ANY) {\n continue;\n }\n if (set[i].semver.prerelease.length > 0) {\n const allowed = set[i].semver;\n if (allowed.major === version2.major && allowed.minor === version2.minor && allowed.patch === version2.patch) {\n return true;\n }\n }\n }\n return false;\n }\n return true;\n };\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/classes/comparator.js\nvar require_comparator = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/classes/comparator.js\"(exports, module) {\n \"use strict\";\n var ANY = /* @__PURE__ */ Symbol(\"SemVer ANY\");\n var Comparator = class _Comparator {\n static get ANY() {\n return ANY;\n }\n constructor(comp, options) {\n options = parseOptions(options);\n if (comp instanceof _Comparator) {\n if (comp.loose === !!options.loose) {\n return comp;\n } else {\n comp = comp.value;\n }\n }\n comp = comp.trim().split(/\\s+/).join(\" \");\n debug(\"comparator\", comp, options);\n this.options = options;\n this.loose = !!options.loose;\n this.parse(comp);\n if (this.semver === ANY) {\n this.value = \"\";\n } else {\n this.value = this.operator + this.semver.version;\n }\n debug(\"comp\", this);\n }\n parse(comp) {\n const r = this.options.loose ? re[t.COMPARATORLOOSE] : re[t.COMPARATOR];\n const m = comp.match(r);\n if (!m) {\n throw new TypeError(`Invalid comparator: ${comp}`);\n }\n this.operator = m[1] !== void 0 ? m[1] : \"\";\n if (this.operator === \"=\") {\n this.operator = \"\";\n }\n if (!m[2]) {\n this.semver = ANY;\n } else {\n this.semver = new SemVer(m[2], this.options.loose);\n }\n }\n toString() {\n return this.value;\n }\n test(version2) {\n debug(\"Comparator.test\", version2, this.options.loose);\n if (this.semver === ANY || version2 === ANY) {\n return true;\n }\n if (typeof version2 === \"string\") {\n try {\n version2 = new SemVer(version2, this.options);\n } catch (er) {\n return false;\n }\n }\n return cmp(version2, this.operator, this.semver, this.options);\n }\n intersects(comp, options) {\n if (!(comp instanceof _Comparator)) {\n throw new TypeError(\"a Comparator is required\");\n }\n if (this.operator === \"\") {\n if (this.value === \"\") {\n return true;\n }\n return new Range(comp.value, options).test(this.value);\n } else if (comp.operator === \"\") {\n if (comp.value === \"\") {\n return true;\n }\n return new Range(this.value, options).test(comp.semver);\n }\n options = parseOptions(options);\n if (options.includePrerelease && (this.value === \"<0.0.0-0\" || comp.value === \"<0.0.0-0\")) {\n return false;\n }\n if (!options.includePrerelease && (this.value.startsWith(\"<0.0.0\") || comp.value.startsWith(\"<0.0.0\"))) {\n return false;\n }\n if (this.operator.startsWith(\">\") && comp.operator.startsWith(\">\")) {\n return true;\n }\n if (this.operator.startsWith(\"<\") && comp.operator.startsWith(\"<\")) {\n return true;\n }\n if (this.semver.version === comp.semver.version && this.operator.includes(\"=\") && comp.operator.includes(\"=\")) {\n return true;\n }\n if (cmp(this.semver, \"<\", comp.semver, options) && this.operator.startsWith(\">\") && comp.operator.startsWith(\"<\")) {\n return true;\n }\n if (cmp(this.semver, \">\", comp.semver, options) && this.operator.startsWith(\"<\") && comp.operator.startsWith(\">\")) {\n return true;\n }\n return false;\n }\n };\n module.exports = Comparator;\n var parseOptions = require_parse_options();\n var { safeRe: re, t } = require_re();\n var cmp = require_cmp();\n var debug = require_debug();\n var SemVer = require_semver();\n var Range = require_range();\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/satisfies.js\nvar require_satisfies = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/satisfies.js\"(exports, module) {\n \"use strict\";\n var Range = require_range();\n var satisfies2 = (version2, range, options) => {\n try {\n range = new Range(range, options);\n } catch (er) {\n return false;\n }\n return range.test(version2);\n };\n module.exports = satisfies2;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/to-comparators.js\nvar require_to_comparators = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/to-comparators.js\"(exports, module) {\n \"use strict\";\n var Range = require_range();\n var toComparators = (range, options) => new Range(range, options).set.map((comp) => comp.map((c) => c.value).join(\" \").trim().split(\" \"));\n module.exports = toComparators;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/max-satisfying.js\nvar require_max_satisfying = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/max-satisfying.js\"(exports, module) {\n \"use strict\";\n var SemVer = require_semver();\n var Range = require_range();\n var maxSatisfying = (versions, range, options) => {\n let max = null;\n let maxSV = null;\n let rangeObj = null;\n try {\n rangeObj = new Range(range, options);\n } catch (er) {\n return null;\n }\n versions.forEach((v) => {\n if (rangeObj.test(v)) {\n if (!max || maxSV.compare(v) === -1) {\n max = v;\n maxSV = new SemVer(max, options);\n }\n }\n });\n return max;\n };\n module.exports = maxSatisfying;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/min-satisfying.js\nvar require_min_satisfying = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/min-satisfying.js\"(exports, module) {\n \"use strict\";\n var SemVer = require_semver();\n var Range = require_range();\n var minSatisfying = (versions, range, options) => {\n let min = null;\n let minSV = null;\n let rangeObj = null;\n try {\n rangeObj = new Range(range, options);\n } catch (er) {\n return null;\n }\n versions.forEach((v) => {\n if (rangeObj.test(v)) {\n if (!min || minSV.compare(v) === 1) {\n min = v;\n minSV = new SemVer(min, options);\n }\n }\n });\n return min;\n };\n module.exports = minSatisfying;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/min-version.js\nvar require_min_version = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/min-version.js\"(exports, module) {\n \"use strict\";\n var SemVer = require_semver();\n var Range = require_range();\n var gt = require_gt();\n var minVersion = (range, loose) => {\n range = new Range(range, loose);\n let minver = new SemVer(\"0.0.0\");\n if (range.test(minver)) {\n return minver;\n }\n minver = new SemVer(\"0.0.0-0\");\n if (range.test(minver)) {\n return minver;\n }\n minver = null;\n for (let i = 0; i < range.set.length; ++i) {\n const comparators = range.set[i];\n let setMin = null;\n comparators.forEach((comparator) => {\n const compver = new SemVer(comparator.semver.version);\n switch (comparator.operator) {\n case \">\":\n if (compver.prerelease.length === 0) {\n compver.patch++;\n } else {\n compver.prerelease.push(0);\n }\n compver.raw = compver.format();\n /* fallthrough */\n case \"\":\n case \">=\":\n if (!setMin || gt(compver, setMin)) {\n setMin = compver;\n }\n break;\n case \"<\":\n case \"<=\":\n break;\n /* istanbul ignore next */\n default:\n throw new Error(`Unexpected operation: ${comparator.operator}`);\n }\n });\n if (setMin && (!minver || gt(minver, setMin))) {\n minver = setMin;\n }\n }\n if (minver && range.test(minver)) {\n return minver;\n }\n return null;\n };\n module.exports = minVersion;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/valid.js\nvar require_valid2 = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/valid.js\"(exports, module) {\n \"use strict\";\n var Range = require_range();\n var validRange = (range, options) => {\n try {\n return new Range(range, options).range || \"*\";\n } catch (er) {\n return null;\n }\n };\n module.exports = validRange;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/outside.js\nvar require_outside = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/outside.js\"(exports, module) {\n \"use strict\";\n var SemVer = require_semver();\n var Comparator = require_comparator();\n var { ANY } = Comparator;\n var Range = require_range();\n var satisfies2 = require_satisfies();\n var gt = require_gt();\n var lt = require_lt();\n var lte = require_lte();\n var gte = require_gte();\n var outside = (version2, range, hilo, options) => {\n version2 = new SemVer(version2, options);\n range = new Range(range, options);\n let gtfn, ltefn, ltfn, comp, ecomp;\n switch (hilo) {\n case \">\":\n gtfn = gt;\n ltefn = lte;\n ltfn = lt;\n comp = \">\";\n ecomp = \">=\";\n break;\n case \"<\":\n gtfn = lt;\n ltefn = gte;\n ltfn = gt;\n comp = \"<\";\n ecomp = \"<=\";\n break;\n default:\n throw new TypeError('Must provide a hilo val of \"<\" or \">\"');\n }\n if (satisfies2(version2, range, options)) {\n return false;\n }\n for (let i = 0; i < range.set.length; ++i) {\n const comparators = range.set[i];\n let high = null;\n let low = null;\n comparators.forEach((comparator) => {\n if (comparator.semver === ANY) {\n comparator = new Comparator(\">=0.0.0\");\n }\n high = high || comparator;\n low = low || comparator;\n if (gtfn(comparator.semver, high.semver, options)) {\n high = comparator;\n } else if (ltfn(comparator.semver, low.semver, options)) {\n low = comparator;\n }\n });\n if (high.operator === comp || high.operator === ecomp) {\n return false;\n }\n if ((!low.operator || low.operator === comp) && ltefn(version2, low.semver)) {\n return false;\n } else if (low.operator === ecomp && ltfn(version2, low.semver)) {\n return false;\n }\n }\n return true;\n };\n module.exports = outside;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/gtr.js\nvar require_gtr = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/gtr.js\"(exports, module) {\n \"use strict\";\n var outside = require_outside();\n var gtr = (version2, range, options) => outside(version2, range, \">\", options);\n module.exports = gtr;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/ltr.js\nvar require_ltr = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/ltr.js\"(exports, module) {\n \"use strict\";\n var outside = require_outside();\n var ltr = (version2, range, options) => outside(version2, range, \"<\", options);\n module.exports = ltr;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/intersects.js\nvar require_intersects = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/intersects.js\"(exports, module) {\n \"use strict\";\n var Range = require_range();\n var intersects = (r1, r2, options) => {\n r1 = new Range(r1, options);\n r2 = new Range(r2, options);\n return r1.intersects(r2, options);\n };\n module.exports = intersects;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/simplify.js\nvar require_simplify = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/simplify.js\"(exports, module) {\n \"use strict\";\n var satisfies2 = require_satisfies();\n var compare = require_compare();\n module.exports = (versions, range, options) => {\n const set = [];\n let first = null;\n let prev = null;\n const v = versions.sort((a, b) => compare(a, b, options));\n for (const version2 of v) {\n const included = satisfies2(version2, range, options);\n if (included) {\n prev = version2;\n if (!first) {\n first = version2;\n }\n } else {\n if (prev) {\n set.push([first, prev]);\n }\n prev = null;\n first = null;\n }\n }\n if (first) {\n set.push([first, null]);\n }\n const ranges2 = [];\n for (const [min, max] of set) {\n if (min === max) {\n ranges2.push(min);\n } else if (!max && min === v[0]) {\n ranges2.push(\"*\");\n } else if (!max) {\n ranges2.push(`>=${min}`);\n } else if (min === v[0]) {\n ranges2.push(`<=${max}`);\n } else {\n ranges2.push(`${min} - ${max}`);\n }\n }\n const simplified = ranges2.join(\" || \");\n const original = typeof range.raw === \"string\" ? range.raw : String(range);\n return simplified.length < original.length ? simplified : range;\n };\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/subset.js\nvar require_subset = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/subset.js\"(exports, module) {\n \"use strict\";\n var Range = require_range();\n var Comparator = require_comparator();\n var { ANY } = Comparator;\n var satisfies2 = require_satisfies();\n var compare = require_compare();\n var subset = (sub, dom, options = {}) => {\n if (sub === dom) {\n return true;\n }\n sub = new Range(sub, options);\n dom = new Range(dom, options);\n let sawNonNull = false;\n OUTER: for (const simpleSub of sub.set) {\n for (const simpleDom of dom.set) {\n const isSub = simpleSubset(simpleSub, simpleDom, options);\n sawNonNull = sawNonNull || isSub !== null;\n if (isSub) {\n continue OUTER;\n }\n }\n if (sawNonNull) {\n return false;\n }\n }\n return true;\n };\n var minimumVersionWithPreRelease = [new Comparator(\">=0.0.0-0\")];\n var minimumVersion = [new Comparator(\">=0.0.0\")];\n var simpleSubset = (sub, dom, options) => {\n if (sub === dom) {\n return true;\n }\n if (sub.length === 1 && sub[0].semver === ANY) {\n if (dom.length === 1 && dom[0].semver === ANY) {\n return true;\n } else if (options.includePrerelease) {\n sub = minimumVersionWithPreRelease;\n } else {\n sub = minimumVersion;\n }\n }\n if (dom.length === 1 && dom[0].semver === ANY) {\n if (options.includePrerelease) {\n return true;\n } else {\n dom = minimumVersion;\n }\n }\n const eqSet = /* @__PURE__ */ new Set();\n let gt, lt;\n for (const c of sub) {\n if (c.operator === \">\" || c.operator === \">=\") {\n gt = higherGT(gt, c, options);\n } else if (c.operator === \"<\" || c.operator === \"<=\") {\n lt = lowerLT(lt, c, options);\n } else {\n eqSet.add(c.semver);\n }\n }\n if (eqSet.size > 1) {\n return null;\n }\n let gtltComp;\n if (gt && lt) {\n gtltComp = compare(gt.semver, lt.semver, options);\n if (gtltComp > 0) {\n return null;\n } else if (gtltComp === 0 && (gt.operator !== \">=\" || lt.operator !== \"<=\")) {\n return null;\n }\n }\n for (const eq of eqSet) {\n if (gt && !satisfies2(eq, String(gt), options)) {\n return null;\n }\n if (lt && !satisfies2(eq, String(lt), options)) {\n return null;\n }\n for (const c of dom) {\n if (!satisfies2(eq, String(c), options)) {\n return false;\n }\n }\n return true;\n }\n let higher, lower;\n let hasDomLT, hasDomGT;\n let needDomLTPre = lt && !options.includePrerelease && lt.semver.prerelease.length ? lt.semver : false;\n let needDomGTPre = gt && !options.includePrerelease && gt.semver.prerelease.length ? gt.semver : false;\n if (needDomLTPre && needDomLTPre.prerelease.length === 1 && lt.operator === \"<\" && needDomLTPre.prerelease[0] === 0) {\n needDomLTPre = false;\n }\n for (const c of dom) {\n hasDomGT = hasDomGT || c.operator === \">\" || c.operator === \">=\";\n hasDomLT = hasDomLT || c.operator === \"<\" || c.operator === \"<=\";\n if (gt) {\n if (needDomGTPre) {\n if (c.semver.prerelease && c.semver.prerelease.length && c.semver.major === needDomGTPre.major && c.semver.minor === needDomGTPre.minor && c.semver.patch === needDomGTPre.patch) {\n needDomGTPre = false;\n }\n }\n if (c.operator === \">\" || c.operator === \">=\") {\n higher = higherGT(gt, c, options);\n if (higher === c && higher !== gt) {\n return false;\n }\n } else if (gt.operator === \">=\" && !satisfies2(gt.semver, String(c), options)) {\n return false;\n }\n }\n if (lt) {\n if (needDomLTPre) {\n if (c.semver.prerelease && c.semver.prerelease.length && c.semver.major === needDomLTPre.major && c.semver.minor === needDomLTPre.minor && c.semver.patch === needDomLTPre.patch) {\n needDomLTPre = false;\n }\n }\n if (c.operator === \"<\" || c.operator === \"<=\") {\n lower = lowerLT(lt, c, options);\n if (lower === c && lower !== lt) {\n return false;\n }\n } else if (lt.operator === \"<=\" && !satisfies2(lt.semver, String(c), options)) {\n return false;\n }\n }\n if (!c.operator && (lt || gt) && gtltComp !== 0) {\n return false;\n }\n }\n if (gt && hasDomLT && !lt && gtltComp !== 0) {\n return false;\n }\n if (lt && hasDomGT && !gt && gtltComp !== 0) {\n return false;\n }\n if (needDomGTPre || needDomLTPre) {\n return false;\n }\n return true;\n };\n var higherGT = (a, b, options) => {\n if (!a) {\n return b;\n }\n const comp = compare(a.semver, b.semver, options);\n return comp > 0 ? a : comp < 0 ? b : b.operator === \">\" && a.operator === \">=\" ? b : a;\n };\n var lowerLT = (a, b, options) => {\n if (!a) {\n return b;\n }\n const comp = compare(a.semver, b.semver, options);\n return comp < 0 ? a : comp > 0 ? b : b.operator === \"<\" && a.operator === \"<=\" ? b : a;\n };\n module.exports = subset;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/index.js\nvar require_semver2 = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/index.js\"(exports, module) {\n \"use strict\";\n var internalRe = require_re();\n var constants = require_constants();\n var SemVer = require_semver();\n var identifiers = require_identifiers();\n var parse = require_parse();\n var valid2 = require_valid();\n var clean = require_clean();\n var inc = require_inc();\n var diff = require_diff();\n var major = require_major();\n var minor = require_minor();\n var patch = require_patch();\n var prerelease = require_prerelease();\n var compare = require_compare();\n var rcompare = require_rcompare();\n var compareLoose = require_compare_loose();\n var compareBuild = require_compare_build();\n var sort = require_sort();\n var rsort = require_rsort();\n var gt = require_gt();\n var lt = require_lt();\n var eq = require_eq();\n var neq = require_neq();\n var gte = require_gte();\n var lte = require_lte();\n var cmp = require_cmp();\n var coerce = require_coerce();\n var Comparator = require_comparator();\n var Range = require_range();\n var satisfies2 = require_satisfies();\n var toComparators = require_to_comparators();\n var maxSatisfying = require_max_satisfying();\n var minSatisfying = require_min_satisfying();\n var minVersion = require_min_version();\n var validRange = require_valid2();\n var outside = require_outside();\n var gtr = require_gtr();\n var ltr = require_ltr();\n var intersects = require_intersects();\n var simplifyRange = require_simplify();\n var subset = require_subset();\n module.exports = {\n parse,\n valid: valid2,\n clean,\n inc,\n diff,\n major,\n minor,\n patch,\n prerelease,\n compare,\n rcompare,\n compareLoose,\n compareBuild,\n sort,\n rsort,\n gt,\n lt,\n eq,\n neq,\n gte,\n lte,\n cmp,\n coerce,\n Comparator,\n Range,\n satisfies: satisfies2,\n toComparators,\n maxSatisfying,\n minSatisfying,\n minVersion,\n validRange,\n outside,\n gtr,\n ltr,\n intersects,\n simplifyRange,\n subset,\n SemVer,\n re: internalRe.re,\n src: internalRe.src,\n tokens: internalRe.t,\n SEMVER_SPEC_VERSION: constants.SEMVER_SPEC_VERSION,\n RELEASE_TYPES: constants.RELEASE_TYPES,\n compareIdentifiers: identifiers.compareIdentifiers,\n rcompareIdentifiers: identifiers.rcompareIdentifiers\n };\n }\n});\n\n// apps/ecosystem-certifier/fixtures/positive/semver-entry.ts\nvar import_semver = __toESM(require_semver2(), 1);\nvar version = Host.v1.document.get(\"text/semver-case\");\nvar ranges = [\">=1.2.0 <2.0.0\", \"^1.2.0\", \"~1.2.3\"];\nvar semver_entry_default = {\n version,\n valid: (0, import_semver.valid)(version) !== null,\n checks: ranges.map((range) => ({ range, ok: (0, import_semver.satisfies)(version, range) }))\n};\nexport {\n semver_entry_default as default\n};\n", + "sourceMap": "{\"mappings\":\"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\",\"names\":[\"version\",\"version\",\"valid\",\"version\",\"version\",\"version\",\"version\",\"version\",\"version\",\"version\",\"satisfies\",\"version\",\"require_valid\",\"satisfies\",\"version\",\"version\",\"version\",\"satisfies\",\"version\",\"ranges\",\"satisfies\",\"require_semver\",\"valid\",\"satisfies\"],\"sources\":[\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/constants.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/debug.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/re.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/parse-options.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/identifiers.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/classes/semver.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/parse.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/valid.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/clean.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/inc.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/diff.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/major.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/minor.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/patch.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/prerelease.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/compare.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/rcompare.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/compare-loose.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/compare-build.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/sort.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/rsort.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/gt.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/lt.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/eq.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/neq.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/gte.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/lte.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/cmp.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/coerce.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/lrucache.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/classes/range.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/classes/comparator.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/satisfies.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/to-comparators.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/max-satisfying.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/min-satisfying.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/min-version.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/valid.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/outside.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/gtr.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/ltr.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/intersects.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/simplify.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/subset.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/index.js\",\"../apps/ecosystem-certifier/fixtures/positive/semver-entry.ts\"],\"sourcesContent\":[\"'use strict'\\n\\n// Note: this is the semver.org version of the spec that it implements\\n// Not necessarily the package version of this code.\\nconst SEMVER_SPEC_VERSION = '2.0.0'\\n\\nconst MAX_LENGTH = 256\\nconst MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER ||\\n/* istanbul ignore next */ 9007199254740991\\n\\n// Max safe segment length for coercion.\\nconst MAX_SAFE_COMPONENT_LENGTH = 16\\n\\n// Max safe length for a build identifier. The max length minus 6 characters for\\n// the shortest version with a build 0.0.0+BUILD.\\nconst MAX_SAFE_BUILD_LENGTH = MAX_LENGTH - 6\\n\\nconst RELEASE_TYPES = [\\n 'major',\\n 'premajor',\\n 'minor',\\n 'preminor',\\n 'patch',\\n 'prepatch',\\n 'prerelease',\\n]\\n\\nmodule.exports = {\\n MAX_LENGTH,\\n MAX_SAFE_COMPONENT_LENGTH,\\n MAX_SAFE_BUILD_LENGTH,\\n MAX_SAFE_INTEGER,\\n RELEASE_TYPES,\\n SEMVER_SPEC_VERSION,\\n FLAG_INCLUDE_PRERELEASE: 0b001,\\n FLAG_LOOSE: 0b010,\\n}\\n\",\"'use strict'\\n\\nconst debug = (\\n typeof process === 'object' &&\\n process.env &&\\n process.env.NODE_DEBUG &&\\n /\\\\bsemver\\\\b/i.test(process.env.NODE_DEBUG)\\n) ? (...args) => console.error('SEMVER', ...args)\\n : () => {}\\n\\nmodule.exports = debug\\n\",\"'use strict'\\n\\nconst {\\n MAX_SAFE_COMPONENT_LENGTH,\\n MAX_SAFE_BUILD_LENGTH,\\n MAX_LENGTH,\\n} = require('./constants')\\nconst debug = require('./debug')\\nexports = module.exports = {}\\n\\n// The actual regexps go on exports.re\\nconst re = exports.re = []\\nconst safeRe = exports.safeRe = []\\nconst src = exports.src = []\\nconst safeSrc = exports.safeSrc = []\\nconst t = exports.t = {}\\nlet R = 0\\n\\nconst LETTERDASHNUMBER = '[a-zA-Z0-9-]'\\n\\n// Replace some greedy regex tokens to prevent regex dos issues. These regex are\\n// used internally via the safeRe object since all inputs in this library get\\n// normalized first to trim and collapse all extra whitespace. The original\\n// regexes are exported for userland consumption and lower level usage. A\\n// future breaking change could export the safer regex only with a note that\\n// all input should have extra whitespace removed.\\nconst safeRegexReplacements = [\\n ['\\\\\\\\s', 1],\\n ['\\\\\\\\d', MAX_LENGTH],\\n [LETTERDASHNUMBER, MAX_SAFE_BUILD_LENGTH],\\n]\\n\\nconst makeSafeRegex = (value) => {\\n for (const [token, max] of safeRegexReplacements) {\\n value = value\\n .split(`${token}*`).join(`${token}{0,${max}}`)\\n .split(`${token}+`).join(`${token}{1,${max}}`)\\n }\\n return value\\n}\\n\\nconst createToken = (name, value, isGlobal) => {\\n const safe = makeSafeRegex(value)\\n const index = R++\\n debug(name, index, value)\\n t[name] = index\\n src[index] = value\\n safeSrc[index] = safe\\n re[index] = new RegExp(value, isGlobal ? 'g' : undefined)\\n safeRe[index] = new RegExp(safe, isGlobal ? 'g' : undefined)\\n}\\n\\n// The following Regular Expressions can be used for tokenizing,\\n// validating, and parsing SemVer version strings.\\n\\n// ## Numeric Identifier\\n// A single `0`, or a non-zero digit followed by zero or more digits.\\n\\ncreateToken('NUMERICIDENTIFIER', '0|[1-9]\\\\\\\\d*')\\ncreateToken('NUMERICIDENTIFIERLOOSE', '\\\\\\\\d+')\\n\\n// ## Non-numeric Identifier\\n// Zero or more digits, followed by a letter or hyphen, and then zero or\\n// more letters, digits, or hyphens.\\n\\ncreateToken('NONNUMERICIDENTIFIER', `\\\\\\\\d*[a-zA-Z-]${LETTERDASHNUMBER}*`)\\n\\n// ## Main Version\\n// Three dot-separated numeric identifiers.\\n\\ncreateToken('MAINVERSION', `(${src[t.NUMERICIDENTIFIER]})\\\\\\\\.` +\\n `(${src[t.NUMERICIDENTIFIER]})\\\\\\\\.` +\\n `(${src[t.NUMERICIDENTIFIER]})`)\\n\\ncreateToken('MAINVERSIONLOOSE', `(${src[t.NUMERICIDENTIFIERLOOSE]})\\\\\\\\.` +\\n `(${src[t.NUMERICIDENTIFIERLOOSE]})\\\\\\\\.` +\\n `(${src[t.NUMERICIDENTIFIERLOOSE]})`)\\n\\n// ## Pre-release Version Identifier\\n// A numeric identifier, or a non-numeric identifier.\\n// Non-numberic identifiers include numberic identifiers but can be longer.\\n// Therefore non-numberic identifiers must go first.\\n\\ncreateToken('PRERELEASEIDENTIFIER', `(?:${src[t.NONNUMERICIDENTIFIER]\\n}|${src[t.NUMERICIDENTIFIER]})`)\\n\\ncreateToken('PRERELEASEIDENTIFIERLOOSE', `(?:${src[t.NONNUMERICIDENTIFIER]\\n}|${src[t.NUMERICIDENTIFIERLOOSE]})`)\\n\\n// ## Pre-release Version\\n// Hyphen, followed by one or more dot-separated pre-release version\\n// identifiers.\\n\\ncreateToken('PRERELEASE', `(?:-(${src[t.PRERELEASEIDENTIFIER]\\n}(?:\\\\\\\\.${src[t.PRERELEASEIDENTIFIER]})*))`)\\n\\ncreateToken('PRERELEASELOOSE', `(?:-?(${src[t.PRERELEASEIDENTIFIERLOOSE]\\n}(?:\\\\\\\\.${src[t.PRERELEASEIDENTIFIERLOOSE]})*))`)\\n\\n// ## Build Metadata Identifier\\n// Any combination of digits, letters, or hyphens.\\n\\ncreateToken('BUILDIDENTIFIER', `${LETTERDASHNUMBER}+`)\\n\\n// ## Build Metadata\\n// Plus sign, followed by one or more period-separated build metadata\\n// identifiers.\\n\\ncreateToken('BUILD', `(?:\\\\\\\\+(${src[t.BUILDIDENTIFIER]\\n}(?:\\\\\\\\.${src[t.BUILDIDENTIFIER]})*))`)\\n\\n// ## Full Version String\\n// A main version, followed optionally by a pre-release version and\\n// build metadata.\\n\\n// Note that the only major, minor, patch, and pre-release sections of\\n// the version string are capturing groups. The build metadata is not a\\n// capturing group, because it should not ever be used in version\\n// comparison.\\n\\ncreateToken('FULLPLAIN', `v?${src[t.MAINVERSION]\\n}${src[t.PRERELEASE]}?${\\n src[t.BUILD]}?`)\\n\\ncreateToken('FULL', `^${src[t.FULLPLAIN]}$`)\\n\\n// like full, but allows v1.2.3 and =1.2.3, which people do sometimes.\\n// also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty\\n// common in the npm registry.\\ncreateToken('LOOSEPLAIN', `[v=\\\\\\\\s]*${src[t.MAINVERSIONLOOSE]\\n}${src[t.PRERELEASELOOSE]}?${\\n src[t.BUILD]}?`)\\n\\ncreateToken('LOOSE', `^${src[t.LOOSEPLAIN]}$`)\\n\\ncreateToken('GTLT', '((?:<|>)?=?)')\\n\\n// Something like \\\"2.*\\\" or \\\"1.2.x\\\".\\n// Note that \\\"x.x\\\" is a valid xRange identifer, meaning \\\"any version\\\"\\n// Only the first item is strictly required.\\ncreateToken('XRANGEIDENTIFIERLOOSE', `${src[t.NUMERICIDENTIFIERLOOSE]}|x|X|\\\\\\\\*`)\\ncreateToken('XRANGEIDENTIFIER', `${src[t.NUMERICIDENTIFIER]}|x|X|\\\\\\\\*`)\\n\\ncreateToken('XRANGEPLAIN', `[v=\\\\\\\\s]*(${src[t.XRANGEIDENTIFIER]})` +\\n `(?:\\\\\\\\.(${src[t.XRANGEIDENTIFIER]})` +\\n `(?:\\\\\\\\.(${src[t.XRANGEIDENTIFIER]})` +\\n `(?:${src[t.PRERELEASE]})?${\\n src[t.BUILD]}?` +\\n `)?)?`)\\n\\ncreateToken('XRANGEPLAINLOOSE', `[v=\\\\\\\\s]*(${src[t.XRANGEIDENTIFIERLOOSE]})` +\\n `(?:\\\\\\\\.(${src[t.XRANGEIDENTIFIERLOOSE]})` +\\n `(?:\\\\\\\\.(${src[t.XRANGEIDENTIFIERLOOSE]})` +\\n `(?:${src[t.PRERELEASELOOSE]})?${\\n src[t.BUILD]}?` +\\n `)?)?`)\\n\\ncreateToken('XRANGE', `^${src[t.GTLT]}\\\\\\\\s*${src[t.XRANGEPLAIN]}$`)\\ncreateToken('XRANGELOOSE', `^${src[t.GTLT]}\\\\\\\\s*${src[t.XRANGEPLAINLOOSE]}$`)\\n\\n// Coercion.\\n// Extract anything that could conceivably be a part of a valid semver\\ncreateToken('COERCEPLAIN', `${'(^|[^\\\\\\\\d])' +\\n '(\\\\\\\\d{1,'}${MAX_SAFE_COMPONENT_LENGTH}})` +\\n `(?:\\\\\\\\.(\\\\\\\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` +\\n `(?:\\\\\\\\.(\\\\\\\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?`)\\ncreateToken('COERCE', `${src[t.COERCEPLAIN]}(?:$|[^\\\\\\\\d])`)\\ncreateToken('COERCEFULL', src[t.COERCEPLAIN] +\\n `(?:${src[t.PRERELEASE]})?` +\\n `(?:${src[t.BUILD]})?` +\\n `(?:$|[^\\\\\\\\d])`)\\ncreateToken('COERCERTL', src[t.COERCE], true)\\ncreateToken('COERCERTLFULL', src[t.COERCEFULL], true)\\n\\n// Tilde ranges.\\n// Meaning is \\\"reasonably at or greater than\\\"\\ncreateToken('LONETILDE', '(?:~>?)')\\n\\ncreateToken('TILDETRIM', `(\\\\\\\\s*)${src[t.LONETILDE]}\\\\\\\\s+`, true)\\nexports.tildeTrimReplace = '$1~'\\n\\ncreateToken('TILDE', `^${src[t.LONETILDE]}${src[t.XRANGEPLAIN]}$`)\\ncreateToken('TILDELOOSE', `^${src[t.LONETILDE]}${src[t.XRANGEPLAINLOOSE]}$`)\\n\\n// Caret ranges.\\n// Meaning is \\\"at least and backwards compatible with\\\"\\ncreateToken('LONECARET', '(?:\\\\\\\\^)')\\n\\ncreateToken('CARETTRIM', `(\\\\\\\\s*)${src[t.LONECARET]}\\\\\\\\s+`, true)\\nexports.caretTrimReplace = '$1^'\\n\\ncreateToken('CARET', `^${src[t.LONECARET]}${src[t.XRANGEPLAIN]}$`)\\ncreateToken('CARETLOOSE', `^${src[t.LONECARET]}${src[t.XRANGEPLAINLOOSE]}$`)\\n\\n// A simple gt/lt/eq thing, or just \\\"\\\" to indicate \\\"any version\\\"\\ncreateToken('COMPARATORLOOSE', `^${src[t.GTLT]}\\\\\\\\s*(${src[t.LOOSEPLAIN]})$|^$`)\\ncreateToken('COMPARATOR', `^${src[t.GTLT]}\\\\\\\\s*(${src[t.FULLPLAIN]})$|^$`)\\n\\n// An expression to strip any whitespace between the gtlt and the thing\\n// it modifies, so that `> 1.2.3` ==> `>1.2.3`\\ncreateToken('COMPARATORTRIM', `(\\\\\\\\s*)${src[t.GTLT]\\n}\\\\\\\\s*(${src[t.LOOSEPLAIN]}|${src[t.XRANGEPLAIN]})`, true)\\nexports.comparatorTrimReplace = '$1$2$3'\\n\\n// Something like `1.2.3 - 1.2.4`\\n// Note that these all use the loose form, because they'll be\\n// checked against either the strict or loose comparator form\\n// later.\\ncreateToken('HYPHENRANGE', `^\\\\\\\\s*(${src[t.XRANGEPLAIN]})` +\\n `\\\\\\\\s+-\\\\\\\\s+` +\\n `(${src[t.XRANGEPLAIN]})` +\\n `\\\\\\\\s*$`)\\n\\ncreateToken('HYPHENRANGELOOSE', `^\\\\\\\\s*(${src[t.XRANGEPLAINLOOSE]})` +\\n `\\\\\\\\s+-\\\\\\\\s+` +\\n `(${src[t.XRANGEPLAINLOOSE]})` +\\n `\\\\\\\\s*$`)\\n\\n// Star ranges basically just allow anything at all.\\ncreateToken('STAR', '(<|>)?=?\\\\\\\\s*\\\\\\\\*')\\n// >=0.0.0 is like a star\\ncreateToken('GTE0', '^\\\\\\\\s*>=\\\\\\\\s*0\\\\\\\\.0\\\\\\\\.0\\\\\\\\s*$')\\ncreateToken('GTE0PRE', '^\\\\\\\\s*>=\\\\\\\\s*0\\\\\\\\.0\\\\\\\\.0-0\\\\\\\\s*$')\\n\",\"'use strict'\\n\\n// parse out just the options we care about\\nconst looseOption = Object.freeze({ loose: true })\\nconst emptyOpts = Object.freeze({ })\\nconst parseOptions = options => {\\n if (!options) {\\n return emptyOpts\\n }\\n\\n if (typeof options !== 'object') {\\n return looseOption\\n }\\n\\n return options\\n}\\nmodule.exports = parseOptions\\n\",\"'use strict'\\n\\nconst numeric = /^[0-9]+$/\\nconst compareIdentifiers = (a, b) => {\\n if (typeof a === 'number' && typeof b === 'number') {\\n return a === b ? 0 : a < b ? -1 : 1\\n }\\n\\n const anum = numeric.test(a)\\n const bnum = numeric.test(b)\\n\\n if (anum && bnum) {\\n a = +a\\n b = +b\\n }\\n\\n return a === b ? 0\\n : (anum && !bnum) ? -1\\n : (bnum && !anum) ? 1\\n : a < b ? -1\\n : 1\\n}\\n\\nconst rcompareIdentifiers = (a, b) => compareIdentifiers(b, a)\\n\\nmodule.exports = {\\n compareIdentifiers,\\n rcompareIdentifiers,\\n}\\n\",\"'use strict'\\n\\nconst debug = require('../internal/debug')\\nconst { MAX_LENGTH, MAX_SAFE_INTEGER } = require('../internal/constants')\\nconst { safeRe: re, t } = require('../internal/re')\\n\\nconst parseOptions = require('../internal/parse-options')\\nconst { compareIdentifiers } = require('../internal/identifiers')\\nclass SemVer {\\n constructor (version, options) {\\n options = parseOptions(options)\\n\\n if (version instanceof SemVer) {\\n if (version.loose === !!options.loose &&\\n version.includePrerelease === !!options.includePrerelease) {\\n return version\\n } else {\\n version = version.version\\n }\\n } else if (typeof version !== 'string') {\\n throw new TypeError(`Invalid version. Must be a string. Got type \\\"${typeof version}\\\".`)\\n }\\n\\n if (version.length > MAX_LENGTH) {\\n throw new TypeError(\\n `version is longer than ${MAX_LENGTH} characters`\\n )\\n }\\n\\n debug('SemVer', version, options)\\n this.options = options\\n this.loose = !!options.loose\\n // this isn't actually relevant for versions, but keep it so that we\\n // don't run into trouble passing this.options around.\\n this.includePrerelease = !!options.includePrerelease\\n\\n const m = version.trim().match(options.loose ? re[t.LOOSE] : re[t.FULL])\\n\\n if (!m) {\\n throw new TypeError(`Invalid Version: ${version}`)\\n }\\n\\n this.raw = version\\n\\n // these are actually numbers\\n this.major = +m[1]\\n this.minor = +m[2]\\n this.patch = +m[3]\\n\\n if (this.major > MAX_SAFE_INTEGER || this.major < 0) {\\n throw new TypeError('Invalid major version')\\n }\\n\\n if (this.minor > MAX_SAFE_INTEGER || this.minor < 0) {\\n throw new TypeError('Invalid minor version')\\n }\\n\\n if (this.patch > MAX_SAFE_INTEGER || this.patch < 0) {\\n throw new TypeError('Invalid patch version')\\n }\\n\\n // numberify any prerelease numeric ids\\n if (!m[4]) {\\n this.prerelease = []\\n } else {\\n this.prerelease = m[4].split('.').map((id) => {\\n if (/^[0-9]+$/.test(id)) {\\n const num = +id\\n if (num >= 0 && num < MAX_SAFE_INTEGER) {\\n return num\\n }\\n }\\n return id\\n })\\n }\\n\\n this.build = m[5] ? m[5].split('.') : []\\n this.format()\\n }\\n\\n format () {\\n this.version = `${this.major}.${this.minor}.${this.patch}`\\n if (this.prerelease.length) {\\n this.version += `-${this.prerelease.join('.')}`\\n }\\n return this.version\\n }\\n\\n toString () {\\n return this.version\\n }\\n\\n compare (other) {\\n debug('SemVer.compare', this.version, this.options, other)\\n if (!(other instanceof SemVer)) {\\n if (typeof other === 'string' && other === this.version) {\\n return 0\\n }\\n other = new SemVer(other, this.options)\\n }\\n\\n if (other.version === this.version) {\\n return 0\\n }\\n\\n return this.compareMain(other) || this.comparePre(other)\\n }\\n\\n compareMain (other) {\\n if (!(other instanceof SemVer)) {\\n other = new SemVer(other, this.options)\\n }\\n\\n if (this.major < other.major) {\\n return -1\\n }\\n if (this.major > other.major) {\\n return 1\\n }\\n if (this.minor < other.minor) {\\n return -1\\n }\\n if (this.minor > other.minor) {\\n return 1\\n }\\n if (this.patch < other.patch) {\\n return -1\\n }\\n if (this.patch > other.patch) {\\n return 1\\n }\\n return 0\\n }\\n\\n comparePre (other) {\\n if (!(other instanceof SemVer)) {\\n other = new SemVer(other, this.options)\\n }\\n\\n // NOT having a prerelease is > having one\\n if (this.prerelease.length && !other.prerelease.length) {\\n return -1\\n } else if (!this.prerelease.length && other.prerelease.length) {\\n return 1\\n } else if (!this.prerelease.length && !other.prerelease.length) {\\n return 0\\n }\\n\\n let i = 0\\n do {\\n const a = this.prerelease[i]\\n const b = other.prerelease[i]\\n debug('prerelease compare', i, a, b)\\n if (a === undefined && b === undefined) {\\n return 0\\n } else if (b === undefined) {\\n return 1\\n } else if (a === undefined) {\\n return -1\\n } else if (a === b) {\\n continue\\n } else {\\n return compareIdentifiers(a, b)\\n }\\n } while (++i)\\n }\\n\\n compareBuild (other) {\\n if (!(other instanceof SemVer)) {\\n other = new SemVer(other, this.options)\\n }\\n\\n let i = 0\\n do {\\n const a = this.build[i]\\n const b = other.build[i]\\n debug('build compare', i, a, b)\\n if (a === undefined && b === undefined) {\\n return 0\\n } else if (b === undefined) {\\n return 1\\n } else if (a === undefined) {\\n return -1\\n } else if (a === b) {\\n continue\\n } else {\\n return compareIdentifiers(a, b)\\n }\\n } while (++i)\\n }\\n\\n // preminor will bump the version up to the next minor release, and immediately\\n // down to pre-release. premajor and prepatch work the same way.\\n inc (release, identifier, identifierBase) {\\n if (release.startsWith('pre')) {\\n if (!identifier && identifierBase === false) {\\n throw new Error('invalid increment argument: identifier is empty')\\n }\\n // Avoid an invalid semver results\\n if (identifier) {\\n const match = `-${identifier}`.match(this.options.loose ? re[t.PRERELEASELOOSE] : re[t.PRERELEASE])\\n if (!match || match[1] !== identifier) {\\n throw new Error(`invalid identifier: ${identifier}`)\\n }\\n }\\n }\\n\\n switch (release) {\\n case 'premajor':\\n this.prerelease.length = 0\\n this.patch = 0\\n this.minor = 0\\n this.major++\\n this.inc('pre', identifier, identifierBase)\\n break\\n case 'preminor':\\n this.prerelease.length = 0\\n this.patch = 0\\n this.minor++\\n this.inc('pre', identifier, identifierBase)\\n break\\n case 'prepatch':\\n // If this is already a prerelease, it will bump to the next version\\n // drop any prereleases that might already exist, since they are not\\n // relevant at this point.\\n this.prerelease.length = 0\\n this.inc('patch', identifier, identifierBase)\\n this.inc('pre', identifier, identifierBase)\\n break\\n // If the input is a non-prerelease version, this acts the same as\\n // prepatch.\\n case 'prerelease':\\n if (this.prerelease.length === 0) {\\n this.inc('patch', identifier, identifierBase)\\n }\\n this.inc('pre', identifier, identifierBase)\\n break\\n case 'release':\\n if (this.prerelease.length === 0) {\\n throw new Error(`version ${this.raw} is not a prerelease`)\\n }\\n this.prerelease.length = 0\\n break\\n\\n case 'major':\\n // If this is a pre-major version, bump up to the same major version.\\n // Otherwise increment major.\\n // 1.0.0-5 bumps to 1.0.0\\n // 1.1.0 bumps to 2.0.0\\n if (\\n this.minor !== 0 ||\\n this.patch !== 0 ||\\n this.prerelease.length === 0\\n ) {\\n this.major++\\n }\\n this.minor = 0\\n this.patch = 0\\n this.prerelease = []\\n break\\n case 'minor':\\n // If this is a pre-minor version, bump up to the same minor version.\\n // Otherwise increment minor.\\n // 1.2.0-5 bumps to 1.2.0\\n // 1.2.1 bumps to 1.3.0\\n if (this.patch !== 0 || this.prerelease.length === 0) {\\n this.minor++\\n }\\n this.patch = 0\\n this.prerelease = []\\n break\\n case 'patch':\\n // If this is not a pre-release version, it will increment the patch.\\n // If it is a pre-release it will bump up to the same patch version.\\n // 1.2.0-5 patches to 1.2.0\\n // 1.2.0 patches to 1.2.1\\n if (this.prerelease.length === 0) {\\n this.patch++\\n }\\n this.prerelease = []\\n break\\n // This probably shouldn't be used publicly.\\n // 1.0.0 'pre' would become 1.0.0-0 which is the wrong direction.\\n case 'pre': {\\n const base = Number(identifierBase) ? 1 : 0\\n\\n if (this.prerelease.length === 0) {\\n this.prerelease = [base]\\n } else {\\n let i = this.prerelease.length\\n while (--i >= 0) {\\n if (typeof this.prerelease[i] === 'number') {\\n this.prerelease[i]++\\n i = -2\\n }\\n }\\n if (i === -1) {\\n // didn't increment anything\\n if (identifier === this.prerelease.join('.') && identifierBase === false) {\\n throw new Error('invalid increment argument: identifier already exists')\\n }\\n this.prerelease.push(base)\\n }\\n }\\n if (identifier) {\\n // 1.2.0-beta.1 bumps to 1.2.0-beta.2,\\n // 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0\\n let prerelease = [identifier, base]\\n if (identifierBase === false) {\\n prerelease = [identifier]\\n }\\n if (compareIdentifiers(this.prerelease[0], identifier) === 0) {\\n if (isNaN(this.prerelease[1])) {\\n this.prerelease = prerelease\\n }\\n } else {\\n this.prerelease = prerelease\\n }\\n }\\n break\\n }\\n default:\\n throw new Error(`invalid increment argument: ${release}`)\\n }\\n this.raw = this.format()\\n if (this.build.length) {\\n this.raw += `+${this.build.join('.')}`\\n }\\n return this\\n }\\n}\\n\\nmodule.exports = SemVer\\n\",\"'use strict'\\n\\nconst SemVer = require('../classes/semver')\\nconst parse = (version, options, throwErrors = false) => {\\n if (version instanceof SemVer) {\\n return version\\n }\\n try {\\n return new SemVer(version, options)\\n } catch (er) {\\n if (!throwErrors) {\\n return null\\n }\\n throw er\\n }\\n}\\n\\nmodule.exports = parse\\n\",\"'use strict'\\n\\nconst parse = require('./parse')\\nconst valid = (version, options) => {\\n const v = parse(version, options)\\n return v ? v.version : null\\n}\\nmodule.exports = valid\\n\",\"'use strict'\\n\\nconst parse = require('./parse')\\nconst clean = (version, options) => {\\n const s = parse(version.trim().replace(/^[=v]+/, ''), options)\\n return s ? s.version : null\\n}\\nmodule.exports = clean\\n\",\"'use strict'\\n\\nconst SemVer = require('../classes/semver')\\n\\nconst inc = (version, release, options, identifier, identifierBase) => {\\n if (typeof (options) === 'string') {\\n identifierBase = identifier\\n identifier = options\\n options = undefined\\n }\\n\\n try {\\n return new SemVer(\\n version instanceof SemVer ? version.version : version,\\n options\\n ).inc(release, identifier, identifierBase).version\\n } catch (er) {\\n return null\\n }\\n}\\nmodule.exports = inc\\n\",\"'use strict'\\n\\nconst parse = require('./parse.js')\\n\\nconst diff = (version1, version2) => {\\n const v1 = parse(version1, null, true)\\n const v2 = parse(version2, null, true)\\n const comparison = v1.compare(v2)\\n\\n if (comparison === 0) {\\n return null\\n }\\n\\n const v1Higher = comparison > 0\\n const highVersion = v1Higher ? v1 : v2\\n const lowVersion = v1Higher ? v2 : v1\\n const highHasPre = !!highVersion.prerelease.length\\n const lowHasPre = !!lowVersion.prerelease.length\\n\\n if (lowHasPre && !highHasPre) {\\n // Going from prerelease -> no prerelease requires some special casing\\n\\n // If the low version has only a major, then it will always be a major\\n // Some examples:\\n // 1.0.0-1 -> 1.0.0\\n // 1.0.0-1 -> 1.1.1\\n // 1.0.0-1 -> 2.0.0\\n if (!lowVersion.patch && !lowVersion.minor) {\\n return 'major'\\n }\\n\\n // If the main part has no difference\\n if (lowVersion.compareMain(highVersion) === 0) {\\n if (lowVersion.minor && !lowVersion.patch) {\\n return 'minor'\\n }\\n return 'patch'\\n }\\n }\\n\\n // add the `pre` prefix if we are going to a prerelease version\\n const prefix = highHasPre ? 'pre' : ''\\n\\n if (v1.major !== v2.major) {\\n return prefix + 'major'\\n }\\n\\n if (v1.minor !== v2.minor) {\\n return prefix + 'minor'\\n }\\n\\n if (v1.patch !== v2.patch) {\\n return prefix + 'patch'\\n }\\n\\n // high and low are preleases\\n return 'prerelease'\\n}\\n\\nmodule.exports = diff\\n\",\"'use strict'\\n\\nconst SemVer = require('../classes/semver')\\nconst major = (a, loose) => new SemVer(a, loose).major\\nmodule.exports = major\\n\",\"'use strict'\\n\\nconst SemVer = require('../classes/semver')\\nconst minor = (a, loose) => new SemVer(a, loose).minor\\nmodule.exports = minor\\n\",\"'use strict'\\n\\nconst SemVer = require('../classes/semver')\\nconst patch = (a, loose) => new SemVer(a, loose).patch\\nmodule.exports = patch\\n\",\"'use strict'\\n\\nconst parse = require('./parse')\\nconst prerelease = (version, options) => {\\n const parsed = parse(version, options)\\n return (parsed && parsed.prerelease.length) ? parsed.prerelease : null\\n}\\nmodule.exports = prerelease\\n\",\"'use strict'\\n\\nconst SemVer = require('../classes/semver')\\nconst compare = (a, b, loose) =>\\n new SemVer(a, loose).compare(new SemVer(b, loose))\\n\\nmodule.exports = compare\\n\",\"'use strict'\\n\\nconst compare = require('./compare')\\nconst rcompare = (a, b, loose) => compare(b, a, loose)\\nmodule.exports = rcompare\\n\",\"'use strict'\\n\\nconst compare = require('./compare')\\nconst compareLoose = (a, b) => compare(a, b, true)\\nmodule.exports = compareLoose\\n\",\"'use strict'\\n\\nconst SemVer = require('../classes/semver')\\nconst compareBuild = (a, b, loose) => {\\n const versionA = new SemVer(a, loose)\\n const versionB = new SemVer(b, loose)\\n return versionA.compare(versionB) || versionA.compareBuild(versionB)\\n}\\nmodule.exports = compareBuild\\n\",\"'use strict'\\n\\nconst compareBuild = require('./compare-build')\\nconst sort = (list, loose) => list.sort((a, b) => compareBuild(a, b, loose))\\nmodule.exports = sort\\n\",\"'use strict'\\n\\nconst compareBuild = require('./compare-build')\\nconst rsort = (list, loose) => list.sort((a, b) => compareBuild(b, a, loose))\\nmodule.exports = rsort\\n\",\"'use strict'\\n\\nconst compare = require('./compare')\\nconst gt = (a, b, loose) => compare(a, b, loose) > 0\\nmodule.exports = gt\\n\",\"'use strict'\\n\\nconst compare = require('./compare')\\nconst lt = (a, b, loose) => compare(a, b, loose) < 0\\nmodule.exports = lt\\n\",\"'use strict'\\n\\nconst compare = require('./compare')\\nconst eq = (a, b, loose) => compare(a, b, loose) === 0\\nmodule.exports = eq\\n\",\"'use strict'\\n\\nconst compare = require('./compare')\\nconst neq = (a, b, loose) => compare(a, b, loose) !== 0\\nmodule.exports = neq\\n\",\"'use strict'\\n\\nconst compare = require('./compare')\\nconst gte = (a, b, loose) => compare(a, b, loose) >= 0\\nmodule.exports = gte\\n\",\"'use strict'\\n\\nconst compare = require('./compare')\\nconst lte = (a, b, loose) => compare(a, b, loose) <= 0\\nmodule.exports = lte\\n\",\"'use strict'\\n\\nconst eq = require('./eq')\\nconst neq = require('./neq')\\nconst gt = require('./gt')\\nconst gte = require('./gte')\\nconst lt = require('./lt')\\nconst lte = require('./lte')\\n\\nconst cmp = (a, op, b, loose) => {\\n switch (op) {\\n case '===':\\n if (typeof a === 'object') {\\n a = a.version\\n }\\n if (typeof b === 'object') {\\n b = b.version\\n }\\n return a === b\\n\\n case '!==':\\n if (typeof a === 'object') {\\n a = a.version\\n }\\n if (typeof b === 'object') {\\n b = b.version\\n }\\n return a !== b\\n\\n case '':\\n case '=':\\n case '==':\\n return eq(a, b, loose)\\n\\n case '!=':\\n return neq(a, b, loose)\\n\\n case '>':\\n return gt(a, b, loose)\\n\\n case '>=':\\n return gte(a, b, loose)\\n\\n case '<':\\n return lt(a, b, loose)\\n\\n case '<=':\\n return lte(a, b, loose)\\n\\n default:\\n throw new TypeError(`Invalid operator: ${op}`)\\n }\\n}\\nmodule.exports = cmp\\n\",\"'use strict'\\n\\nconst SemVer = require('../classes/semver')\\nconst parse = require('./parse')\\nconst { safeRe: re, t } = require('../internal/re')\\n\\nconst coerce = (version, options) => {\\n if (version instanceof SemVer) {\\n return version\\n }\\n\\n if (typeof version === 'number') {\\n version = String(version)\\n }\\n\\n if (typeof version !== 'string') {\\n return null\\n }\\n\\n options = options || {}\\n\\n let match = null\\n if (!options.rtl) {\\n match = version.match(options.includePrerelease ? re[t.COERCEFULL] : re[t.COERCE])\\n } else {\\n // Find the right-most coercible string that does not share\\n // a terminus with a more left-ward coercible string.\\n // Eg, '1.2.3.4' wants to coerce '2.3.4', not '3.4' or '4'\\n // With includePrerelease option set, '1.2.3.4-rc' wants to coerce '2.3.4-rc', not '2.3.4'\\n //\\n // Walk through the string checking with a /g regexp\\n // Manually set the index so as to pick up overlapping matches.\\n // Stop when we get a match that ends at the string end, since no\\n // coercible string can be more right-ward without the same terminus.\\n const coerceRtlRegex = options.includePrerelease ? re[t.COERCERTLFULL] : re[t.COERCERTL]\\n let next\\n while ((next = coerceRtlRegex.exec(version)) &&\\n (!match || match.index + match[0].length !== version.length)\\n ) {\\n if (!match ||\\n next.index + next[0].length !== match.index + match[0].length) {\\n match = next\\n }\\n coerceRtlRegex.lastIndex = next.index + next[1].length + next[2].length\\n }\\n // leave it in a clean state\\n coerceRtlRegex.lastIndex = -1\\n }\\n\\n if (match === null) {\\n return null\\n }\\n\\n const major = match[2]\\n const minor = match[3] || '0'\\n const patch = match[4] || '0'\\n const prerelease = options.includePrerelease && match[5] ? `-${match[5]}` : ''\\n const build = options.includePrerelease && match[6] ? `+${match[6]}` : ''\\n\\n return parse(`${major}.${minor}.${patch}${prerelease}${build}`, options)\\n}\\nmodule.exports = coerce\\n\",\"'use strict'\\n\\nclass LRUCache {\\n constructor () {\\n this.max = 1000\\n this.map = new Map()\\n }\\n\\n get (key) {\\n const value = this.map.get(key)\\n if (value === undefined) {\\n return undefined\\n } else {\\n // Remove the key from the map and add it to the end\\n this.map.delete(key)\\n this.map.set(key, value)\\n return value\\n }\\n }\\n\\n delete (key) {\\n return this.map.delete(key)\\n }\\n\\n set (key, value) {\\n const deleted = this.delete(key)\\n\\n if (!deleted && value !== undefined) {\\n // If cache is full, delete the least recently used item\\n if (this.map.size >= this.max) {\\n const firstKey = this.map.keys().next().value\\n this.delete(firstKey)\\n }\\n\\n this.map.set(key, value)\\n }\\n\\n return this\\n }\\n}\\n\\nmodule.exports = LRUCache\\n\",\"'use strict'\\n\\nconst SPACE_CHARACTERS = /\\\\s+/g\\n\\n// hoisted class for cyclic dependency\\nclass Range {\\n constructor (range, options) {\\n options = parseOptions(options)\\n\\n if (range instanceof Range) {\\n if (\\n range.loose === !!options.loose &&\\n range.includePrerelease === !!options.includePrerelease\\n ) {\\n return range\\n } else {\\n return new Range(range.raw, options)\\n }\\n }\\n\\n if (range instanceof Comparator) {\\n // just put it in the set and return\\n this.raw = range.value\\n this.set = [[range]]\\n this.formatted = undefined\\n return this\\n }\\n\\n this.options = options\\n this.loose = !!options.loose\\n this.includePrerelease = !!options.includePrerelease\\n\\n // First reduce all whitespace as much as possible so we do not have to rely\\n // on potentially slow regexes like \\\\s*. This is then stored and used for\\n // future error messages as well.\\n this.raw = range.trim().replace(SPACE_CHARACTERS, ' ')\\n\\n // First, split on ||\\n this.set = this.raw\\n .split('||')\\n // map the range to a 2d array of comparators\\n .map(r => this.parseRange(r.trim()))\\n // throw out any comparator lists that are empty\\n // this generally means that it was not a valid range, which is allowed\\n // in loose mode, but will still throw if the WHOLE range is invalid.\\n .filter(c => c.length)\\n\\n if (!this.set.length) {\\n throw new TypeError(`Invalid SemVer Range: ${this.raw}`)\\n }\\n\\n // if we have any that are not the null set, throw out null sets.\\n if (this.set.length > 1) {\\n // keep the first one, in case they're all null sets\\n const first = this.set[0]\\n this.set = this.set.filter(c => !isNullSet(c[0]))\\n if (this.set.length === 0) {\\n this.set = [first]\\n } else if (this.set.length > 1) {\\n // if we have any that are *, then the range is just *\\n for (const c of this.set) {\\n if (c.length === 1 && isAny(c[0])) {\\n this.set = [c]\\n break\\n }\\n }\\n }\\n }\\n\\n this.formatted = undefined\\n }\\n\\n get range () {\\n if (this.formatted === undefined) {\\n this.formatted = ''\\n for (let i = 0; i < this.set.length; i++) {\\n if (i > 0) {\\n this.formatted += '||'\\n }\\n const comps = this.set[i]\\n for (let k = 0; k < comps.length; k++) {\\n if (k > 0) {\\n this.formatted += ' '\\n }\\n this.formatted += comps[k].toString().trim()\\n }\\n }\\n }\\n return this.formatted\\n }\\n\\n format () {\\n return this.range\\n }\\n\\n toString () {\\n return this.range\\n }\\n\\n parseRange (range) {\\n // memoize range parsing for performance.\\n // this is a very hot path, and fully deterministic.\\n const memoOpts =\\n (this.options.includePrerelease && FLAG_INCLUDE_PRERELEASE) |\\n (this.options.loose && FLAG_LOOSE)\\n const memoKey = memoOpts + ':' + range\\n const cached = cache.get(memoKey)\\n if (cached) {\\n return cached\\n }\\n\\n const loose = this.options.loose\\n // `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4`\\n const hr = loose ? re[t.HYPHENRANGELOOSE] : re[t.HYPHENRANGE]\\n range = range.replace(hr, hyphenReplace(this.options.includePrerelease))\\n debug('hyphen replace', range)\\n\\n // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5`\\n range = range.replace(re[t.COMPARATORTRIM], comparatorTrimReplace)\\n debug('comparator trim', range)\\n\\n // `~ 1.2.3` => `~1.2.3`\\n range = range.replace(re[t.TILDETRIM], tildeTrimReplace)\\n debug('tilde trim', range)\\n\\n // `^ 1.2.3` => `^1.2.3`\\n range = range.replace(re[t.CARETTRIM], caretTrimReplace)\\n debug('caret trim', range)\\n\\n // At this point, the range is completely trimmed and\\n // ready to be split into comparators.\\n\\n let rangeList = range\\n .split(' ')\\n .map(comp => parseComparator(comp, this.options))\\n .join(' ')\\n .split(/\\\\s+/)\\n // >=0.0.0 is equivalent to *\\n .map(comp => replaceGTE0(comp, this.options))\\n\\n if (loose) {\\n // in loose mode, throw out any that are not valid comparators\\n rangeList = rangeList.filter(comp => {\\n debug('loose invalid filter', comp, this.options)\\n return !!comp.match(re[t.COMPARATORLOOSE])\\n })\\n }\\n debug('range list', rangeList)\\n\\n // if any comparators are the null set, then replace with JUST null set\\n // if more than one comparator, remove any * comparators\\n // also, don't include the same comparator more than once\\n const rangeMap = new Map()\\n const comparators = rangeList.map(comp => new Comparator(comp, this.options))\\n for (const comp of comparators) {\\n if (isNullSet(comp)) {\\n return [comp]\\n }\\n rangeMap.set(comp.value, comp)\\n }\\n if (rangeMap.size > 1 && rangeMap.has('')) {\\n rangeMap.delete('')\\n }\\n\\n const result = [...rangeMap.values()]\\n cache.set(memoKey, result)\\n return result\\n }\\n\\n intersects (range, options) {\\n if (!(range instanceof Range)) {\\n throw new TypeError('a Range is required')\\n }\\n\\n return this.set.some((thisComparators) => {\\n return (\\n isSatisfiable(thisComparators, options) &&\\n range.set.some((rangeComparators) => {\\n return (\\n isSatisfiable(rangeComparators, options) &&\\n thisComparators.every((thisComparator) => {\\n return rangeComparators.every((rangeComparator) => {\\n return thisComparator.intersects(rangeComparator, options)\\n })\\n })\\n )\\n })\\n )\\n })\\n }\\n\\n // if ANY of the sets match ALL of its comparators, then pass\\n test (version) {\\n if (!version) {\\n return false\\n }\\n\\n if (typeof version === 'string') {\\n try {\\n version = new SemVer(version, this.options)\\n } catch (er) {\\n return false\\n }\\n }\\n\\n for (let i = 0; i < this.set.length; i++) {\\n if (testSet(this.set[i], version, this.options)) {\\n return true\\n }\\n }\\n return false\\n }\\n}\\n\\nmodule.exports = Range\\n\\nconst LRU = require('../internal/lrucache')\\nconst cache = new LRU()\\n\\nconst parseOptions = require('../internal/parse-options')\\nconst Comparator = require('./comparator')\\nconst debug = require('../internal/debug')\\nconst SemVer = require('./semver')\\nconst {\\n safeRe: re,\\n t,\\n comparatorTrimReplace,\\n tildeTrimReplace,\\n caretTrimReplace,\\n} = require('../internal/re')\\nconst { FLAG_INCLUDE_PRERELEASE, FLAG_LOOSE } = require('../internal/constants')\\n\\nconst isNullSet = c => c.value === '<0.0.0-0'\\nconst isAny = c => c.value === ''\\n\\n// take a set of comparators and determine whether there\\n// exists a version which can satisfy it\\nconst isSatisfiable = (comparators, options) => {\\n let result = true\\n const remainingComparators = comparators.slice()\\n let testComparator = remainingComparators.pop()\\n\\n while (result && remainingComparators.length) {\\n result = remainingComparators.every((otherComparator) => {\\n return testComparator.intersects(otherComparator, options)\\n })\\n\\n testComparator = remainingComparators.pop()\\n }\\n\\n return result\\n}\\n\\n// comprised of xranges, tildes, stars, and gtlt's at this point.\\n// already replaced the hyphen ranges\\n// turn into a set of JUST comparators.\\nconst parseComparator = (comp, options) => {\\n comp = comp.replace(re[t.BUILD], '')\\n debug('comp', comp, options)\\n comp = replaceCarets(comp, options)\\n debug('caret', comp)\\n comp = replaceTildes(comp, options)\\n debug('tildes', comp)\\n comp = replaceXRanges(comp, options)\\n debug('xrange', comp)\\n comp = replaceStars(comp, options)\\n debug('stars', comp)\\n return comp\\n}\\n\\nconst isX = id => !id || id.toLowerCase() === 'x' || id === '*'\\n\\n// ~, ~> --> * (any, kinda silly)\\n// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0-0\\n// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0-0\\n// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0-0\\n// ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0-0\\n// ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0-0\\n// ~0.0.1 --> >=0.0.1 <0.1.0-0\\nconst replaceTildes = (comp, options) => {\\n return comp\\n .trim()\\n .split(/\\\\s+/)\\n .map((c) => replaceTilde(c, options))\\n .join(' ')\\n}\\n\\nconst replaceTilde = (comp, options) => {\\n const r = options.loose ? re[t.TILDELOOSE] : re[t.TILDE]\\n return comp.replace(r, (_, M, m, p, pr) => {\\n debug('tilde', comp, _, M, m, p, pr)\\n let ret\\n\\n if (isX(M)) {\\n ret = ''\\n } else if (isX(m)) {\\n ret = `>=${M}.0.0 <${+M + 1}.0.0-0`\\n } else if (isX(p)) {\\n // ~1.2 == >=1.2.0 <1.3.0-0\\n ret = `>=${M}.${m}.0 <${M}.${+m + 1}.0-0`\\n } else if (pr) {\\n debug('replaceTilde pr', pr)\\n ret = `>=${M}.${m}.${p}-${pr\\n } <${M}.${+m + 1}.0-0`\\n } else {\\n // ~1.2.3 == >=1.2.3 <1.3.0-0\\n ret = `>=${M}.${m}.${p\\n } <${M}.${+m + 1}.0-0`\\n }\\n\\n debug('tilde return', ret)\\n return ret\\n })\\n}\\n\\n// ^ --> * (any, kinda silly)\\n// ^2, ^2.x, ^2.x.x --> >=2.0.0 <3.0.0-0\\n// ^2.0, ^2.0.x --> >=2.0.0 <3.0.0-0\\n// ^1.2, ^1.2.x --> >=1.2.0 <2.0.0-0\\n// ^1.2.3 --> >=1.2.3 <2.0.0-0\\n// ^1.2.0 --> >=1.2.0 <2.0.0-0\\n// ^0.0.1 --> >=0.0.1 <0.0.2-0\\n// ^0.1.0 --> >=0.1.0 <0.2.0-0\\nconst replaceCarets = (comp, options) => {\\n return comp\\n .trim()\\n .split(/\\\\s+/)\\n .map((c) => replaceCaret(c, options))\\n .join(' ')\\n}\\n\\nconst replaceCaret = (comp, options) => {\\n debug('caret', comp, options)\\n const r = options.loose ? re[t.CARETLOOSE] : re[t.CARET]\\n const z = options.includePrerelease ? '-0' : ''\\n return comp.replace(r, (_, M, m, p, pr) => {\\n debug('caret', comp, _, M, m, p, pr)\\n let ret\\n\\n if (isX(M)) {\\n ret = ''\\n } else if (isX(m)) {\\n ret = `>=${M}.0.0${z} <${+M + 1}.0.0-0`\\n } else if (isX(p)) {\\n if (M === '0') {\\n ret = `>=${M}.${m}.0${z} <${M}.${+m + 1}.0-0`\\n } else {\\n ret = `>=${M}.${m}.0${z} <${+M + 1}.0.0-0`\\n }\\n } else if (pr) {\\n debug('replaceCaret pr', pr)\\n if (M === '0') {\\n if (m === '0') {\\n ret = `>=${M}.${m}.${p}-${pr\\n } <${M}.${m}.${+p + 1}-0`\\n } else {\\n ret = `>=${M}.${m}.${p}-${pr\\n } <${M}.${+m + 1}.0-0`\\n }\\n } else {\\n ret = `>=${M}.${m}.${p}-${pr\\n } <${+M + 1}.0.0-0`\\n }\\n } else {\\n debug('no pr')\\n if (M === '0') {\\n if (m === '0') {\\n ret = `>=${M}.${m}.${p\\n }${z} <${M}.${m}.${+p + 1}-0`\\n } else {\\n ret = `>=${M}.${m}.${p\\n }${z} <${M}.${+m + 1}.0-0`\\n }\\n } else {\\n ret = `>=${M}.${m}.${p\\n } <${+M + 1}.0.0-0`\\n }\\n }\\n\\n debug('caret return', ret)\\n return ret\\n })\\n}\\n\\nconst replaceXRanges = (comp, options) => {\\n debug('replaceXRanges', comp, options)\\n return comp\\n .split(/\\\\s+/)\\n .map((c) => replaceXRange(c, options))\\n .join(' ')\\n}\\n\\nconst replaceXRange = (comp, options) => {\\n comp = comp.trim()\\n const r = options.loose ? re[t.XRANGELOOSE] : re[t.XRANGE]\\n return comp.replace(r, (ret, gtlt, M, m, p, pr) => {\\n debug('xRange', comp, ret, gtlt, M, m, p, pr)\\n const xM = isX(M)\\n const xm = xM || isX(m)\\n const xp = xm || isX(p)\\n const anyX = xp\\n\\n if (gtlt === '=' && anyX) {\\n gtlt = ''\\n }\\n\\n // if we're including prereleases in the match, then we need\\n // to fix this to -0, the lowest possible prerelease value\\n pr = options.includePrerelease ? '-0' : ''\\n\\n if (xM) {\\n if (gtlt === '>' || gtlt === '<') {\\n // nothing is allowed\\n ret = '<0.0.0-0'\\n } else {\\n // nothing is forbidden\\n ret = '*'\\n }\\n } else if (gtlt && anyX) {\\n // we know patch is an x, because we have any x at all.\\n // replace X with 0\\n if (xm) {\\n m = 0\\n }\\n p = 0\\n\\n if (gtlt === '>') {\\n // >1 => >=2.0.0\\n // >1.2 => >=1.3.0\\n gtlt = '>='\\n if (xm) {\\n M = +M + 1\\n m = 0\\n p = 0\\n } else {\\n m = +m + 1\\n p = 0\\n }\\n } else if (gtlt === '<=') {\\n // <=0.7.x is actually <0.8.0, since any 0.7.x should\\n // pass. Similarly, <=7.x is actually <8.0.0, etc.\\n gtlt = '<'\\n if (xm) {\\n M = +M + 1\\n } else {\\n m = +m + 1\\n }\\n }\\n\\n if (gtlt === '<') {\\n pr = '-0'\\n }\\n\\n ret = `${gtlt + M}.${m}.${p}${pr}`\\n } else if (xm) {\\n ret = `>=${M}.0.0${pr} <${+M + 1}.0.0-0`\\n } else if (xp) {\\n ret = `>=${M}.${m}.0${pr\\n } <${M}.${+m + 1}.0-0`\\n }\\n\\n debug('xRange return', ret)\\n\\n return ret\\n })\\n}\\n\\n// Because * is AND-ed with everything else in the comparator,\\n// and '' means \\\"any version\\\", just remove the *s entirely.\\nconst replaceStars = (comp, options) => {\\n debug('replaceStars', comp, options)\\n // Looseness is ignored here. star is always as loose as it gets!\\n return comp\\n .trim()\\n .replace(re[t.STAR], '')\\n}\\n\\nconst replaceGTE0 = (comp, options) => {\\n debug('replaceGTE0', comp, options)\\n return comp\\n .trim()\\n .replace(re[options.includePrerelease ? t.GTE0PRE : t.GTE0], '')\\n}\\n\\n// This function is passed to string.replace(re[t.HYPHENRANGE])\\n// M, m, patch, prerelease, build\\n// 1.2 - 3.4.5 => >=1.2.0 <=3.4.5\\n// 1.2.3 - 3.4 => >=1.2.0 <3.5.0-0 Any 3.4.x will do\\n// 1.2 - 3.4 => >=1.2.0 <3.5.0-0\\n// TODO build?\\nconst hyphenReplace = incPr => ($0,\\n from, fM, fm, fp, fpr, fb,\\n to, tM, tm, tp, tpr) => {\\n if (isX(fM)) {\\n from = ''\\n } else if (isX(fm)) {\\n from = `>=${fM}.0.0${incPr ? '-0' : ''}`\\n } else if (isX(fp)) {\\n from = `>=${fM}.${fm}.0${incPr ? '-0' : ''}`\\n } else if (fpr) {\\n from = `>=${from}`\\n } else {\\n from = `>=${from}${incPr ? '-0' : ''}`\\n }\\n\\n if (isX(tM)) {\\n to = ''\\n } else if (isX(tm)) {\\n to = `<${+tM + 1}.0.0-0`\\n } else if (isX(tp)) {\\n to = `<${tM}.${+tm + 1}.0-0`\\n } else if (tpr) {\\n to = `<=${tM}.${tm}.${tp}-${tpr}`\\n } else if (incPr) {\\n to = `<${tM}.${tm}.${+tp + 1}-0`\\n } else {\\n to = `<=${to}`\\n }\\n\\n return `${from} ${to}`.trim()\\n}\\n\\nconst testSet = (set, version, options) => {\\n for (let i = 0; i < set.length; i++) {\\n if (!set[i].test(version)) {\\n return false\\n }\\n }\\n\\n if (version.prerelease.length && !options.includePrerelease) {\\n // Find the set of versions that are allowed to have prereleases\\n // For example, ^1.2.3-pr.1 desugars to >=1.2.3-pr.1 <2.0.0\\n // That should allow `1.2.3-pr.2` to pass.\\n // However, `1.2.4-alpha.notready` should NOT be allowed,\\n // even though it's within the range set by the comparators.\\n for (let i = 0; i < set.length; i++) {\\n debug(set[i].semver)\\n if (set[i].semver === Comparator.ANY) {\\n continue\\n }\\n\\n if (set[i].semver.prerelease.length > 0) {\\n const allowed = set[i].semver\\n if (allowed.major === version.major &&\\n allowed.minor === version.minor &&\\n allowed.patch === version.patch) {\\n return true\\n }\\n }\\n }\\n\\n // Version has a -pre, but it's not one of the ones we like.\\n return false\\n }\\n\\n return true\\n}\\n\",\"'use strict'\\n\\nconst ANY = Symbol('SemVer ANY')\\n// hoisted class for cyclic dependency\\nclass Comparator {\\n static get ANY () {\\n return ANY\\n }\\n\\n constructor (comp, options) {\\n options = parseOptions(options)\\n\\n if (comp instanceof Comparator) {\\n if (comp.loose === !!options.loose) {\\n return comp\\n } else {\\n comp = comp.value\\n }\\n }\\n\\n comp = comp.trim().split(/\\\\s+/).join(' ')\\n debug('comparator', comp, options)\\n this.options = options\\n this.loose = !!options.loose\\n this.parse(comp)\\n\\n if (this.semver === ANY) {\\n this.value = ''\\n } else {\\n this.value = this.operator + this.semver.version\\n }\\n\\n debug('comp', this)\\n }\\n\\n parse (comp) {\\n const r = this.options.loose ? re[t.COMPARATORLOOSE] : re[t.COMPARATOR]\\n const m = comp.match(r)\\n\\n if (!m) {\\n throw new TypeError(`Invalid comparator: ${comp}`)\\n }\\n\\n this.operator = m[1] !== undefined ? m[1] : ''\\n if (this.operator === '=') {\\n this.operator = ''\\n }\\n\\n // if it literally is just '>' or '' then allow anything.\\n if (!m[2]) {\\n this.semver = ANY\\n } else {\\n this.semver = new SemVer(m[2], this.options.loose)\\n }\\n }\\n\\n toString () {\\n return this.value\\n }\\n\\n test (version) {\\n debug('Comparator.test', version, this.options.loose)\\n\\n if (this.semver === ANY || version === ANY) {\\n return true\\n }\\n\\n if (typeof version === 'string') {\\n try {\\n version = new SemVer(version, this.options)\\n } catch (er) {\\n return false\\n }\\n }\\n\\n return cmp(version, this.operator, this.semver, this.options)\\n }\\n\\n intersects (comp, options) {\\n if (!(comp instanceof Comparator)) {\\n throw new TypeError('a Comparator is required')\\n }\\n\\n if (this.operator === '') {\\n if (this.value === '') {\\n return true\\n }\\n return new Range(comp.value, options).test(this.value)\\n } else if (comp.operator === '') {\\n if (comp.value === '') {\\n return true\\n }\\n return new Range(this.value, options).test(comp.semver)\\n }\\n\\n options = parseOptions(options)\\n\\n // Special cases where nothing can possibly be lower\\n if (options.includePrerelease &&\\n (this.value === '<0.0.0-0' || comp.value === '<0.0.0-0')) {\\n return false\\n }\\n if (!options.includePrerelease &&\\n (this.value.startsWith('<0.0.0') || comp.value.startsWith('<0.0.0'))) {\\n return false\\n }\\n\\n // Same direction increasing (> or >=)\\n if (this.operator.startsWith('>') && comp.operator.startsWith('>')) {\\n return true\\n }\\n // Same direction decreasing (< or <=)\\n if (this.operator.startsWith('<') && comp.operator.startsWith('<')) {\\n return true\\n }\\n // same SemVer and both sides are inclusive (<= or >=)\\n if (\\n (this.semver.version === comp.semver.version) &&\\n this.operator.includes('=') && comp.operator.includes('=')) {\\n return true\\n }\\n // opposite directions less than\\n if (cmp(this.semver, '<', comp.semver, options) &&\\n this.operator.startsWith('>') && comp.operator.startsWith('<')) {\\n return true\\n }\\n // opposite directions greater than\\n if (cmp(this.semver, '>', comp.semver, options) &&\\n this.operator.startsWith('<') && comp.operator.startsWith('>')) {\\n return true\\n }\\n return false\\n }\\n}\\n\\nmodule.exports = Comparator\\n\\nconst parseOptions = require('../internal/parse-options')\\nconst { safeRe: re, t } = require('../internal/re')\\nconst cmp = require('../functions/cmp')\\nconst debug = require('../internal/debug')\\nconst SemVer = require('./semver')\\nconst Range = require('./range')\\n\",\"'use strict'\\n\\nconst Range = require('../classes/range')\\nconst satisfies = (version, range, options) => {\\n try {\\n range = new Range(range, options)\\n } catch (er) {\\n return false\\n }\\n return range.test(version)\\n}\\nmodule.exports = satisfies\\n\",\"'use strict'\\n\\nconst Range = require('../classes/range')\\n\\n// Mostly just for testing and legacy API reasons\\nconst toComparators = (range, options) =>\\n new Range(range, options).set\\n .map(comp => comp.map(c => c.value).join(' ').trim().split(' '))\\n\\nmodule.exports = toComparators\\n\",\"'use strict'\\n\\nconst SemVer = require('../classes/semver')\\nconst Range = require('../classes/range')\\n\\nconst maxSatisfying = (versions, range, options) => {\\n let max = null\\n let maxSV = null\\n let rangeObj = null\\n try {\\n rangeObj = new Range(range, options)\\n } catch (er) {\\n return null\\n }\\n versions.forEach((v) => {\\n if (rangeObj.test(v)) {\\n // satisfies(v, range, options)\\n if (!max || maxSV.compare(v) === -1) {\\n // compare(max, v, true)\\n max = v\\n maxSV = new SemVer(max, options)\\n }\\n }\\n })\\n return max\\n}\\nmodule.exports = maxSatisfying\\n\",\"'use strict'\\n\\nconst SemVer = require('../classes/semver')\\nconst Range = require('../classes/range')\\nconst minSatisfying = (versions, range, options) => {\\n let min = null\\n let minSV = null\\n let rangeObj = null\\n try {\\n rangeObj = new Range(range, options)\\n } catch (er) {\\n return null\\n }\\n versions.forEach((v) => {\\n if (rangeObj.test(v)) {\\n // satisfies(v, range, options)\\n if (!min || minSV.compare(v) === 1) {\\n // compare(min, v, true)\\n min = v\\n minSV = new SemVer(min, options)\\n }\\n }\\n })\\n return min\\n}\\nmodule.exports = minSatisfying\\n\",\"'use strict'\\n\\nconst SemVer = require('../classes/semver')\\nconst Range = require('../classes/range')\\nconst gt = require('../functions/gt')\\n\\nconst minVersion = (range, loose) => {\\n range = new Range(range, loose)\\n\\n let minver = new SemVer('0.0.0')\\n if (range.test(minver)) {\\n return minver\\n }\\n\\n minver = new SemVer('0.0.0-0')\\n if (range.test(minver)) {\\n return minver\\n }\\n\\n minver = null\\n for (let i = 0; i < range.set.length; ++i) {\\n const comparators = range.set[i]\\n\\n let setMin = null\\n comparators.forEach((comparator) => {\\n // Clone to avoid manipulating the comparator's semver object.\\n const compver = new SemVer(comparator.semver.version)\\n switch (comparator.operator) {\\n case '>':\\n if (compver.prerelease.length === 0) {\\n compver.patch++\\n } else {\\n compver.prerelease.push(0)\\n }\\n compver.raw = compver.format()\\n /* fallthrough */\\n case '':\\n case '>=':\\n if (!setMin || gt(compver, setMin)) {\\n setMin = compver\\n }\\n break\\n case '<':\\n case '<=':\\n /* Ignore maximum versions */\\n break\\n /* istanbul ignore next */\\n default:\\n throw new Error(`Unexpected operation: ${comparator.operator}`)\\n }\\n })\\n if (setMin && (!minver || gt(minver, setMin))) {\\n minver = setMin\\n }\\n }\\n\\n if (minver && range.test(minver)) {\\n return minver\\n }\\n\\n return null\\n}\\nmodule.exports = minVersion\\n\",\"'use strict'\\n\\nconst Range = require('../classes/range')\\nconst validRange = (range, options) => {\\n try {\\n // Return '*' instead of '' so that truthiness works.\\n // This will throw if it's invalid anyway\\n return new Range(range, options).range || '*'\\n } catch (er) {\\n return null\\n }\\n}\\nmodule.exports = validRange\\n\",\"'use strict'\\n\\nconst SemVer = require('../classes/semver')\\nconst Comparator = require('../classes/comparator')\\nconst { ANY } = Comparator\\nconst Range = require('../classes/range')\\nconst satisfies = require('../functions/satisfies')\\nconst gt = require('../functions/gt')\\nconst lt = require('../functions/lt')\\nconst lte = require('../functions/lte')\\nconst gte = require('../functions/gte')\\n\\nconst outside = (version, range, hilo, options) => {\\n version = new SemVer(version, options)\\n range = new Range(range, options)\\n\\n let gtfn, ltefn, ltfn, comp, ecomp\\n switch (hilo) {\\n case '>':\\n gtfn = gt\\n ltefn = lte\\n ltfn = lt\\n comp = '>'\\n ecomp = '>='\\n break\\n case '<':\\n gtfn = lt\\n ltefn = gte\\n ltfn = gt\\n comp = '<'\\n ecomp = '<='\\n break\\n default:\\n throw new TypeError('Must provide a hilo val of \\\"<\\\" or \\\">\\\"')\\n }\\n\\n // If it satisfies the range it is not outside\\n if (satisfies(version, range, options)) {\\n return false\\n }\\n\\n // From now on, variable terms are as if we're in \\\"gtr\\\" mode.\\n // but note that everything is flipped for the \\\"ltr\\\" function.\\n\\n for (let i = 0; i < range.set.length; ++i) {\\n const comparators = range.set[i]\\n\\n let high = null\\n let low = null\\n\\n comparators.forEach((comparator) => {\\n if (comparator.semver === ANY) {\\n comparator = new Comparator('>=0.0.0')\\n }\\n high = high || comparator\\n low = low || comparator\\n if (gtfn(comparator.semver, high.semver, options)) {\\n high = comparator\\n } else if (ltfn(comparator.semver, low.semver, options)) {\\n low = comparator\\n }\\n })\\n\\n // If the edge version comparator has a operator then our version\\n // isn't outside it\\n if (high.operator === comp || high.operator === ecomp) {\\n return false\\n }\\n\\n // If the lowest version comparator has an operator and our version\\n // is less than it then it isn't higher than the range\\n if ((!low.operator || low.operator === comp) &&\\n ltefn(version, low.semver)) {\\n return false\\n } else if (low.operator === ecomp && ltfn(version, low.semver)) {\\n return false\\n }\\n }\\n return true\\n}\\n\\nmodule.exports = outside\\n\",\"'use strict'\\n\\n// Determine if version is greater than all the versions possible in the range.\\nconst outside = require('./outside')\\nconst gtr = (version, range, options) => outside(version, range, '>', options)\\nmodule.exports = gtr\\n\",\"'use strict'\\n\\nconst outside = require('./outside')\\n// Determine if version is less than all the versions possible in the range\\nconst ltr = (version, range, options) => outside(version, range, '<', options)\\nmodule.exports = ltr\\n\",\"'use strict'\\n\\nconst Range = require('../classes/range')\\nconst intersects = (r1, r2, options) => {\\n r1 = new Range(r1, options)\\n r2 = new Range(r2, options)\\n return r1.intersects(r2, options)\\n}\\nmodule.exports = intersects\\n\",\"'use strict'\\n\\n// given a set of versions and a range, create a \\\"simplified\\\" range\\n// that includes the same versions that the original range does\\n// If the original range is shorter than the simplified one, return that.\\nconst satisfies = require('../functions/satisfies.js')\\nconst compare = require('../functions/compare.js')\\nmodule.exports = (versions, range, options) => {\\n const set = []\\n let first = null\\n let prev = null\\n const v = versions.sort((a, b) => compare(a, b, options))\\n for (const version of v) {\\n const included = satisfies(version, range, options)\\n if (included) {\\n prev = version\\n if (!first) {\\n first = version\\n }\\n } else {\\n if (prev) {\\n set.push([first, prev])\\n }\\n prev = null\\n first = null\\n }\\n }\\n if (first) {\\n set.push([first, null])\\n }\\n\\n const ranges = []\\n for (const [min, max] of set) {\\n if (min === max) {\\n ranges.push(min)\\n } else if (!max && min === v[0]) {\\n ranges.push('*')\\n } else if (!max) {\\n ranges.push(`>=${min}`)\\n } else if (min === v[0]) {\\n ranges.push(`<=${max}`)\\n } else {\\n ranges.push(`${min} - ${max}`)\\n }\\n }\\n const simplified = ranges.join(' || ')\\n const original = typeof range.raw === 'string' ? range.raw : String(range)\\n return simplified.length < original.length ? simplified : range\\n}\\n\",\"'use strict'\\n\\nconst Range = require('../classes/range.js')\\nconst Comparator = require('../classes/comparator.js')\\nconst { ANY } = Comparator\\nconst satisfies = require('../functions/satisfies.js')\\nconst compare = require('../functions/compare.js')\\n\\n// Complex range `r1 || r2 || ...` is a subset of `R1 || R2 || ...` iff:\\n// - Every simple range `r1, r2, ...` is a null set, OR\\n// - Every simple range `r1, r2, ...` which is not a null set is a subset of\\n// some `R1, R2, ...`\\n//\\n// Simple range `c1 c2 ...` is a subset of simple range `C1 C2 ...` iff:\\n// - If c is only the ANY comparator\\n// - If C is only the ANY comparator, return true\\n// - Else if in prerelease mode, return false\\n// - else replace c with `[>=0.0.0]`\\n// - If C is only the ANY comparator\\n// - if in prerelease mode, return true\\n// - else replace C with `[>=0.0.0]`\\n// - Let EQ be the set of = comparators in c\\n// - If EQ is more than one, return true (null set)\\n// - Let GT be the highest > or >= comparator in c\\n// - Let LT be the lowest < or <= comparator in c\\n// - If GT and LT, and GT.semver > LT.semver, return true (null set)\\n// - If any C is a = range, and GT or LT are set, return false\\n// - If EQ\\n// - If GT, and EQ does not satisfy GT, return true (null set)\\n// - If LT, and EQ does not satisfy LT, return true (null set)\\n// - If EQ satisfies every C, return true\\n// - Else return false\\n// - If GT\\n// - If GT.semver is lower than any > or >= comp in C, return false\\n// - If GT is >=, and GT.semver does not satisfy every C, return false\\n// - If GT.semver has a prerelease, and not in prerelease mode\\n// - If no C has a prerelease and the GT.semver tuple, return false\\n// - If LT\\n// - If LT.semver is greater than any < or <= comp in C, return false\\n// - If LT is <=, and LT.semver does not satisfy every C, return false\\n// - If GT.semver has a prerelease, and not in prerelease mode\\n// - If no C has a prerelease and the LT.semver tuple, return false\\n// - Else return true\\n\\nconst subset = (sub, dom, options = {}) => {\\n if (sub === dom) {\\n return true\\n }\\n\\n sub = new Range(sub, options)\\n dom = new Range(dom, options)\\n let sawNonNull = false\\n\\n OUTER: for (const simpleSub of sub.set) {\\n for (const simpleDom of dom.set) {\\n const isSub = simpleSubset(simpleSub, simpleDom, options)\\n sawNonNull = sawNonNull || isSub !== null\\n if (isSub) {\\n continue OUTER\\n }\\n }\\n // the null set is a subset of everything, but null simple ranges in\\n // a complex range should be ignored. so if we saw a non-null range,\\n // then we know this isn't a subset, but if EVERY simple range was null,\\n // then it is a subset.\\n if (sawNonNull) {\\n return false\\n }\\n }\\n return true\\n}\\n\\nconst minimumVersionWithPreRelease = [new Comparator('>=0.0.0-0')]\\nconst minimumVersion = [new Comparator('>=0.0.0')]\\n\\nconst simpleSubset = (sub, dom, options) => {\\n if (sub === dom) {\\n return true\\n }\\n\\n if (sub.length === 1 && sub[0].semver === ANY) {\\n if (dom.length === 1 && dom[0].semver === ANY) {\\n return true\\n } else if (options.includePrerelease) {\\n sub = minimumVersionWithPreRelease\\n } else {\\n sub = minimumVersion\\n }\\n }\\n\\n if (dom.length === 1 && dom[0].semver === ANY) {\\n if (options.includePrerelease) {\\n return true\\n } else {\\n dom = minimumVersion\\n }\\n }\\n\\n const eqSet = new Set()\\n let gt, lt\\n for (const c of sub) {\\n if (c.operator === '>' || c.operator === '>=') {\\n gt = higherGT(gt, c, options)\\n } else if (c.operator === '<' || c.operator === '<=') {\\n lt = lowerLT(lt, c, options)\\n } else {\\n eqSet.add(c.semver)\\n }\\n }\\n\\n if (eqSet.size > 1) {\\n return null\\n }\\n\\n let gtltComp\\n if (gt && lt) {\\n gtltComp = compare(gt.semver, lt.semver, options)\\n if (gtltComp > 0) {\\n return null\\n } else if (gtltComp === 0 && (gt.operator !== '>=' || lt.operator !== '<=')) {\\n return null\\n }\\n }\\n\\n // will iterate one or zero times\\n for (const eq of eqSet) {\\n if (gt && !satisfies(eq, String(gt), options)) {\\n return null\\n }\\n\\n if (lt && !satisfies(eq, String(lt), options)) {\\n return null\\n }\\n\\n for (const c of dom) {\\n if (!satisfies(eq, String(c), options)) {\\n return false\\n }\\n }\\n\\n return true\\n }\\n\\n let higher, lower\\n let hasDomLT, hasDomGT\\n // if the subset has a prerelease, we need a comparator in the superset\\n // with the same tuple and a prerelease, or it's not a subset\\n let needDomLTPre = lt &&\\n !options.includePrerelease &&\\n lt.semver.prerelease.length ? lt.semver : false\\n let needDomGTPre = gt &&\\n !options.includePrerelease &&\\n gt.semver.prerelease.length ? gt.semver : false\\n // exception: <1.2.3-0 is the same as <1.2.3\\n if (needDomLTPre && needDomLTPre.prerelease.length === 1 &&\\n lt.operator === '<' && needDomLTPre.prerelease[0] === 0) {\\n needDomLTPre = false\\n }\\n\\n for (const c of dom) {\\n hasDomGT = hasDomGT || c.operator === '>' || c.operator === '>='\\n hasDomLT = hasDomLT || c.operator === '<' || c.operator === '<='\\n if (gt) {\\n if (needDomGTPre) {\\n if (c.semver.prerelease && c.semver.prerelease.length &&\\n c.semver.major === needDomGTPre.major &&\\n c.semver.minor === needDomGTPre.minor &&\\n c.semver.patch === needDomGTPre.patch) {\\n needDomGTPre = false\\n }\\n }\\n if (c.operator === '>' || c.operator === '>=') {\\n higher = higherGT(gt, c, options)\\n if (higher === c && higher !== gt) {\\n return false\\n }\\n } else if (gt.operator === '>=' && !satisfies(gt.semver, String(c), options)) {\\n return false\\n }\\n }\\n if (lt) {\\n if (needDomLTPre) {\\n if (c.semver.prerelease && c.semver.prerelease.length &&\\n c.semver.major === needDomLTPre.major &&\\n c.semver.minor === needDomLTPre.minor &&\\n c.semver.patch === needDomLTPre.patch) {\\n needDomLTPre = false\\n }\\n }\\n if (c.operator === '<' || c.operator === '<=') {\\n lower = lowerLT(lt, c, options)\\n if (lower === c && lower !== lt) {\\n return false\\n }\\n } else if (lt.operator === '<=' && !satisfies(lt.semver, String(c), options)) {\\n return false\\n }\\n }\\n if (!c.operator && (lt || gt) && gtltComp !== 0) {\\n return false\\n }\\n }\\n\\n // if there was a < or >, and nothing in the dom, then must be false\\n // UNLESS it was limited by another range in the other direction.\\n // Eg, >1.0.0 <1.0.1 is still a subset of <2.0.0\\n if (gt && hasDomLT && !lt && gtltComp !== 0) {\\n return false\\n }\\n\\n if (lt && hasDomGT && !gt && gtltComp !== 0) {\\n return false\\n }\\n\\n // we needed a prerelease range in a specific tuple, but didn't get one\\n // then this isn't a subset. eg >=1.2.3-pre is not a subset of >=1.0.0,\\n // because it includes prereleases in the 1.2.3 tuple\\n if (needDomGTPre || needDomLTPre) {\\n return false\\n }\\n\\n return true\\n}\\n\\n// >=1.2.3 is lower than >1.2.3\\nconst higherGT = (a, b, options) => {\\n if (!a) {\\n return b\\n }\\n const comp = compare(a.semver, b.semver, options)\\n return comp > 0 ? a\\n : comp < 0 ? b\\n : b.operator === '>' && a.operator === '>=' ? b\\n : a\\n}\\n\\n// <=1.2.3 is higher than <1.2.3\\nconst lowerLT = (a, b, options) => {\\n if (!a) {\\n return b\\n }\\n const comp = compare(a.semver, b.semver, options)\\n return comp < 0 ? a\\n : comp > 0 ? b\\n : b.operator === '<' && a.operator === '<=' ? b\\n : a\\n}\\n\\nmodule.exports = subset\\n\",\"'use strict'\\n\\n// just pre-load all the stuff that index.js lazily exports\\nconst internalRe = require('./internal/re')\\nconst constants = require('./internal/constants')\\nconst SemVer = require('./classes/semver')\\nconst identifiers = require('./internal/identifiers')\\nconst parse = require('./functions/parse')\\nconst valid = require('./functions/valid')\\nconst clean = require('./functions/clean')\\nconst inc = require('./functions/inc')\\nconst diff = require('./functions/diff')\\nconst major = require('./functions/major')\\nconst minor = require('./functions/minor')\\nconst patch = require('./functions/patch')\\nconst prerelease = require('./functions/prerelease')\\nconst compare = require('./functions/compare')\\nconst rcompare = require('./functions/rcompare')\\nconst compareLoose = require('./functions/compare-loose')\\nconst compareBuild = require('./functions/compare-build')\\nconst sort = require('./functions/sort')\\nconst rsort = require('./functions/rsort')\\nconst gt = require('./functions/gt')\\nconst lt = require('./functions/lt')\\nconst eq = require('./functions/eq')\\nconst neq = require('./functions/neq')\\nconst gte = require('./functions/gte')\\nconst lte = require('./functions/lte')\\nconst cmp = require('./functions/cmp')\\nconst coerce = require('./functions/coerce')\\nconst Comparator = require('./classes/comparator')\\nconst Range = require('./classes/range')\\nconst satisfies = require('./functions/satisfies')\\nconst toComparators = require('./ranges/to-comparators')\\nconst maxSatisfying = require('./ranges/max-satisfying')\\nconst minSatisfying = require('./ranges/min-satisfying')\\nconst minVersion = require('./ranges/min-version')\\nconst validRange = require('./ranges/valid')\\nconst outside = require('./ranges/outside')\\nconst gtr = require('./ranges/gtr')\\nconst ltr = require('./ranges/ltr')\\nconst intersects = require('./ranges/intersects')\\nconst simplifyRange = require('./ranges/simplify')\\nconst subset = require('./ranges/subset')\\nmodule.exports = {\\n parse,\\n valid,\\n clean,\\n inc,\\n diff,\\n major,\\n minor,\\n patch,\\n prerelease,\\n compare,\\n rcompare,\\n compareLoose,\\n compareBuild,\\n sort,\\n rsort,\\n gt,\\n lt,\\n eq,\\n neq,\\n gte,\\n lte,\\n cmp,\\n coerce,\\n Comparator,\\n Range,\\n satisfies,\\n toComparators,\\n maxSatisfying,\\n minSatisfying,\\n minVersion,\\n validRange,\\n outside,\\n gtr,\\n ltr,\\n intersects,\\n simplifyRange,\\n subset,\\n SemVer,\\n re: internalRe.re,\\n src: internalRe.src,\\n tokens: internalRe.t,\\n SEMVER_SPEC_VERSION: constants.SEMVER_SPEC_VERSION,\\n RELEASE_TYPES: constants.RELEASE_TYPES,\\n compareIdentifiers: identifiers.compareIdentifiers,\\n rcompareIdentifiers: identifiers.rcompareIdentifiers,\\n}\\n\",\"import { satisfies, valid } from 'semver';\\n\\nconst version = Host.v1.document.get('text/semver-case');\\nconst ranges = ['>=1.2.0 <2.0.0', '^1.2.0', '~1.2.3'];\\n\\nexport default {\\n version,\\n valid: valid(version) !== null,\\n checks: ranges.map((range) => ({ range, ok: satisfies(version, range) })),\\n};\\n\"],\"version\":3}", + "originMeta": { + "originalPath": "node_modules/.pnpm/semver@7.7.3/node_modules/semver/classes/comparator.js", + "packageName": "semver", + "packageVersion": "7.7.3", + "integrity": "483aad47a5ae3669a320d313a6ce1be9be705b5c52775cba1b4f45d1fada0562" + } + } + ], + "builderVersion": "deterministic-builder-v1", + "dependencyIntegrity": "483aad47a5ae3669a320d313a6ce1be9be705b5c52775cba1b4f45d1fada0562", + "diagnosticsMeta": { + "entryPath": "/workspace/apps/ecosystem-certifier/fixtures/positive/semver-entry.ts", + "modulePaths": [ + "./semver-entry.js" + ] + }, + "graphHash": "9215dccaba757b484b9b1c608c38ec06a9d4e4c98b0b16ddf6e1d9cf18c0d03f" + } + } + }, + "manifest": { + "abi_id": "Host.v1", + "abi_version": 1, + "functions": [ + { + "fn_id": 1, + "js_path": [ + "document", + "get" + ], + "effect": "READ", + "arity": 1, + "arg_schema": [ + { + "type": "string" + } + ], + "return_schema": { + "type": "dv" + }, + "gas": { + "schedule_id": "doc-read-v1", + "base": 20, + "k_arg_bytes": 1, + "k_ret_bytes": 1, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 4096, + "max_response_bytes": 262144, + "max_units": 1000, + "arg_utf8_max": [ + 2048 + ] + }, + "error_codes": [ + { + "code": "INVALID_PATH", + "tag": "host/invalid_path" + }, + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + }, + { + "code": "NOT_FOUND", + "tag": "host/not_found" + } + ] + }, + { + "fn_id": 2, + "js_path": [ + "document", + "getCanonical" + ], + "effect": "READ", + "arity": 1, + "arg_schema": [ + { + "type": "string" + } + ], + "return_schema": { + "type": "dv" + }, + "gas": { + "schedule_id": "doc-read-v1", + "base": 20, + "k_arg_bytes": 1, + "k_ret_bytes": 1, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 4096, + "max_response_bytes": 262144, + "max_units": 1000, + "arg_utf8_max": [ + 2048 + ] + }, + "error_codes": [ + { + "code": "INVALID_PATH", + "tag": "host/invalid_path" + }, + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + }, + { + "code": "NOT_FOUND", + "tag": "host/not_found" + } + ] + }, + { + "fn_id": 3, + "js_path": [ + "emit" + ], + "effect": "EMIT", + "arity": 1, + "arg_schema": [ + { + "type": "dv" + } + ], + "return_schema": { + "type": "null" + }, + "gas": { + "schedule_id": "emit-v1", + "base": 5, + "k_arg_bytes": 1, + "k_ret_bytes": 0, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 32768, + "max_response_bytes": 64, + "max_units": 1024 + }, + "error_codes": [ + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + } + ] + } + ] + } + }, + { + "id": "green-base64", + "title": "base64-js deterministic roundtrip", + "kind": "ecosystem-green", + "badge": "Green ecosystem fixture", + "description": "Binary roundtrip coverage from the certified green ecosystem corpus.", + "certified": true, + "executionProfile": "compat-binary-v1", + "sourceKind": "module-pack", + "abiId": "Host.v2", + "gasLimit": "5000000", + "sourcePaths": [ + "libs/test-harness/fixtures/library-reuse/binary-base64-entry.ts" + ], + "sourceText": "import { fromByteArray, toByteArray } from 'base64-js';\n\nconst bytes = toByteArray('AQIDBAUGBwg=');\nconst sum = bytes.reduce((acc, value) => acc + value, 0);\n\nexport default {\n length: bytes.length,\n sum,\n first: bytes[0],\n last: bytes[bytes.length - 1],\n reencoded: fromByteArray(bytes),\n};\n", + "hostPreset": "certification", + "hostSummary": { + "label": "Certification host", + "description": "Provides the ecosystem-certifier text and binary documents used for workload certification.", + "documents": [ + "pack/metadata.json", + "pack/metadata.yaml", + "docs/a.md", + "docs/b.md", + "docs/c.md", + "docs/d.md", + "bytes/payload", + "bytes/flagship-extra", + "pack/attachment.deflated" + ] + }, + "docsLinks": [ + { + "label": "Workload certification", + "href": "/docs/workload-certification.md" + }, + { + "label": "Compatibility report", + "href": "/docs/ecosystem-compatibility-report.md" + } + ], + "supportsOogSearch": false, + "program": { + "version": 2, + "abiId": "Host.v2", + "abiVersion": 2, + "abiManifestHash": "ec5c3df99a1b0ab84b692996193707ae6c931382e75c96c7c14b4f8baaae5af2", + "engineBuildHash": "f91091cb7feb788df340305a877a9cadb0c6f4d13aea8a7da4040b6367d178ea", + "gasVersion": 8, + "executionProfile": "compat-binary-v1", + "sourceKind": "module-pack", + "source": { + "modulePack": { + "version": 1, + "entrySpecifier": "./binary-base64-entry.js", + "entryExport": "default", + "modules": [ + { + "specifier": "./binary-base64-entry.js", + "source": "var __create = Object.create;\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __getProtoOf = Object.getPrototypeOf;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __commonJS = (cb, mod) => function __require() {\n return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(\n // If the importer is in node compatibility mode or this is not an ESM\n // file that has been converted to a CommonJS file using a Babel-\n // compatible transform (i.e. \"__esModule\" has not been set), then set\n // \"default\" to the CommonJS \"module.exports\" for node compatibility.\n isNodeMode || !mod || !mod.__esModule ? __defProp(target, \"default\", { value: mod, enumerable: true }) : target,\n mod\n));\n\n// node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.js\nvar require_base64_js = __commonJS({\n \"node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.js\"(exports) {\n \"use strict\";\n exports.byteLength = byteLength;\n exports.toByteArray = toByteArray2;\n exports.fromByteArray = fromByteArray2;\n var lookup = [];\n var revLookup = [];\n var Arr = typeof Uint8Array !== \"undefined\" ? Uint8Array : Array;\n var code = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n for (i = 0, len = code.length; i < len; ++i) {\n lookup[i] = code[i];\n revLookup[code.charCodeAt(i)] = i;\n }\n var i;\n var len;\n revLookup[\"-\".charCodeAt(0)] = 62;\n revLookup[\"_\".charCodeAt(0)] = 63;\n function getLens(b64) {\n var len2 = b64.length;\n if (len2 % 4 > 0) {\n throw new Error(\"Invalid string. Length must be a multiple of 4\");\n }\n var validLen = b64.indexOf(\"=\");\n if (validLen === -1) validLen = len2;\n var placeHoldersLen = validLen === len2 ? 0 : 4 - validLen % 4;\n return [validLen, placeHoldersLen];\n }\n function byteLength(b64) {\n var lens = getLens(b64);\n var validLen = lens[0];\n var placeHoldersLen = lens[1];\n return (validLen + placeHoldersLen) * 3 / 4 - placeHoldersLen;\n }\n function _byteLength(b64, validLen, placeHoldersLen) {\n return (validLen + placeHoldersLen) * 3 / 4 - placeHoldersLen;\n }\n function toByteArray2(b64) {\n var tmp;\n var lens = getLens(b64);\n var validLen = lens[0];\n var placeHoldersLen = lens[1];\n var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen));\n var curByte = 0;\n var len2 = placeHoldersLen > 0 ? validLen - 4 : validLen;\n var i2;\n for (i2 = 0; i2 < len2; i2 += 4) {\n tmp = revLookup[b64.charCodeAt(i2)] << 18 | revLookup[b64.charCodeAt(i2 + 1)] << 12 | revLookup[b64.charCodeAt(i2 + 2)] << 6 | revLookup[b64.charCodeAt(i2 + 3)];\n arr[curByte++] = tmp >> 16 & 255;\n arr[curByte++] = tmp >> 8 & 255;\n arr[curByte++] = tmp & 255;\n }\n if (placeHoldersLen === 2) {\n tmp = revLookup[b64.charCodeAt(i2)] << 2 | revLookup[b64.charCodeAt(i2 + 1)] >> 4;\n arr[curByte++] = tmp & 255;\n }\n if (placeHoldersLen === 1) {\n tmp = revLookup[b64.charCodeAt(i2)] << 10 | revLookup[b64.charCodeAt(i2 + 1)] << 4 | revLookup[b64.charCodeAt(i2 + 2)] >> 2;\n arr[curByte++] = tmp >> 8 & 255;\n arr[curByte++] = tmp & 255;\n }\n return arr;\n }\n function tripletToBase64(num) {\n return lookup[num >> 18 & 63] + lookup[num >> 12 & 63] + lookup[num >> 6 & 63] + lookup[num & 63];\n }\n function encodeChunk(uint8, start, end) {\n var tmp;\n var output = [];\n for (var i2 = start; i2 < end; i2 += 3) {\n tmp = (uint8[i2] << 16 & 16711680) + (uint8[i2 + 1] << 8 & 65280) + (uint8[i2 + 2] & 255);\n output.push(tripletToBase64(tmp));\n }\n return output.join(\"\");\n }\n function fromByteArray2(uint8) {\n var tmp;\n var len2 = uint8.length;\n var extraBytes = len2 % 3;\n var parts = [];\n var maxChunkLength = 16383;\n for (var i2 = 0, len22 = len2 - extraBytes; i2 < len22; i2 += maxChunkLength) {\n parts.push(encodeChunk(uint8, i2, i2 + maxChunkLength > len22 ? len22 : i2 + maxChunkLength));\n }\n if (extraBytes === 1) {\n tmp = uint8[len2 - 1];\n parts.push(\n lookup[tmp >> 2] + lookup[tmp << 4 & 63] + \"==\"\n );\n } else if (extraBytes === 2) {\n tmp = (uint8[len2 - 2] << 8) + uint8[len2 - 1];\n parts.push(\n lookup[tmp >> 10] + lookup[tmp >> 4 & 63] + lookup[tmp << 2 & 63] + \"=\"\n );\n }\n return parts.join(\"\");\n }\n }\n});\n\n// libs/test-harness/fixtures/library-reuse/binary-base64-entry.ts\nvar import_base64_js = __toESM(require_base64_js(), 1);\nvar bytes = (0, import_base64_js.toByteArray)(\"AQIDBAUGBwg=\");\nvar sum = bytes.reduce((acc, value) => acc + value, 0);\nvar binary_base64_entry_default = {\n length: bytes.length,\n sum,\n first: bytes[0],\n last: bytes[bytes.length - 1],\n reencoded: (0, import_base64_js.fromByteArray)(bytes)\n};\nexport {\n binary_base64_entry_default as default\n};\n", + "sourceMap": "{\"mappings\":\"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\",\"names\":[\"toByteArray\",\"fromByteArray\",\"len\",\"i\",\"len2\"],\"sources\":[\"../node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.js\",\"../libs/test-harness/fixtures/library-reuse/binary-base64-entry.ts\"],\"sourcesContent\":[\"'use strict'\\n\\nexports.byteLength = byteLength\\nexports.toByteArray = toByteArray\\nexports.fromByteArray = fromByteArray\\n\\nvar lookup = []\\nvar revLookup = []\\nvar Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array\\n\\nvar code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'\\nfor (var i = 0, len = code.length; i < len; ++i) {\\n lookup[i] = code[i]\\n revLookup[code.charCodeAt(i)] = i\\n}\\n\\n// Support decoding URL-safe base64 strings, as Node.js does.\\n// See: https://en.wikipedia.org/wiki/Base64#URL_applications\\nrevLookup['-'.charCodeAt(0)] = 62\\nrevLookup['_'.charCodeAt(0)] = 63\\n\\nfunction getLens (b64) {\\n var len = b64.length\\n\\n if (len % 4 > 0) {\\n throw new Error('Invalid string. Length must be a multiple of 4')\\n }\\n\\n // Trim off extra bytes after placeholder bytes are found\\n // See: https://github.com/beatgammit/base64-js/issues/42\\n var validLen = b64.indexOf('=')\\n if (validLen === -1) validLen = len\\n\\n var placeHoldersLen = validLen === len\\n ? 0\\n : 4 - (validLen % 4)\\n\\n return [validLen, placeHoldersLen]\\n}\\n\\n// base64 is 4/3 + up to two characters of the original data\\nfunction byteLength (b64) {\\n var lens = getLens(b64)\\n var validLen = lens[0]\\n var placeHoldersLen = lens[1]\\n return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen\\n}\\n\\nfunction _byteLength (b64, validLen, placeHoldersLen) {\\n return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen\\n}\\n\\nfunction toByteArray (b64) {\\n var tmp\\n var lens = getLens(b64)\\n var validLen = lens[0]\\n var placeHoldersLen = lens[1]\\n\\n var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen))\\n\\n var curByte = 0\\n\\n // if there are placeholders, only get up to the last complete 4 chars\\n var len = placeHoldersLen > 0\\n ? validLen - 4\\n : validLen\\n\\n var i\\n for (i = 0; i < len; i += 4) {\\n tmp =\\n (revLookup[b64.charCodeAt(i)] << 18) |\\n (revLookup[b64.charCodeAt(i + 1)] << 12) |\\n (revLookup[b64.charCodeAt(i + 2)] << 6) |\\n revLookup[b64.charCodeAt(i + 3)]\\n arr[curByte++] = (tmp >> 16) & 0xFF\\n arr[curByte++] = (tmp >> 8) & 0xFF\\n arr[curByte++] = tmp & 0xFF\\n }\\n\\n if (placeHoldersLen === 2) {\\n tmp =\\n (revLookup[b64.charCodeAt(i)] << 2) |\\n (revLookup[b64.charCodeAt(i + 1)] >> 4)\\n arr[curByte++] = tmp & 0xFF\\n }\\n\\n if (placeHoldersLen === 1) {\\n tmp =\\n (revLookup[b64.charCodeAt(i)] << 10) |\\n (revLookup[b64.charCodeAt(i + 1)] << 4) |\\n (revLookup[b64.charCodeAt(i + 2)] >> 2)\\n arr[curByte++] = (tmp >> 8) & 0xFF\\n arr[curByte++] = tmp & 0xFF\\n }\\n\\n return arr\\n}\\n\\nfunction tripletToBase64 (num) {\\n return lookup[num >> 18 & 0x3F] +\\n lookup[num >> 12 & 0x3F] +\\n lookup[num >> 6 & 0x3F] +\\n lookup[num & 0x3F]\\n}\\n\\nfunction encodeChunk (uint8, start, end) {\\n var tmp\\n var output = []\\n for (var i = start; i < end; i += 3) {\\n tmp =\\n ((uint8[i] << 16) & 0xFF0000) +\\n ((uint8[i + 1] << 8) & 0xFF00) +\\n (uint8[i + 2] & 0xFF)\\n output.push(tripletToBase64(tmp))\\n }\\n return output.join('')\\n}\\n\\nfunction fromByteArray (uint8) {\\n var tmp\\n var len = uint8.length\\n var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes\\n var parts = []\\n var maxChunkLength = 16383 // must be multiple of 3\\n\\n // go through the array every three bytes, we'll deal with trailing stuff later\\n for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {\\n parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)))\\n }\\n\\n // pad the end with zeros, but make sure to not forget the extra bytes\\n if (extraBytes === 1) {\\n tmp = uint8[len - 1]\\n parts.push(\\n lookup[tmp >> 2] +\\n lookup[(tmp << 4) & 0x3F] +\\n '=='\\n )\\n } else if (extraBytes === 2) {\\n tmp = (uint8[len - 2] << 8) + uint8[len - 1]\\n parts.push(\\n lookup[tmp >> 10] +\\n lookup[(tmp >> 4) & 0x3F] +\\n lookup[(tmp << 2) & 0x3F] +\\n '='\\n )\\n }\\n\\n return parts.join('')\\n}\\n\",\"import { fromByteArray, toByteArray } from 'base64-js';\\n\\nconst bytes = toByteArray('AQIDBAUGBwg=');\\nconst sum = bytes.reduce((acc, value) => acc + value, 0);\\n\\nexport default {\\n length: bytes.length,\\n sum,\\n first: bytes[0],\\n last: bytes[bytes.length - 1],\\n reencoded: fromByteArray(bytes),\\n};\\n\"],\"version\":3}", + "originMeta": { + "originalPath": "node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.js", + "packageName": "base64-js", + "packageVersion": "1.5.1", + "integrity": "483aad47a5ae3669a320d313a6ce1be9be705b5c52775cba1b4f45d1fada0562" + } + } + ], + "builderVersion": "deterministic-builder-v1", + "dependencyIntegrity": "483aad47a5ae3669a320d313a6ce1be9be705b5c52775cba1b4f45d1fada0562", + "diagnosticsMeta": { + "entryPath": "/workspace/libs/test-harness/fixtures/library-reuse/binary-base64-entry.ts", + "modulePaths": [ + "./binary-base64-entry.js" + ] + }, + "graphHash": "d409281c0ea5deb67a631c31052e39836768a41ecc80e946d071853620684b98" + } + } + }, + "manifest": { + "abi_id": "Host.v2", + "abi_version": 2, + "functions": [ + { + "fn_id": 1, + "js_path": [ + "document", + "get" + ], + "effect": "READ", + "arity": 1, + "arg_schema": [ + { + "type": "string" + } + ], + "return_schema": { + "type": "dv" + }, + "gas": { + "schedule_id": "doc-read-v1", + "base": 20, + "k_arg_bytes": 1, + "k_ret_bytes": 1, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 4096, + "max_response_bytes": 262144, + "max_units": 1000, + "arg_utf8_max": [ + 2048 + ] + }, + "error_codes": [ + { + "code": "INVALID_PATH", + "tag": "host/invalid_path" + }, + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + }, + { + "code": "NOT_FOUND", + "tag": "host/not_found" + } + ] + }, + { + "fn_id": 2, + "js_path": [ + "document", + "getCanonical" + ], + "effect": "READ", + "arity": 1, + "arg_schema": [ + { + "type": "string" + } + ], + "return_schema": { + "type": "dv" + }, + "gas": { + "schedule_id": "doc-read-v1", + "base": 20, + "k_arg_bytes": 1, + "k_ret_bytes": 1, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 4096, + "max_response_bytes": 262144, + "max_units": 1000, + "arg_utf8_max": [ + 2048 + ] + }, + "error_codes": [ + { + "code": "INVALID_PATH", + "tag": "host/invalid_path" + }, + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + }, + { + "code": "NOT_FOUND", + "tag": "host/not_found" + } + ] + }, + { + "fn_id": 3, + "js_path": [ + "emit" + ], + "effect": "EMIT", + "arity": 1, + "arg_schema": [ + { + "type": "dv" + } + ], + "return_schema": { + "type": "null" + }, + "gas": { + "schedule_id": "emit-v1", + "base": 5, + "k_arg_bytes": 1, + "k_ret_bytes": 0, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 32768, + "max_response_bytes": 64, + "max_units": 1024 + }, + "error_codes": [ + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + } + ] + } + ] + } + }, + { + "id": "green-markdown-it", + "title": "markdown-it deterministic tokenization", + "kind": "ecosystem-green", + "badge": "Green ecosystem fixture", + "description": "A larger parser-oriented compatibility fixture running under deterministic constraints.", + "certified": true, + "executionProfile": "compat-binary-v1", + "sourceKind": "module-pack", + "abiId": "Host.v1", + "gasLimit": "1000000", + "sourcePaths": [ + "apps/ecosystem-certifier/fixtures/positive/markdown-it-entry.ts" + ], + "sourceText": "import MarkdownIt from 'markdown-it';\n\nconst md = new MarkdownIt({\n linkify: true,\n});\nconst source = Host.v1.document.get('text/markdown-case');\nconst tokens = md.parse(source, {});\nconst links = md.render(source).match(/ token.type),\n tokenCount: tokens.length,\n linkCount: links,\n};\n", + "hostPreset": "certification", + "hostSummary": { + "label": "Certification host", + "description": "Provides the ecosystem-certifier text and binary documents used for workload certification.", + "documents": [ + "pack/metadata.json", + "pack/metadata.yaml", + "docs/a.md", + "docs/b.md", + "docs/c.md", + "docs/d.md", + "bytes/payload", + "bytes/flagship-extra", + "pack/attachment.deflated" + ] + }, + "docsLinks": [ + { + "label": "Workload certification", + "href": "/docs/workload-certification.md" + }, + { + "label": "Compatibility report", + "href": "/docs/ecosystem-compatibility-report.md" + } + ], + "supportsOogSearch": false, + "program": { + "version": 2, + "abiId": "Host.v1", + "abiVersion": 1, + "abiManifestHash": "e23b0b2ee169900bbde7aff78e6ce20fead1715c60f8a8e3106d9959450a3d34", + "engineBuildHash": "f91091cb7feb788df340305a877a9cadb0c6f4d13aea8a7da4040b6367d178ea", + "gasVersion": 8, + "executionProfile": "compat-binary-v1", + "sourceKind": "module-pack", + "source": { + "modulePack": { + "version": 1, + "entrySpecifier": "./markdown-it-entry.js", + "entryExport": "default", + "modules": [ + { + "specifier": "./markdown-it-entry.js", + "source": "var __defProp = Object.defineProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/common/utils.mjs\nvar utils_exports = {};\n__export(utils_exports, {\n arrayReplaceAt: () => arrayReplaceAt,\n assign: () => assign,\n escapeHtml: () => escapeHtml,\n escapeRE: () => escapeRE,\n fromCodePoint: () => fromCodePoint2,\n has: () => has,\n isMdAsciiPunct: () => isMdAsciiPunct,\n isPunctChar: () => isPunctChar,\n isSpace: () => isSpace,\n isString: () => isString,\n isValidEntityCode: () => isValidEntityCode,\n isWhiteSpace: () => isWhiteSpace,\n lib: () => lib,\n normalizeReference: () => normalizeReference,\n unescapeAll: () => unescapeAll,\n unescapeMd: () => unescapeMd\n});\n\n// node_modules/.pnpm/mdurl@2.0.0/node_modules/mdurl/index.mjs\nvar mdurl_exports = {};\n__export(mdurl_exports, {\n decode: () => decode_default,\n encode: () => encode_default,\n format: () => format,\n parse: () => parse_default\n});\n\n// node_modules/.pnpm/mdurl@2.0.0/node_modules/mdurl/lib/decode.mjs\nvar decodeCache = {};\nfunction getDecodeCache(exclude) {\n let cache = decodeCache[exclude];\n if (cache) {\n return cache;\n }\n cache = decodeCache[exclude] = [];\n for (let i = 0; i < 128; i++) {\n const ch = String.fromCharCode(i);\n cache.push(ch);\n }\n for (let i = 0; i < exclude.length; i++) {\n const ch = exclude.charCodeAt(i);\n cache[ch] = \"%\" + (\"0\" + ch.toString(16).toUpperCase()).slice(-2);\n }\n return cache;\n}\nfunction decode(string, exclude) {\n if (typeof exclude !== \"string\") {\n exclude = decode.defaultChars;\n }\n const cache = getDecodeCache(exclude);\n return string.replace(/(%[a-f0-9]{2})+/gi, function(seq) {\n let result = \"\";\n for (let i = 0, l = seq.length; i < l; i += 3) {\n const b1 = parseInt(seq.slice(i + 1, i + 3), 16);\n if (b1 < 128) {\n result += cache[b1];\n continue;\n }\n if ((b1 & 224) === 192 && i + 3 < l) {\n const b2 = parseInt(seq.slice(i + 4, i + 6), 16);\n if ((b2 & 192) === 128) {\n const chr = b1 << 6 & 1984 | b2 & 63;\n if (chr < 128) {\n result += \"��\";\n } else {\n result += String.fromCharCode(chr);\n }\n i += 3;\n continue;\n }\n }\n if ((b1 & 240) === 224 && i + 6 < l) {\n const b2 = parseInt(seq.slice(i + 4, i + 6), 16);\n const b3 = parseInt(seq.slice(i + 7, i + 9), 16);\n if ((b2 & 192) === 128 && (b3 & 192) === 128) {\n const chr = b1 << 12 & 61440 | b2 << 6 & 4032 | b3 & 63;\n if (chr < 2048 || chr >= 55296 && chr <= 57343) {\n result += \"���\";\n } else {\n result += String.fromCharCode(chr);\n }\n i += 6;\n continue;\n }\n }\n if ((b1 & 248) === 240 && i + 9 < l) {\n const b2 = parseInt(seq.slice(i + 4, i + 6), 16);\n const b3 = parseInt(seq.slice(i + 7, i + 9), 16);\n const b4 = parseInt(seq.slice(i + 10, i + 12), 16);\n if ((b2 & 192) === 128 && (b3 & 192) === 128 && (b4 & 192) === 128) {\n let chr = b1 << 18 & 1835008 | b2 << 12 & 258048 | b3 << 6 & 4032 | b4 & 63;\n if (chr < 65536 || chr > 1114111) {\n result += \"����\";\n } else {\n chr -= 65536;\n result += String.fromCharCode(55296 + (chr >> 10), 56320 + (chr & 1023));\n }\n i += 9;\n continue;\n }\n }\n result += \"�\";\n }\n return result;\n });\n}\ndecode.defaultChars = \";/?:@&=+$,#\";\ndecode.componentChars = \"\";\nvar decode_default = decode;\n\n// node_modules/.pnpm/mdurl@2.0.0/node_modules/mdurl/lib/encode.mjs\nvar encodeCache = {};\nfunction getEncodeCache(exclude) {\n let cache = encodeCache[exclude];\n if (cache) {\n return cache;\n }\n cache = encodeCache[exclude] = [];\n for (let i = 0; i < 128; i++) {\n const ch = String.fromCharCode(i);\n if (/^[0-9a-z]$/i.test(ch)) {\n cache.push(ch);\n } else {\n cache.push(\"%\" + (\"0\" + i.toString(16).toUpperCase()).slice(-2));\n }\n }\n for (let i = 0; i < exclude.length; i++) {\n cache[exclude.charCodeAt(i)] = exclude[i];\n }\n return cache;\n}\nfunction encode(string, exclude, keepEscaped) {\n if (typeof exclude !== \"string\") {\n keepEscaped = exclude;\n exclude = encode.defaultChars;\n }\n if (typeof keepEscaped === \"undefined\") {\n keepEscaped = true;\n }\n const cache = getEncodeCache(exclude);\n let result = \"\";\n for (let i = 0, l = string.length; i < l; i++) {\n const code2 = string.charCodeAt(i);\n if (keepEscaped && code2 === 37 && i + 2 < l) {\n if (/^[0-9a-f]{2}$/i.test(string.slice(i + 1, i + 3))) {\n result += string.slice(i, i + 3);\n i += 2;\n continue;\n }\n }\n if (code2 < 128) {\n result += cache[code2];\n continue;\n }\n if (code2 >= 55296 && code2 <= 57343) {\n if (code2 >= 55296 && code2 <= 56319 && i + 1 < l) {\n const nextCode = string.charCodeAt(i + 1);\n if (nextCode >= 56320 && nextCode <= 57343) {\n result += encodeURIComponent(string[i] + string[i + 1]);\n i++;\n continue;\n }\n }\n result += \"%EF%BF%BD\";\n continue;\n }\n result += encodeURIComponent(string[i]);\n }\n return result;\n}\nencode.defaultChars = \";/?:@&=+$,-_.!~*'()#\";\nencode.componentChars = \"-_.!~*'()\";\nvar encode_default = encode;\n\n// node_modules/.pnpm/mdurl@2.0.0/node_modules/mdurl/lib/format.mjs\nfunction format(url) {\n let result = \"\";\n result += url.protocol || \"\";\n result += url.slashes ? \"//\" : \"\";\n result += url.auth ? url.auth + \"@\" : \"\";\n if (url.hostname && url.hostname.indexOf(\":\") !== -1) {\n result += \"[\" + url.hostname + \"]\";\n } else {\n result += url.hostname || \"\";\n }\n result += url.port ? \":\" + url.port : \"\";\n result += url.pathname || \"\";\n result += url.search || \"\";\n result += url.hash || \"\";\n return result;\n}\n\n// node_modules/.pnpm/mdurl@2.0.0/node_modules/mdurl/lib/parse.mjs\nfunction Url() {\n this.protocol = null;\n this.slashes = null;\n this.auth = null;\n this.port = null;\n this.hostname = null;\n this.hash = null;\n this.search = null;\n this.pathname = null;\n}\nvar protocolPattern = /^([a-z0-9.+-]+:)/i;\nvar portPattern = /:[0-9]*$/;\nvar simplePathPattern = /^(\\/\\/?(?!\\/)[^\\?\\s]*)(\\?[^\\s]*)?$/;\nvar delims = [\"<\", \">\", '\"', \"`\", \" \", \"\\r\", \"\\n\", \"\t\"];\nvar unwise = [\"{\", \"}\", \"|\", \"\\\\\", \"^\", \"`\"].concat(delims);\nvar autoEscape = [\"'\"].concat(unwise);\nvar nonHostChars = [\"%\", \"/\", \"?\", \";\", \"#\"].concat(autoEscape);\nvar hostEndingChars = [\"/\", \"?\", \"#\"];\nvar hostnameMaxLen = 255;\nvar hostnamePartPattern = /^[+a-z0-9A-Z_-]{0,63}$/;\nvar hostnamePartStart = /^([+a-z0-9A-Z_-]{0,63})(.*)$/;\nvar hostlessProtocol = {\n javascript: true,\n \"javascript:\": true\n};\nvar slashedProtocol = {\n http: true,\n https: true,\n ftp: true,\n gopher: true,\n file: true,\n \"http:\": true,\n \"https:\": true,\n \"ftp:\": true,\n \"gopher:\": true,\n \"file:\": true\n};\nfunction urlParse(url, slashesDenoteHost) {\n if (url && url instanceof Url) return url;\n const u = new Url();\n u.parse(url, slashesDenoteHost);\n return u;\n}\nUrl.prototype.parse = function(url, slashesDenoteHost) {\n let lowerProto, hec, slashes;\n let rest = url;\n rest = rest.trim();\n if (!slashesDenoteHost && url.split(\"#\").length === 1) {\n const simplePath = simplePathPattern.exec(rest);\n if (simplePath) {\n this.pathname = simplePath[1];\n if (simplePath[2]) {\n this.search = simplePath[2];\n }\n return this;\n }\n }\n let proto = protocolPattern.exec(rest);\n if (proto) {\n proto = proto[0];\n lowerProto = proto.toLowerCase();\n this.protocol = proto;\n rest = rest.substr(proto.length);\n }\n if (slashesDenoteHost || proto || rest.match(/^\\/\\/[^@\\/]+@[^@\\/]+/)) {\n slashes = rest.substr(0, 2) === \"//\";\n if (slashes && !(proto && hostlessProtocol[proto])) {\n rest = rest.substr(2);\n this.slashes = true;\n }\n }\n if (!hostlessProtocol[proto] && (slashes || proto && !slashedProtocol[proto])) {\n let hostEnd = -1;\n for (let i = 0; i < hostEndingChars.length; i++) {\n hec = rest.indexOf(hostEndingChars[i]);\n if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) {\n hostEnd = hec;\n }\n }\n let auth, atSign;\n if (hostEnd === -1) {\n atSign = rest.lastIndexOf(\"@\");\n } else {\n atSign = rest.lastIndexOf(\"@\", hostEnd);\n }\n if (atSign !== -1) {\n auth = rest.slice(0, atSign);\n rest = rest.slice(atSign + 1);\n this.auth = auth;\n }\n hostEnd = -1;\n for (let i = 0; i < nonHostChars.length; i++) {\n hec = rest.indexOf(nonHostChars[i]);\n if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) {\n hostEnd = hec;\n }\n }\n if (hostEnd === -1) {\n hostEnd = rest.length;\n }\n if (rest[hostEnd - 1] === \":\") {\n hostEnd--;\n }\n const host = rest.slice(0, hostEnd);\n rest = rest.slice(hostEnd);\n this.parseHost(host);\n this.hostname = this.hostname || \"\";\n const ipv6Hostname = this.hostname[0] === \"[\" && this.hostname[this.hostname.length - 1] === \"]\";\n if (!ipv6Hostname) {\n const hostparts = this.hostname.split(/\\./);\n for (let i = 0, l = hostparts.length; i < l; i++) {\n const part = hostparts[i];\n if (!part) {\n continue;\n }\n if (!part.match(hostnamePartPattern)) {\n let newpart = \"\";\n for (let j = 0, k = part.length; j < k; j++) {\n if (part.charCodeAt(j) > 127) {\n newpart += \"x\";\n } else {\n newpart += part[j];\n }\n }\n if (!newpart.match(hostnamePartPattern)) {\n const validParts = hostparts.slice(0, i);\n const notHost = hostparts.slice(i + 1);\n const bit = part.match(hostnamePartStart);\n if (bit) {\n validParts.push(bit[1]);\n notHost.unshift(bit[2]);\n }\n if (notHost.length) {\n rest = notHost.join(\".\") + rest;\n }\n this.hostname = validParts.join(\".\");\n break;\n }\n }\n }\n }\n if (this.hostname.length > hostnameMaxLen) {\n this.hostname = \"\";\n }\n if (ipv6Hostname) {\n this.hostname = this.hostname.substr(1, this.hostname.length - 2);\n }\n }\n const hash = rest.indexOf(\"#\");\n if (hash !== -1) {\n this.hash = rest.substr(hash);\n rest = rest.slice(0, hash);\n }\n const qm = rest.indexOf(\"?\");\n if (qm !== -1) {\n this.search = rest.substr(qm);\n rest = rest.slice(0, qm);\n }\n if (rest) {\n this.pathname = rest;\n }\n if (slashedProtocol[lowerProto] && this.hostname && !this.pathname) {\n this.pathname = \"\";\n }\n return this;\n};\nUrl.prototype.parseHost = function(host) {\n let port = portPattern.exec(host);\n if (port) {\n port = port[0];\n if (port !== \":\") {\n this.port = port.substr(1);\n }\n host = host.substr(0, host.length - port.length);\n }\n if (host) {\n this.hostname = host;\n }\n};\nvar parse_default = urlParse;\n\n// node_modules/.pnpm/uc.micro@2.1.0/node_modules/uc.micro/index.mjs\nvar uc_exports = {};\n__export(uc_exports, {\n Any: () => regex_default,\n Cc: () => regex_default2,\n Cf: () => regex_default3,\n P: () => regex_default4,\n S: () => regex_default5,\n Z: () => regex_default6\n});\n\n// node_modules/.pnpm/uc.micro@2.1.0/node_modules/uc.micro/properties/Any/regex.mjs\nvar regex_default = /[\\0-\\uD7FF\\uE000-\\uFFFF]|[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]|[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?:[^\\uD800-\\uDBFF]|^)[\\uDC00-\\uDFFF]/;\n\n// node_modules/.pnpm/uc.micro@2.1.0/node_modules/uc.micro/categories/Cc/regex.mjs\nvar regex_default2 = /[\\0-\\x1F\\x7F-\\x9F]/;\n\n// node_modules/.pnpm/uc.micro@2.1.0/node_modules/uc.micro/categories/Cf/regex.mjs\nvar regex_default3 = /[\\xAD\\u0600-\\u0605\\u061C\\u06DD\\u070F\\u0890\\u0891\\u08E2\\u180E\\u200B-\\u200F\\u202A-\\u202E\\u2060-\\u2064\\u2066-\\u206F\\uFEFF\\uFFF9-\\uFFFB]|\\uD804[\\uDCBD\\uDCCD]|\\uD80D[\\uDC30-\\uDC3F]|\\uD82F[\\uDCA0-\\uDCA3]|\\uD834[\\uDD73-\\uDD7A]|\\uDB40[\\uDC01\\uDC20-\\uDC7F]/;\n\n// node_modules/.pnpm/uc.micro@2.1.0/node_modules/uc.micro/categories/P/regex.mjs\nvar regex_default4 = /[!-#%-\\*,-\\/:;\\?@\\[-\\]_\\{\\}\\xA1\\xA7\\xAB\\xB6\\xB7\\xBB\\xBF\\u037E\\u0387\\u055A-\\u055F\\u0589\\u058A\\u05BE\\u05C0\\u05C3\\u05C6\\u05F3\\u05F4\\u0609\\u060A\\u060C\\u060D\\u061B\\u061D-\\u061F\\u066A-\\u066D\\u06D4\\u0700-\\u070D\\u07F7-\\u07F9\\u0830-\\u083E\\u085E\\u0964\\u0965\\u0970\\u09FD\\u0A76\\u0AF0\\u0C77\\u0C84\\u0DF4\\u0E4F\\u0E5A\\u0E5B\\u0F04-\\u0F12\\u0F14\\u0F3A-\\u0F3D\\u0F85\\u0FD0-\\u0FD4\\u0FD9\\u0FDA\\u104A-\\u104F\\u10FB\\u1360-\\u1368\\u1400\\u166E\\u169B\\u169C\\u16EB-\\u16ED\\u1735\\u1736\\u17D4-\\u17D6\\u17D8-\\u17DA\\u1800-\\u180A\\u1944\\u1945\\u1A1E\\u1A1F\\u1AA0-\\u1AA6\\u1AA8-\\u1AAD\\u1B5A-\\u1B60\\u1B7D\\u1B7E\\u1BFC-\\u1BFF\\u1C3B-\\u1C3F\\u1C7E\\u1C7F\\u1CC0-\\u1CC7\\u1CD3\\u2010-\\u2027\\u2030-\\u2043\\u2045-\\u2051\\u2053-\\u205E\\u207D\\u207E\\u208D\\u208E\\u2308-\\u230B\\u2329\\u232A\\u2768-\\u2775\\u27C5\\u27C6\\u27E6-\\u27EF\\u2983-\\u2998\\u29D8-\\u29DB\\u29FC\\u29FD\\u2CF9-\\u2CFC\\u2CFE\\u2CFF\\u2D70\\u2E00-\\u2E2E\\u2E30-\\u2E4F\\u2E52-\\u2E5D\\u3001-\\u3003\\u3008-\\u3011\\u3014-\\u301F\\u3030\\u303D\\u30A0\\u30FB\\uA4FE\\uA4FF\\uA60D-\\uA60F\\uA673\\uA67E\\uA6F2-\\uA6F7\\uA874-\\uA877\\uA8CE\\uA8CF\\uA8F8-\\uA8FA\\uA8FC\\uA92E\\uA92F\\uA95F\\uA9C1-\\uA9CD\\uA9DE\\uA9DF\\uAA5C-\\uAA5F\\uAADE\\uAADF\\uAAF0\\uAAF1\\uABEB\\uFD3E\\uFD3F\\uFE10-\\uFE19\\uFE30-\\uFE52\\uFE54-\\uFE61\\uFE63\\uFE68\\uFE6A\\uFE6B\\uFF01-\\uFF03\\uFF05-\\uFF0A\\uFF0C-\\uFF0F\\uFF1A\\uFF1B\\uFF1F\\uFF20\\uFF3B-\\uFF3D\\uFF3F\\uFF5B\\uFF5D\\uFF5F-\\uFF65]|\\uD800[\\uDD00-\\uDD02\\uDF9F\\uDFD0]|\\uD801\\uDD6F|\\uD802[\\uDC57\\uDD1F\\uDD3F\\uDE50-\\uDE58\\uDE7F\\uDEF0-\\uDEF6\\uDF39-\\uDF3F\\uDF99-\\uDF9C]|\\uD803[\\uDEAD\\uDF55-\\uDF59\\uDF86-\\uDF89]|\\uD804[\\uDC47-\\uDC4D\\uDCBB\\uDCBC\\uDCBE-\\uDCC1\\uDD40-\\uDD43\\uDD74\\uDD75\\uDDC5-\\uDDC8\\uDDCD\\uDDDB\\uDDDD-\\uDDDF\\uDE38-\\uDE3D\\uDEA9]|\\uD805[\\uDC4B-\\uDC4F\\uDC5A\\uDC5B\\uDC5D\\uDCC6\\uDDC1-\\uDDD7\\uDE41-\\uDE43\\uDE60-\\uDE6C\\uDEB9\\uDF3C-\\uDF3E]|\\uD806[\\uDC3B\\uDD44-\\uDD46\\uDDE2\\uDE3F-\\uDE46\\uDE9A-\\uDE9C\\uDE9E-\\uDEA2\\uDF00-\\uDF09]|\\uD807[\\uDC41-\\uDC45\\uDC70\\uDC71\\uDEF7\\uDEF8\\uDF43-\\uDF4F\\uDFFF]|\\uD809[\\uDC70-\\uDC74]|\\uD80B[\\uDFF1\\uDFF2]|\\uD81A[\\uDE6E\\uDE6F\\uDEF5\\uDF37-\\uDF3B\\uDF44]|\\uD81B[\\uDE97-\\uDE9A\\uDFE2]|\\uD82F\\uDC9F|\\uD836[\\uDE87-\\uDE8B]|\\uD83A[\\uDD5E\\uDD5F]/;\n\n// node_modules/.pnpm/uc.micro@2.1.0/node_modules/uc.micro/categories/S/regex.mjs\nvar regex_default5 = /[\\$\\+<->\\^`\\|~\\xA2-\\xA6\\xA8\\xA9\\xAC\\xAE-\\xB1\\xB4\\xB8\\xD7\\xF7\\u02C2-\\u02C5\\u02D2-\\u02DF\\u02E5-\\u02EB\\u02ED\\u02EF-\\u02FF\\u0375\\u0384\\u0385\\u03F6\\u0482\\u058D-\\u058F\\u0606-\\u0608\\u060B\\u060E\\u060F\\u06DE\\u06E9\\u06FD\\u06FE\\u07F6\\u07FE\\u07FF\\u0888\\u09F2\\u09F3\\u09FA\\u09FB\\u0AF1\\u0B70\\u0BF3-\\u0BFA\\u0C7F\\u0D4F\\u0D79\\u0E3F\\u0F01-\\u0F03\\u0F13\\u0F15-\\u0F17\\u0F1A-\\u0F1F\\u0F34\\u0F36\\u0F38\\u0FBE-\\u0FC5\\u0FC7-\\u0FCC\\u0FCE\\u0FCF\\u0FD5-\\u0FD8\\u109E\\u109F\\u1390-\\u1399\\u166D\\u17DB\\u1940\\u19DE-\\u19FF\\u1B61-\\u1B6A\\u1B74-\\u1B7C\\u1FBD\\u1FBF-\\u1FC1\\u1FCD-\\u1FCF\\u1FDD-\\u1FDF\\u1FED-\\u1FEF\\u1FFD\\u1FFE\\u2044\\u2052\\u207A-\\u207C\\u208A-\\u208C\\u20A0-\\u20C0\\u2100\\u2101\\u2103-\\u2106\\u2108\\u2109\\u2114\\u2116-\\u2118\\u211E-\\u2123\\u2125\\u2127\\u2129\\u212E\\u213A\\u213B\\u2140-\\u2144\\u214A-\\u214D\\u214F\\u218A\\u218B\\u2190-\\u2307\\u230C-\\u2328\\u232B-\\u2426\\u2440-\\u244A\\u249C-\\u24E9\\u2500-\\u2767\\u2794-\\u27C4\\u27C7-\\u27E5\\u27F0-\\u2982\\u2999-\\u29D7\\u29DC-\\u29FB\\u29FE-\\u2B73\\u2B76-\\u2B95\\u2B97-\\u2BFF\\u2CE5-\\u2CEA\\u2E50\\u2E51\\u2E80-\\u2E99\\u2E9B-\\u2EF3\\u2F00-\\u2FD5\\u2FF0-\\u2FFF\\u3004\\u3012\\u3013\\u3020\\u3036\\u3037\\u303E\\u303F\\u309B\\u309C\\u3190\\u3191\\u3196-\\u319F\\u31C0-\\u31E3\\u31EF\\u3200-\\u321E\\u322A-\\u3247\\u3250\\u3260-\\u327F\\u328A-\\u32B0\\u32C0-\\u33FF\\u4DC0-\\u4DFF\\uA490-\\uA4C6\\uA700-\\uA716\\uA720\\uA721\\uA789\\uA78A\\uA828-\\uA82B\\uA836-\\uA839\\uAA77-\\uAA79\\uAB5B\\uAB6A\\uAB6B\\uFB29\\uFBB2-\\uFBC2\\uFD40-\\uFD4F\\uFDCF\\uFDFC-\\uFDFF\\uFE62\\uFE64-\\uFE66\\uFE69\\uFF04\\uFF0B\\uFF1C-\\uFF1E\\uFF3E\\uFF40\\uFF5C\\uFF5E\\uFFE0-\\uFFE6\\uFFE8-\\uFFEE\\uFFFC\\uFFFD]|\\uD800[\\uDD37-\\uDD3F\\uDD79-\\uDD89\\uDD8C-\\uDD8E\\uDD90-\\uDD9C\\uDDA0\\uDDD0-\\uDDFC]|\\uD802[\\uDC77\\uDC78\\uDEC8]|\\uD805\\uDF3F|\\uD807[\\uDFD5-\\uDFF1]|\\uD81A[\\uDF3C-\\uDF3F\\uDF45]|\\uD82F\\uDC9C|\\uD833[\\uDF50-\\uDFC3]|\\uD834[\\uDC00-\\uDCF5\\uDD00-\\uDD26\\uDD29-\\uDD64\\uDD6A-\\uDD6C\\uDD83\\uDD84\\uDD8C-\\uDDA9\\uDDAE-\\uDDEA\\uDE00-\\uDE41\\uDE45\\uDF00-\\uDF56]|\\uD835[\\uDEC1\\uDEDB\\uDEFB\\uDF15\\uDF35\\uDF4F\\uDF6F\\uDF89\\uDFA9\\uDFC3]|\\uD836[\\uDC00-\\uDDFF\\uDE37-\\uDE3A\\uDE6D-\\uDE74\\uDE76-\\uDE83\\uDE85\\uDE86]|\\uD838[\\uDD4F\\uDEFF]|\\uD83B[\\uDCAC\\uDCB0\\uDD2E\\uDEF0\\uDEF1]|\\uD83C[\\uDC00-\\uDC2B\\uDC30-\\uDC93\\uDCA0-\\uDCAE\\uDCB1-\\uDCBF\\uDCC1-\\uDCCF\\uDCD1-\\uDCF5\\uDD0D-\\uDDAD\\uDDE6-\\uDE02\\uDE10-\\uDE3B\\uDE40-\\uDE48\\uDE50\\uDE51\\uDE60-\\uDE65\\uDF00-\\uDFFF]|\\uD83D[\\uDC00-\\uDED7\\uDEDC-\\uDEEC\\uDEF0-\\uDEFC\\uDF00-\\uDF76\\uDF7B-\\uDFD9\\uDFE0-\\uDFEB\\uDFF0]|\\uD83E[\\uDC00-\\uDC0B\\uDC10-\\uDC47\\uDC50-\\uDC59\\uDC60-\\uDC87\\uDC90-\\uDCAD\\uDCB0\\uDCB1\\uDD00-\\uDE53\\uDE60-\\uDE6D\\uDE70-\\uDE7C\\uDE80-\\uDE88\\uDE90-\\uDEBD\\uDEBF-\\uDEC5\\uDECE-\\uDEDB\\uDEE0-\\uDEE8\\uDEF0-\\uDEF8\\uDF00-\\uDF92\\uDF94-\\uDFCA]/;\n\n// node_modules/.pnpm/uc.micro@2.1.0/node_modules/uc.micro/categories/Z/regex.mjs\nvar regex_default6 = /[ \\xA0\\u1680\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]/;\n\n// node_modules/.pnpm/entities@4.5.0/node_modules/entities/lib/esm/generated/decode-data-html.js\nvar decode_data_html_default = new Uint16Array(\n // prettier-ignore\n 'ᵁ<Õıʊҝջאٵ۞ޢߖࠏ੊ઑඡ๭༉༦჊ረዡᐕᒝᓃᓟᔥ\\0\\0\\0\\0\\0\\0ᕫᛍᦍᰒᷝ὾⁠↰⊍⏀⏻⑂⠤⤒ⴈ⹈⿎〖㊺㘹㞬㣾㨨㩱㫠㬮ࠀEMabcfglmnoprstu\\\\bfms„‹•˜¦³¹ÈÏlig耻Æ䃆P耻&䀦cute耻Á䃁reve;䄂Āiyx}rc耻Â䃂;䐐r;쀀𝔄rave耻À䃀pha;䎑acr;䄀d;橓Āgp¡on;䄄f;쀀𝔸plyFunction;恡ing耻Å䃅Ācs¾Ãr;쀀𝒜ign;扔ilde耻Ã䃃ml耻Ä䃄ЀaceforsuåûþėĜĢħĪĀcrêòkslash;或Ŷöø;櫧ed;挆y;䐑ƀcrtąċĔause;戵noullis;愬a;䎒r;쀀𝔅pf;쀀𝔹eve;䋘còēmpeq;扎܀HOacdefhilorsuōőŖƀƞƢƵƷƺǜȕɳɸɾcy;䐧PY耻©䂩ƀcpyŝŢźute;䄆Ā;iŧŨ拒talDifferentialD;慅leys;愭ȀaeioƉƎƔƘron;䄌dil耻Ç䃇rc;䄈nint;戰ot;䄊ĀdnƧƭilla;䂸terDot;䂷òſi;䎧rcleȀDMPTLJNjǑǖot;抙inus;抖lus;投imes;抗oĀcsǢǸkwiseContourIntegral;戲eCurlyĀDQȃȏoubleQuote;思uote;怙ȀlnpuȞȨɇɕonĀ;eȥȦ户;橴ƀgitȯȶȺruent;扡nt;戯ourIntegral;戮ĀfrɌɎ;愂oduct;成nterClockwiseContourIntegral;戳oss;樯cr;쀀𝒞pĀ;Cʄʅ拓ap;才րDJSZacefiosʠʬʰʴʸˋ˗ˡ˦̳ҍĀ;oŹʥtrahd;椑cy;䐂cy;䐅cy;䐏ƀgrsʿ˄ˇger;怡r;憡hv;櫤Āayː˕ron;䄎;䐔lĀ;t˝˞戇a;䎔r;쀀𝔇Āaf˫̧Ācm˰̢riticalȀADGT̖̜̀̆cute;䂴oŴ̋̍;䋙bleAcute;䋝rave;䁠ilde;䋜ond;拄ferentialD;慆Ѱ̽\\0\\0\\0͔͂\\0Ѕf;쀀𝔻ƀ;DE͈͉͍䂨ot;惜qual;扐blèCDLRUVͣͲ΂ϏϢϸontourIntegraìȹoɴ͹\\0\\0ͻ»͉nArrow;懓Āeo·ΤftƀARTΐΖΡrrow;懐ightArrow;懔eåˊngĀLRΫτeftĀARγιrrow;柸ightArrow;柺ightArrow;柹ightĀATϘϞrrow;懒ee;抨pɁϩ\\0\\0ϯrrow;懑ownArrow;懕erticalBar;戥ǹABLRTaВЪаўѿͼrrowƀ;BUНОТ憓ar;椓pArrow;懵reve;䌑eft˒к\\0ц\\0ѐightVector;楐eeVector;楞ectorĀ;Bљњ憽ar;楖ightǔѧ\\0ѱeeVector;楟ectorĀ;BѺѻ懁ar;楗eeĀ;A҆҇护rrow;憧ĀctҒҗr;쀀𝒟rok;䄐ࠀNTacdfglmopqstuxҽӀӄӋӞӢӧӮӵԡԯԶՒ՝ՠեG;䅊H耻Ð䃐cute耻É䃉ƀaiyӒӗӜron;䄚rc耻Ê䃊;䐭ot;䄖r;쀀𝔈rave耻È䃈ement;戈ĀapӺӾcr;䄒tyɓԆ\\0\\0ԒmallSquare;旻erySmallSquare;斫ĀgpԦԪon;䄘f;쀀𝔼silon;䎕uĀaiԼՉlĀ;TՂՃ橵ilde;扂librium;懌Āci՗՚r;愰m;橳a;䎗ml耻Ë䃋Āipժկsts;戃onentialE;慇ʀcfiosօֈ֍ֲ׌y;䐤r;쀀𝔉lledɓ֗\\0\\0֣mallSquare;旼erySmallSquare;斪Ͱֺ\\0ֿ\\0\\0ׄf;쀀𝔽All;戀riertrf;愱cò׋؀JTabcdfgorstר׬ׯ׺؀ؒؖ؛؝أ٬ٲcy;䐃耻>䀾mmaĀ;d׷׸䎓;䏜reve;䄞ƀeiy؇،ؐdil;䄢rc;䄜;䐓ot;䄠r;쀀𝔊;拙pf;쀀𝔾eater̀EFGLSTصلَٖٛ٦qualĀ;Lؾؿ扥ess;招ullEqual;执reater;檢ess;扷lantEqual;橾ilde;扳cr;쀀𝒢;扫ЀAacfiosuڅڋږڛڞڪھۊRDcy;䐪Āctڐڔek;䋇;䁞irc;䄤r;愌lbertSpace;愋ǰگ\\0ڲf;愍izontalLine;攀Āctۃۅòکrok;䄦mpńېۘownHumðįqual;扏܀EJOacdfgmnostuۺ۾܃܇܎ܚܞܡܨ݄ݸދޏޕcy;䐕lig;䄲cy;䐁cute耻Í䃍Āiyܓܘrc耻Î䃎;䐘ot;䄰r;愑rave耻Ì䃌ƀ;apܠܯܿĀcgܴܷr;䄪inaryI;慈lieóϝǴ݉\\0ݢĀ;eݍݎ戬Āgrݓݘral;戫section;拂isibleĀCTݬݲomma;恣imes;恢ƀgptݿރވon;䄮f;쀀𝕀a;䎙cr;愐ilde;䄨ǫޚ\\0ޞcy;䐆l耻Ï䃏ʀcfosuެ޷޼߂ߐĀiyޱ޵rc;䄴;䐙r;쀀𝔍pf;쀀𝕁ǣ߇\\0ߌr;쀀𝒥rcy;䐈kcy;䐄΀HJacfosߤߨ߽߬߱ࠂࠈcy;䐥cy;䐌ppa;䎚Āey߶߻dil;䄶;䐚r;쀀𝔎pf;쀀𝕂cr;쀀𝒦րJTaceflmostࠥࠩࠬࡐࡣ঳সে্਷ੇcy;䐉耻<䀼ʀcmnpr࠷࠼ࡁࡄࡍute;䄹bda;䎛g;柪lacetrf;愒r;憞ƀaeyࡗ࡜ࡡron;䄽dil;䄻;䐛Āfsࡨ॰tԀACDFRTUVarࡾࢩࢱࣦ࣠ࣼयज़ΐ४Ānrࢃ࢏gleBracket;柨rowƀ;BR࢙࢚࢞憐ar;懤ightArrow;懆eiling;挈oǵࢷ\\0ࣃbleBracket;柦nǔࣈ\\0࣒eeVector;楡ectorĀ;Bࣛࣜ懃ar;楙loor;挊ightĀAV࣯ࣵrrow;憔ector;楎Āerँगeƀ;AVउऊऐ抣rrow;憤ector;楚iangleƀ;BEतथऩ抲ar;槏qual;抴pƀDTVषूौownVector;楑eeVector;楠ectorĀ;Bॖॗ憿ar;楘ectorĀ;B॥०憼ar;楒ightáΜs̀EFGLSTॾঋকঝঢভqualGreater;拚ullEqual;扦reater;扶ess;檡lantEqual;橽ilde;扲r;쀀𝔏Ā;eঽা拘ftarrow;懚idot;䄿ƀnpw৔ਖਛgȀLRlr৞৷ਂਐeftĀAR০৬rrow;柵ightArrow;柷ightArrow;柶eftĀarγਊightáοightáϊf;쀀𝕃erĀLRਢਬeftArrow;憙ightArrow;憘ƀchtਾੀੂòࡌ;憰rok;䅁;扪Ѐacefiosuਗ਼੝੠੷੼અઋ઎p;椅y;䐜Ādl੥੯iumSpace;恟lintrf;愳r;쀀𝔐nusPlus;戓pf;쀀𝕄cò੶;䎜ҀJacefostuણધભીଔଙඑ඗ඞcy;䐊cute;䅃ƀaey઴હાron;䅇dil;䅅;䐝ƀgswે૰଎ativeƀMTV૓૟૨ediumSpace;怋hiĀcn૦૘ë૙eryThiî૙tedĀGL૸ଆreaterGreateòٳessLesóੈLine;䀊r;쀀𝔑ȀBnptଢନଷ଺reak;恠BreakingSpace;䂠f;愕ڀ;CDEGHLNPRSTV୕ୖ୪୼஡௫ఄ౞಄ದ೘ൡඅ櫬Āou୛୤ngruent;扢pCap;扭oubleVerticalBar;戦ƀlqxஃஊ஛ement;戉ualĀ;Tஒஓ扠ilde;쀀≂̸ists;戄reater΀;EFGLSTஶஷ஽௉௓௘௥扯qual;扱ullEqual;쀀≧̸reater;쀀≫̸ess;批lantEqual;쀀⩾̸ilde;扵umpń௲௽ownHump;쀀≎̸qual;쀀≏̸eĀfsఊధtTriangleƀ;BEచఛడ拪ar;쀀⧏̸qual;括s̀;EGLSTవశ఼ౄోౘ扮qual;扰reater;扸ess;쀀≪̸lantEqual;쀀⩽̸ilde;扴estedĀGL౨౹reaterGreater;쀀⪢̸essLess;쀀⪡̸recedesƀ;ESಒಓಛ技qual;쀀⪯̸lantEqual;拠ĀeiಫಹverseElement;戌ghtTriangleƀ;BEೋೌ೒拫ar;쀀⧐̸qual;拭ĀquೝഌuareSuĀbp೨೹setĀ;E೰ೳ쀀⊏̸qual;拢ersetĀ;Eഃആ쀀⊐̸qual;拣ƀbcpഓതൎsetĀ;Eഛഞ쀀⊂⃒qual;抈ceedsȀ;ESTലള഻െ抁qual;쀀⪰̸lantEqual;拡ilde;쀀≿̸ersetĀ;E൘൛쀀⊃⃒qual;抉ildeȀ;EFT൮൯൵ൿ扁qual;扄ullEqual;扇ilde;扉erticalBar;戤cr;쀀𝒩ilde耻Ñ䃑;䎝܀Eacdfgmoprstuvලෂ෉෕ෛ෠෧෼ขภยา฿ไlig;䅒cute耻Ó䃓Āiy෎ීrc耻Ô䃔;䐞blac;䅐r;쀀𝔒rave耻Ò䃒ƀaei෮ෲ෶cr;䅌ga;䎩cron;䎟pf;쀀𝕆enCurlyĀDQฎบoubleQuote;怜uote;怘;橔Āclวฬr;쀀𝒪ash耻Ø䃘iŬื฼de耻Õ䃕es;樷ml耻Ö䃖erĀBP๋๠Āar๐๓r;怾acĀek๚๜;揞et;掴arenthesis;揜Ҁacfhilors๿ງຊຏຒດຝະ໼rtialD;戂y;䐟r;쀀𝔓i;䎦;䎠usMinus;䂱Āipຢອncareplanåڝf;愙Ȁ;eio຺ູ໠໤檻cedesȀ;EST່້໏໚扺qual;檯lantEqual;扼ilde;找me;怳Ādp໩໮uct;戏ortionĀ;aȥ໹l;戝Āci༁༆r;쀀𝒫;䎨ȀUfos༑༖༛༟OT耻\"䀢r;쀀𝔔pf;愚cr;쀀𝒬؀BEacefhiorsu༾གྷཇའཱིྦྷྪྭ႖ႩႴႾarr;椐G耻®䂮ƀcnrཎནབute;䅔g;柫rĀ;tཛྷཝ憠l;椖ƀaeyཧཬཱron;䅘dil;䅖;䐠Ā;vླྀཹ愜erseĀEUྂྙĀlq྇ྎement;戋uilibrium;懋pEquilibrium;楯r»ཹo;䎡ghtЀACDFTUVa࿁࿫࿳ဢဨၛႇϘĀnr࿆࿒gleBracket;柩rowƀ;BL࿜࿝࿡憒ar;懥eftArrow;懄eiling;按oǵ࿹\\0စbleBracket;柧nǔည\\0နeeVector;楝ectorĀ;Bဝသ懂ar;楕loor;挋Āerိ၃eƀ;AVဵံြ抢rrow;憦ector;楛iangleƀ;BEၐၑၕ抳ar;槐qual;抵pƀDTVၣၮၸownVector;楏eeVector;楜ectorĀ;Bႂႃ憾ar;楔ectorĀ;B႑႒懀ar;楓Āpuႛ႞f;愝ndImplies;楰ightarrow;懛ĀchႹႼr;愛;憱leDelayed;槴ڀHOacfhimoqstuფჱჷჽᄙᄞᅑᅖᅡᅧᆵᆻᆿĀCcჩხHcy;䐩y;䐨FTcy;䐬cute;䅚ʀ;aeiyᄈᄉᄎᄓᄗ檼ron;䅠dil;䅞rc;䅜;䐡r;쀀𝔖ortȀDLRUᄪᄴᄾᅉownArrow»ОeftArrow»࢚ightArrow»࿝pArrow;憑gma;䎣allCircle;战pf;쀀𝕊ɲᅭ\\0\\0ᅰt;戚areȀ;ISUᅻᅼᆉᆯ斡ntersection;抓uĀbpᆏᆞsetĀ;Eᆗᆘ抏qual;抑ersetĀ;Eᆨᆩ抐qual;抒nion;抔cr;쀀𝒮ar;拆ȀbcmpᇈᇛሉላĀ;sᇍᇎ拐etĀ;Eᇍᇕqual;抆ĀchᇠህeedsȀ;ESTᇭᇮᇴᇿ扻qual;檰lantEqual;扽ilde;承Tháྌ;我ƀ;esሒሓሣ拑rsetĀ;Eሜም抃qual;抇et»ሓրHRSacfhiorsሾቄ቉ቕ቞ቱቶኟዂወዑORN耻Þ䃞ADE;愢ĀHc቎ቒcy;䐋y;䐦Ābuቚቜ;䀉;䎤ƀaeyብቪቯron;䅤dil;䅢;䐢r;쀀𝔗Āeiቻ኉Dzኀ\\0ኇefore;戴a;䎘Ācn኎ኘkSpace;쀀  Space;怉ldeȀ;EFTካኬኲኼ戼qual;扃ullEqual;扅ilde;扈pf;쀀𝕋ipleDot;惛Āctዖዛr;쀀𝒯rok;䅦ૡዷጎጚጦ\\0ጬጱ\\0\\0\\0\\0\\0ጸጽ፷ᎅ\\0᏿ᐄᐊᐐĀcrዻጁute耻Ú䃚rĀ;oጇገ憟cir;楉rǣጓ\\0጖y;䐎ve;䅬Āiyጞጣrc耻Û䃛;䐣blac;䅰r;쀀𝔘rave耻Ù䃙acr;䅪Ādiፁ፩erĀBPፈ፝Āarፍፐr;䁟acĀekፗፙ;揟et;掵arenthesis;揝onĀ;P፰፱拃lus;抎Āgp፻፿on;䅲f;쀀𝕌ЀADETadps᎕ᎮᎸᏄϨᏒᏗᏳrrowƀ;BDᅐᎠᎤar;椒ownArrow;懅ownArrow;憕quilibrium;楮eeĀ;AᏋᏌ报rrow;憥ownáϳerĀLRᏞᏨeftArrow;憖ightArrow;憗iĀ;lᏹᏺ䏒on;䎥ing;䅮cr;쀀𝒰ilde;䅨ml耻Ü䃜ҀDbcdefosvᐧᐬᐰᐳᐾᒅᒊᒐᒖash;披ar;櫫y;䐒ashĀ;lᐻᐼ抩;櫦Āerᑃᑅ;拁ƀbtyᑌᑐᑺar;怖Ā;iᑏᑕcalȀBLSTᑡᑥᑪᑴar;戣ine;䁼eparator;杘ilde;所ThinSpace;怊r;쀀𝔙pf;쀀𝕍cr;쀀𝒱dash;抪ʀcefosᒧᒬᒱᒶᒼirc;䅴dge;拀r;쀀𝔚pf;쀀𝕎cr;쀀𝒲Ȁfiosᓋᓐᓒᓘr;쀀𝔛;䎞pf;쀀𝕏cr;쀀𝒳ҀAIUacfosuᓱᓵᓹᓽᔄᔏᔔᔚᔠcy;䐯cy;䐇cy;䐮cute耻Ý䃝Āiyᔉᔍrc;䅶;䐫r;쀀𝔜pf;쀀𝕐cr;쀀𝒴ml;䅸ЀHacdefosᔵᔹᔿᕋᕏᕝᕠᕤcy;䐖cute;䅹Āayᕄᕉron;䅽;䐗ot;䅻Dzᕔ\\0ᕛoWidtè૙a;䎖r;愨pf;愤cr;쀀𝒵௡ᖃᖊᖐ\\0ᖰᖶᖿ\\0\\0\\0\\0ᗆᗛᗫᙟ᙭\\0ᚕ᚛ᚲᚹ\\0ᚾcute耻á䃡reve;䄃̀;Ediuyᖜᖝᖡᖣᖨᖭ戾;쀀∾̳;房rc耻â䃢te肻´̆;䐰lig耻æ䃦Ā;r²ᖺ;쀀𝔞rave耻à䃠ĀepᗊᗖĀfpᗏᗔsym;愵èᗓha;䎱ĀapᗟcĀclᗤᗧr;䄁g;樿ɤᗰ\\0\\0ᘊʀ;adsvᗺᗻᗿᘁᘇ戧nd;橕;橜lope;橘;橚΀;elmrszᘘᘙᘛᘞᘿᙏᙙ戠;榤e»ᘙsdĀ;aᘥᘦ戡ѡᘰᘲᘴᘶᘸᘺᘼᘾ;榨;榩;榪;榫;榬;榭;榮;榯tĀ;vᙅᙆ戟bĀ;dᙌᙍ抾;榝Āptᙔᙗh;戢»¹arr;捼Āgpᙣᙧon;䄅f;쀀𝕒΀;Eaeiop዁ᙻᙽᚂᚄᚇᚊ;橰cir;橯;扊d;手s;䀧roxĀ;e዁ᚒñᚃing耻å䃥ƀctyᚡᚦᚨr;쀀𝒶;䀪mpĀ;e዁ᚯñʈilde耻ã䃣ml耻ä䃤Āciᛂᛈoninôɲnt;樑ࠀNabcdefiklnoprsu᛭ᛱᜰ᜼ᝃᝈ᝸᝽០៦ᠹᡐᜍ᤽᥈ᥰot;櫭Ācrᛶ᜞kȀcepsᜀᜅᜍᜓong;扌psilon;䏶rime;怵imĀ;e᜚᜛戽q;拍Ŷᜢᜦee;抽edĀ;gᜬᜭ挅e»ᜭrkĀ;t፜᜷brk;掶Āoyᜁᝁ;䐱quo;怞ʀcmprtᝓ᝛ᝡᝤᝨausĀ;eĊĉptyv;榰séᜌnoõēƀahwᝯ᝱ᝳ;䎲;愶een;扬r;쀀𝔟g΀costuvwឍឝឳេ៕៛៞ƀaiuបពរðݠrc;旯p»፱ƀdptឤឨឭot;樀lus;樁imes;樂ɱឹ\\0\\0ើcup;樆ar;昅riangleĀdu៍្own;施p;斳plus;樄eåᑄåᒭarow;植ƀako៭ᠦᠵĀcn៲ᠣkƀlst៺֫᠂ozenge;槫riangleȀ;dlr᠒᠓᠘᠝斴own;斾eft;旂ight;斸k;搣Ʊᠫ\\0ᠳƲᠯ\\0ᠱ;斒;斑4;斓ck;斈ĀeoᠾᡍĀ;qᡃᡆ쀀=⃥uiv;쀀≡⃥t;挐Ȁptwxᡙᡞᡧᡬf;쀀𝕓Ā;tᏋᡣom»Ꮜtie;拈؀DHUVbdhmptuvᢅᢖᢪᢻᣗᣛᣬ᣿ᤅᤊᤐᤡȀLRlrᢎᢐᢒᢔ;敗;敔;敖;敓ʀ;DUduᢡᢢᢤᢦᢨ敐;敦;敩;敤;敧ȀLRlrᢳᢵᢷᢹ;敝;敚;敜;教΀;HLRhlrᣊᣋᣍᣏᣑᣓᣕ救;敬;散;敠;敫;敢;敟ox;槉ȀLRlrᣤᣦᣨᣪ;敕;敒;攐;攌ʀ;DUduڽ᣷᣹᣻᣽;敥;敨;攬;攴inus;抟lus;択imes;抠ȀLRlrᤙᤛᤝ᤟;敛;敘;攘;攔΀;HLRhlrᤰᤱᤳᤵᤷ᤻᤹攂;敪;敡;敞;攼;攤;攜Āevģ᥂bar耻¦䂦Ȁceioᥑᥖᥚᥠr;쀀𝒷mi;恏mĀ;e᜚᜜lƀ;bhᥨᥩᥫ䁜;槅sub;柈Ŭᥴ᥾lĀ;e᥹᥺怢t»᥺pƀ;Eeįᦅᦇ;檮Ā;qۜۛೡᦧ\\0᧨ᨑᨕᨲ\\0ᨷᩐ\\0\\0᪴\\0\\0᫁\\0\\0ᬡᬮ᭍᭒\\0᯽\\0ᰌƀcpr᦭ᦲ᧝ute;䄇̀;abcdsᦿᧀᧄ᧊᧕᧙戩nd;橄rcup;橉Āau᧏᧒p;橋p;橇ot;橀;쀀∩︀Āeo᧢᧥t;恁îړȀaeiu᧰᧻ᨁᨅǰ᧵\\0᧸s;橍on;䄍dil耻ç䃧rc;䄉psĀ;sᨌᨍ橌m;橐ot;䄋ƀdmnᨛᨠᨦil肻¸ƭptyv;榲t脀¢;eᨭᨮ䂢räƲr;쀀𝔠ƀceiᨽᩀᩍy;䑇ckĀ;mᩇᩈ朓ark»ᩈ;䏇r΀;Ecefms᩟᩠ᩢᩫ᪤᪪᪮旋;槃ƀ;elᩩᩪᩭ䋆q;扗eɡᩴ\\0\\0᪈rrowĀlr᩼᪁eft;憺ight;憻ʀRSacd᪒᪔᪖᪚᪟»ཇ;擈st;抛irc;抚ash;抝nint;樐id;櫯cir;槂ubsĀ;u᪻᪼晣it»᪼ˬ᫇᫔᫺\\0ᬊonĀ;eᫍᫎ䀺Ā;qÇÆɭ᫙\\0\\0᫢aĀ;t᫞᫟䀬;䁀ƀ;fl᫨᫩᫫戁îᅠeĀmx᫱᫶ent»᫩eóɍǧ᫾\\0ᬇĀ;dኻᬂot;橭nôɆƀfryᬐᬔᬗ;쀀𝕔oäɔ脀©;sŕᬝr;愗Āaoᬥᬩrr;憵ss;朗Ācuᬲᬷr;쀀𝒸Ābpᬼ᭄Ā;eᭁᭂ櫏;櫑Ā;eᭉᭊ櫐;櫒dot;拯΀delprvw᭠᭬᭷ᮂᮬᯔ᯹arrĀlr᭨᭪;椸;椵ɰ᭲\\0\\0᭵r;拞c;拟arrĀ;p᭿ᮀ憶;椽̀;bcdosᮏᮐᮖᮡᮥᮨ截rcap;橈Āauᮛᮞp;橆p;橊ot;抍r;橅;쀀∪︀Ȁalrv᮵ᮿᯞᯣrrĀ;mᮼᮽ憷;椼yƀevwᯇᯔᯘqɰᯎ\\0\\0ᯒreã᭳uã᭵ee;拎edge;拏en耻¤䂤earrowĀlrᯮ᯳eft»ᮀight»ᮽeäᯝĀciᰁᰇoninôǷnt;戱lcty;挭ঀAHabcdefhijlorstuwz᰸᰻᰿ᱝᱩᱵᲊᲞᲬᲷ᳻᳿ᴍᵻᶑᶫᶻ᷆᷍rò΁ar;楥Ȁglrs᱈ᱍ᱒᱔ger;怠eth;愸òᄳhĀ;vᱚᱛ怐»ऊūᱡᱧarow;椏aã̕Āayᱮᱳron;䄏;䐴ƀ;ao̲ᱼᲄĀgrʿᲁr;懊tseq;橷ƀglmᲑᲔᲘ耻°䂰ta;䎴ptyv;榱ĀirᲣᲨsht;楿;쀀𝔡arĀlrᲳᲵ»ࣜ»သʀaegsv᳂͸᳖᳜᳠mƀ;oș᳊᳔ndĀ;ș᳑uit;晦amma;䏝in;拲ƀ;io᳧᳨᳸䃷de脀÷;o᳧ᳰntimes;拇nø᳷cy;䑒cɯᴆ\\0\\0ᴊrn;挞op;挍ʀlptuwᴘᴝᴢᵉᵕlar;䀤f;쀀𝕕ʀ;emps̋ᴭᴷᴽᵂqĀ;d͒ᴳot;扑inus;戸lus;戔quare;抡blebarwedgåúnƀadhᄮᵝᵧownarrowóᲃarpoonĀlrᵲᵶefôᲴighôᲶŢᵿᶅkaro÷གɯᶊ\\0\\0ᶎrn;挟op;挌ƀcotᶘᶣᶦĀryᶝᶡ;쀀𝒹;䑕l;槶rok;䄑Ādrᶰᶴot;拱iĀ;fᶺ᠖斿Āah᷀᷃ròЩaòྦangle;榦Āci᷒ᷕy;䑟grarr;柿ऀDacdefglmnopqrstuxḁḉḙḸոḼṉṡṾấắẽỡἪἷὄ὎὚ĀDoḆᴴoôᲉĀcsḎḔute耻é䃩ter;橮ȀaioyḢḧḱḶron;䄛rĀ;cḭḮ扖耻ê䃪lon;払;䑍ot;䄗ĀDrṁṅot;扒;쀀𝔢ƀ;rsṐṑṗ檚ave耻è䃨Ā;dṜṝ檖ot;檘Ȁ;ilsṪṫṲṴ檙nters;揧;愓Ā;dṹṺ檕ot;檗ƀapsẅẉẗcr;䄓tyƀ;svẒẓẕ戅et»ẓpĀ1;ẝẤijạả;怄;怅怃ĀgsẪẬ;䅋p;怂ĀgpẴẸon;䄙f;쀀𝕖ƀalsỄỎỒrĀ;sỊị拕l;槣us;橱iƀ;lvỚớở䎵on»ớ;䏵ȀcsuvỪỳἋἣĀioữḱrc»Ḯɩỹ\\0\\0ỻíՈantĀglἂἆtr»ṝess»Ṻƀaeiἒ἖Ἒls;䀽st;扟vĀ;DȵἠD;橸parsl;槥ĀDaἯἳot;打rr;楱ƀcdiἾὁỸr;愯oô͒ĀahὉὋ;䎷耻ð䃰Āmrὓὗl耻ë䃫o;悬ƀcipὡὤὧl;䀡sôծĀeoὬὴctatioîՙnentialåչৡᾒ\\0ᾞ\\0ᾡᾧ\\0\\0ῆῌ\\0ΐ\\0ῦῪ \\0 ⁚llingdotseñṄy;䑄male;晀ƀilrᾭᾳ῁lig;耀ffiɩᾹ\\0\\0᾽g;耀ffig;耀ffl;쀀𝔣lig;耀filig;쀀fjƀaltῙ῜ῡt;晭ig;耀flns;斱of;䆒ǰ΅\\0ῳf;쀀𝕗ĀakֿῷĀ;vῼ´拔;櫙artint;樍Āao‌⁕Ācs‑⁒ႉ‸⁅⁈\\0⁐β•‥‧‪‬\\0‮耻½䂽;慓耻¼䂼;慕;慙;慛Ƴ‴\\0‶;慔;慖ʴ‾⁁\\0\\0⁃耻¾䂾;慗;慜5;慘ƶ⁌\\0⁎;慚;慝8;慞l;恄wn;挢cr;쀀𝒻ࢀEabcdefgijlnorstv₂₉₟₥₰₴⃰⃵⃺⃿℃ℒℸ̗ℾ⅒↞Ā;lٍ₇;檌ƀcmpₐₕ₝ute;䇵maĀ;dₜ᳚䎳;檆reve;䄟Āiy₪₮rc;䄝;䐳ot;䄡Ȁ;lqsؾق₽⃉ƀ;qsؾٌ⃄lanô٥Ȁ;cdl٥⃒⃥⃕c;檩otĀ;o⃜⃝檀Ā;l⃢⃣檂;檄Ā;e⃪⃭쀀⋛︀s;檔r;쀀𝔤Ā;gٳ؛mel;愷cy;䑓Ȁ;Eajٚℌℎℐ;檒;檥;檤ȀEaesℛℝ℩ℴ;扩pĀ;p℣ℤ檊rox»ℤĀ;q℮ℯ檈Ā;q℮ℛim;拧pf;쀀𝕘Āci⅃ⅆr;愊mƀ;el٫ⅎ⅐;檎;檐茀>;cdlqr׮ⅠⅪⅮⅳⅹĀciⅥⅧ;檧r;橺ot;拗Par;榕uest;橼ʀadelsↄⅪ←ٖ↛ǰ↉\\0↎proø₞r;楸qĀlqؿ↖lesó₈ií٫Āen↣↭rtneqq;쀀≩︀Å↪ԀAabcefkosy⇄⇇⇱⇵⇺∘∝∯≨≽ròΠȀilmr⇐⇔⇗⇛rsðᒄf»․ilôکĀdr⇠⇤cy;䑊ƀ;cwࣴ⇫⇯ir;楈;憭ar;意irc;䄥ƀalr∁∎∓rtsĀ;u∉∊晥it»∊lip;怦con;抹r;쀀𝔥sĀew∣∩arow;椥arow;椦ʀamopr∺∾≃≞≣rr;懿tht;戻kĀlr≉≓eftarrow;憩ightarrow;憪f;쀀𝕙bar;怕ƀclt≯≴≸r;쀀𝒽asè⇴rok;䄧Ābp⊂⊇ull;恃hen»ᱛૡ⊣\\0⊪\\0⊸⋅⋎\\0⋕⋳\\0\\0⋸⌢⍧⍢⍿\\0⎆⎪⎴cute耻í䃭ƀ;iyݱ⊰⊵rc耻î䃮;䐸Ācx⊼⊿y;䐵cl耻¡䂡ĀfrΟ⋉;쀀𝔦rave耻ì䃬Ȁ;inoܾ⋝⋩⋮Āin⋢⋦nt;樌t;戭fin;槜ta;愩lig;䄳ƀaop⋾⌚⌝ƀcgt⌅⌈⌗r;䄫ƀelpܟ⌏⌓inåގarôܠh;䄱f;抷ed;䆵ʀ;cfotӴ⌬⌱⌽⍁are;愅inĀ;t⌸⌹戞ie;槝doô⌙ʀ;celpݗ⍌⍐⍛⍡al;抺Āgr⍕⍙eróᕣã⍍arhk;樗rod;樼Ȁcgpt⍯⍲⍶⍻y;䑑on;䄯f;쀀𝕚a;䎹uest耻¿䂿Āci⎊⎏r;쀀𝒾nʀ;EdsvӴ⎛⎝⎡ӳ;拹ot;拵Ā;v⎦⎧拴;拳Ā;iݷ⎮lde;䄩ǫ⎸\\0⎼cy;䑖l耻ï䃯̀cfmosu⏌⏗⏜⏡⏧⏵Āiy⏑⏕rc;䄵;䐹r;쀀𝔧ath;䈷pf;쀀𝕛ǣ⏬\\0⏱r;쀀𝒿rcy;䑘kcy;䑔Ѐacfghjos␋␖␢␧␭␱␵␻ppaĀ;v␓␔䎺;䏰Āey␛␠dil;䄷;䐺r;쀀𝔨reen;䄸cy;䑅cy;䑜pf;쀀𝕜cr;쀀𝓀஀ABEHabcdefghjlmnoprstuv⑰⒁⒆⒍⒑┎┽╚▀♎♞♥♹♽⚚⚲⛘❝❨➋⟀⠁⠒ƀart⑷⑺⑼rò৆òΕail;椛arr;椎Ā;gঔ⒋;檋ar;楢ॣ⒥\\0⒪\\0⒱\\0\\0\\0\\0\\0⒵Ⓔ\\0ⓆⓈⓍ\\0⓹ute;䄺mptyv;榴raîࡌbda;䎻gƀ;dlࢎⓁⓃ;榑åࢎ;檅uo耻«䂫rЀ;bfhlpst࢙ⓞⓦⓩ⓫⓮⓱⓵Ā;f࢝ⓣs;椟s;椝ë≒p;憫l;椹im;楳l;憢ƀ;ae⓿─┄檫il;椙Ā;s┉┊檭;쀀⪭︀ƀabr┕┙┝rr;椌rk;杲Āak┢┬cĀek┨┪;䁻;䁛Āes┱┳;榋lĀdu┹┻;榏;榍Ȁaeuy╆╋╖╘ron;䄾Ādi═╔il;䄼ìࢰâ┩;䐻Ȁcqrs╣╦╭╽a;椶uoĀ;rนᝆĀdu╲╷har;楧shar;楋h;憲ʀ;fgqs▋▌উ◳◿扤tʀahlrt▘▤▷◂◨rrowĀ;t࢙□aé⓶arpoonĀdu▯▴own»њp»०eftarrows;懇ightƀahs◍◖◞rrowĀ;sࣴࢧarpoonó྘quigarro÷⇰hreetimes;拋ƀ;qs▋ও◺lanôবʀ;cdgsব☊☍☝☨c;檨otĀ;o☔☕橿Ā;r☚☛檁;檃Ā;e☢☥쀀⋚︀s;檓ʀadegs☳☹☽♉♋pproøⓆot;拖qĀgq♃♅ôউgtò⒌ôছiíলƀilr♕࣡♚sht;楼;쀀𝔩Ā;Eজ♣;檑š♩♶rĀdu▲♮Ā;l॥♳;楪lk;斄cy;䑙ʀ;achtੈ⚈⚋⚑⚖rò◁orneòᴈard;楫ri;旺Āio⚟⚤dot;䅀ustĀ;a⚬⚭掰che»⚭ȀEaes⚻⚽⛉⛔;扨pĀ;p⛃⛄檉rox»⛄Ā;q⛎⛏檇Ā;q⛎⚻im;拦Ѐabnoptwz⛩⛴⛷✚✯❁❇❐Ānr⛮⛱g;柬r;懽rëࣁgƀlmr⛿✍✔eftĀar০✇ightá৲apsto;柼ightá৽parrowĀlr✥✩efô⓭ight;憬ƀafl✶✹✽r;榅;쀀𝕝us;樭imes;樴š❋❏st;戗áፎƀ;ef❗❘᠀旊nge»❘arĀ;l❤❥䀨t;榓ʀachmt❳❶❼➅➇ròࢨorneòᶌarĀ;d྘➃;業;怎ri;抿̀achiqt➘➝ੀ➢➮➻quo;怹r;쀀𝓁mƀ;egল➪➬;檍;檏Ābu┪➳oĀ;rฟ➹;怚rok;䅂萀<;cdhilqrࠫ⟒☹⟜⟠⟥⟪⟰Āci⟗⟙;檦r;橹reå◲mes;拉arr;楶uest;橻ĀPi⟵⟹ar;榖ƀ;ef⠀भ᠛旃rĀdu⠇⠍shar;楊har;楦Āen⠗⠡rtneqq;쀀≨︀Å⠞܀Dacdefhilnopsu⡀⡅⢂⢎⢓⢠⢥⢨⣚⣢⣤ઃ⣳⤂Dot;戺Ȁclpr⡎⡒⡣⡽r耻¯䂯Āet⡗⡙;時Ā;e⡞⡟朠se»⡟Ā;sျ⡨toȀ;dluျ⡳⡷⡻owîҌefôएðᏑker;斮Āoy⢇⢌mma;権;䐼ash;怔asuredangle»ᘦr;쀀𝔪o;愧ƀcdn⢯⢴⣉ro耻µ䂵Ȁ;acdᑤ⢽⣀⣄sôᚧir;櫰ot肻·Ƶusƀ;bd⣒ᤃ⣓戒Ā;uᴼ⣘;横ţ⣞⣡p;櫛ò−ðઁĀdp⣩⣮els;抧f;쀀𝕞Āct⣸⣽r;쀀𝓂pos»ᖝƀ;lm⤉⤊⤍䎼timap;抸ఀGLRVabcdefghijlmoprstuvw⥂⥓⥾⦉⦘⧚⧩⨕⨚⩘⩝⪃⪕⪤⪨⬄⬇⭄⭿⮮ⰴⱧⱼ⳩Āgt⥇⥋;쀀⋙̸Ā;v⥐௏쀀≫⃒ƀelt⥚⥲⥶ftĀar⥡⥧rrow;懍ightarrow;懎;쀀⋘̸Ā;v⥻ే쀀≪⃒ightarrow;懏ĀDd⦎⦓ash;抯ash;抮ʀbcnpt⦣⦧⦬⦱⧌la»˞ute;䅄g;쀀∠⃒ʀ;Eiop඄⦼⧀⧅⧈;쀀⩰̸d;쀀≋̸s;䅉roø඄urĀ;a⧓⧔普lĀ;s⧓ସdz⧟\\0⧣p肻 ଷmpĀ;e௹ఀʀaeouy⧴⧾⨃⨐⨓ǰ⧹\\0⧻;橃on;䅈dil;䅆ngĀ;dൾ⨊ot;쀀⩭̸p;橂;䐽ash;怓΀;Aadqsxஒ⨩⨭⨻⩁⩅⩐rr;懗rĀhr⨳⨶k;椤Ā;oᏲᏰot;쀀≐̸uiöୣĀei⩊⩎ar;椨í஘istĀ;s஠டr;쀀𝔫ȀEest௅⩦⩹⩼ƀ;qs஼⩭௡ƀ;qs஼௅⩴lanô௢ií௪Ā;rஶ⪁»ஷƀAap⪊⪍⪑rò⥱rr;憮ar;櫲ƀ;svྍ⪜ྌĀ;d⪡⪢拼;拺cy;䑚΀AEadest⪷⪺⪾⫂⫅⫶⫹rò⥦;쀀≦̸rr;憚r;急Ȁ;fqs఻⫎⫣⫯tĀar⫔⫙rro÷⫁ightarro÷⪐ƀ;qs఻⪺⫪lanôౕĀ;sౕ⫴»శiíౝĀ;rవ⫾iĀ;eచథiäඐĀpt⬌⬑f;쀀𝕟膀¬;in⬙⬚⬶䂬nȀ;Edvஉ⬤⬨⬮;쀀⋹̸ot;쀀⋵̸ǡஉ⬳⬵;拷;拶iĀ;vಸ⬼ǡಸ⭁⭃;拾;拽ƀaor⭋⭣⭩rȀ;ast୻⭕⭚⭟lleì୻l;쀀⫽⃥;쀀∂̸lint;樔ƀ;ceಒ⭰⭳uåಥĀ;cಘ⭸Ā;eಒ⭽ñಘȀAait⮈⮋⮝⮧rò⦈rrƀ;cw⮔⮕⮙憛;쀀⤳̸;쀀↝̸ghtarrow»⮕riĀ;eೋೖ΀chimpqu⮽⯍⯙⬄୸⯤⯯Ȁ;cerല⯆ഷ⯉uå൅;쀀𝓃ortɭ⬅\\0\\0⯖ará⭖mĀ;e൮⯟Ā;q൴൳suĀbp⯫⯭å೸åഋƀbcp⯶ⰑⰙȀ;Ees⯿ⰀഢⰄ抄;쀀⫅̸etĀ;eഛⰋqĀ;qണⰀcĀ;eലⰗñസȀ;EesⰢⰣൟⰧ抅;쀀⫆̸etĀ;e൘ⰮqĀ;qൠⰣȀgilrⰽⰿⱅⱇìௗlde耻ñ䃱çృiangleĀlrⱒⱜeftĀ;eచⱚñదightĀ;eೋⱥñ೗Ā;mⱬⱭ䎽ƀ;esⱴⱵⱹ䀣ro;愖p;怇ҀDHadgilrsⲏⲔⲙⲞⲣⲰⲶⳓⳣash;抭arr;椄p;쀀≍⃒ash;抬ĀetⲨⲬ;쀀≥⃒;쀀>⃒nfin;槞ƀAetⲽⳁⳅrr;椂;쀀≤⃒Ā;rⳊⳍ쀀<⃒ie;쀀⊴⃒ĀAtⳘⳜrr;椃rie;쀀⊵⃒im;쀀∼⃒ƀAan⳰⳴ⴂrr;懖rĀhr⳺⳽k;椣Ā;oᏧᏥear;椧ቓ᪕\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0ⴭ\\0ⴸⵈⵠⵥ⵲ⶄᬇ\\0\\0ⶍⶫ\\0ⷈⷎ\\0ⷜ⸙⸫⸾⹃Ācsⴱ᪗ute耻ó䃳ĀiyⴼⵅrĀ;c᪞ⵂ耻ô䃴;䐾ʀabios᪠ⵒⵗLjⵚlac;䅑v;樸old;榼lig;䅓Ācr⵩⵭ir;榿;쀀𝔬ͯ⵹\\0\\0⵼\\0ⶂn;䋛ave耻ò䃲;槁Ābmⶈ෴ar;榵Ȁacitⶕ⶘ⶥⶨrò᪀Āir⶝ⶠr;榾oss;榻nå๒;槀ƀaeiⶱⶵⶹcr;䅍ga;䏉ƀcdnⷀⷅǍron;䎿;榶pf;쀀𝕠ƀaelⷔ⷗ǒr;榷rp;榹΀;adiosvⷪⷫⷮ⸈⸍⸐⸖戨rò᪆Ȁ;efmⷷⷸ⸂⸅橝rĀ;oⷾⷿ愴f»ⷿ耻ª䂪耻º䂺gof;抶r;橖lope;橗;橛ƀclo⸟⸡⸧ò⸁ash耻ø䃸l;折iŬⸯ⸴de耻õ䃵esĀ;aǛ⸺s;樶ml耻ö䃶bar;挽ૡ⹞\\0⹽\\0⺀⺝\\0⺢⺹\\0\\0⻋ຜ\\0⼓\\0\\0⼫⾼\\0⿈rȀ;astЃ⹧⹲຅脀¶;l⹭⹮䂶leìЃɩ⹸\\0\\0⹻m;櫳;櫽y;䐿rʀcimpt⺋⺏⺓ᡥ⺗nt;䀥od;䀮il;怰enk;怱r;쀀𝔭ƀimo⺨⺰⺴Ā;v⺭⺮䏆;䏕maô੶ne;明ƀ;tv⺿⻀⻈䏀chfork»´;䏖Āau⻏⻟nĀck⻕⻝kĀ;h⇴⻛;愎ö⇴sҀ;abcdemst⻳⻴ᤈ⻹⻽⼄⼆⼊⼎䀫cir;樣ir;樢Āouᵀ⼂;樥;橲n肻±ຝim;樦wo;樧ƀipu⼙⼠⼥ntint;樕f;쀀𝕡nd耻£䂣Ԁ;Eaceinosu່⼿⽁⽄⽇⾁⾉⾒⽾⾶;檳p;檷uå໙Ā;c໎⽌̀;acens່⽙⽟⽦⽨⽾pproø⽃urlyeñ໙ñ໎ƀaes⽯⽶⽺pprox;檹qq;檵im;拨iíໟmeĀ;s⾈ຮ怲ƀEas⽸⾐⽺ð⽵ƀdfp໬⾙⾯ƀals⾠⾥⾪lar;挮ine;挒urf;挓Ā;t໻⾴ï໻rel;抰Āci⿀⿅r;쀀𝓅;䏈ncsp;怈̀fiopsu⿚⋢⿟⿥⿫⿱r;쀀𝔮pf;쀀𝕢rime;恗cr;쀀𝓆ƀaeo⿸〉〓tĀei⿾々rnionóڰnt;樖stĀ;e【】䀿ñἙô༔઀ABHabcdefhilmnoprstux぀けさすムㄎㄫㅇㅢㅲㆎ㈆㈕㈤㈩㉘㉮㉲㊐㊰㊷ƀartぇおがròႳòϝail;検aròᱥar;楤΀cdenqrtとふへみわゔヌĀeuねぱ;쀀∽̱te;䅕iãᅮmptyv;榳gȀ;del࿑らるろ;榒;榥å࿑uo耻»䂻rր;abcfhlpstw࿜ガクシスゼゾダッデナp;極Ā;f࿠ゴs;椠;椳s;椞ë≝ð✮l;楅im;楴l;憣;憝Āaiパフil;椚oĀ;nホボ戶aló༞ƀabrョリヮrò៥rk;杳ĀakンヽcĀekヹ・;䁽;䁝Āes㄂㄄;榌lĀduㄊㄌ;榎;榐Ȁaeuyㄗㄜㄧㄩron;䅙Ādiㄡㄥil;䅗ì࿲âヺ;䑀Ȁclqsㄴㄷㄽㅄa;椷dhar;楩uoĀ;rȎȍh;憳ƀacgㅎㅟངlȀ;ipsླྀㅘㅛႜnåႻarôྩt;断ƀilrㅩဣㅮsht;楽;쀀𝔯ĀaoㅷㆆrĀduㅽㅿ»ѻĀ;l႑ㆄ;楬Ā;vㆋㆌ䏁;䏱ƀgns㆕ㇹㇼht̀ahlrstㆤㆰ㇂㇘㇤㇮rrowĀ;t࿜ㆭaéトarpoonĀduㆻㆿowîㅾp»႒eftĀah㇊㇐rrowó࿪arpoonóՑightarrows;應quigarro÷ニhreetimes;拌g;䋚ingdotseñἲƀahm㈍㈐㈓rò࿪aòՑ;怏oustĀ;a㈞㈟掱che»㈟mid;櫮Ȁabpt㈲㈽㉀㉒Ānr㈷㈺g;柭r;懾rëဃƀafl㉇㉊㉎r;榆;쀀𝕣us;樮imes;樵Āap㉝㉧rĀ;g㉣㉤䀩t;榔olint;樒arò㇣Ȁachq㉻㊀Ⴜ㊅quo;怺r;쀀𝓇Ābu・㊊oĀ;rȔȓƀhir㊗㊛㊠reåㇸmes;拊iȀ;efl㊪ၙᠡ㊫方tri;槎luhar;楨;愞ൡ㋕㋛㋟㌬㌸㍱\\0㍺㎤\\0\\0㏬㏰\\0㐨㑈㑚㒭㒱㓊㓱\\0㘖\\0\\0㘳cute;䅛quï➺Ԁ;Eaceinpsyᇭ㋳㋵㋿㌂㌋㌏㌟㌦㌩;檴ǰ㋺\\0㋼;檸on;䅡uåᇾĀ;dᇳ㌇il;䅟rc;䅝ƀEas㌖㌘㌛;檶p;檺im;择olint;樓iíሄ;䑁otƀ;be㌴ᵇ㌵担;橦΀Aacmstx㍆㍊㍗㍛㍞㍣㍭rr;懘rĀhr㍐㍒ë∨Ā;oਸ਼਴t耻§䂧i;䀻war;椩mĀin㍩ðnuóñt;朶rĀ;o㍶⁕쀀𝔰Ȁacoy㎂㎆㎑㎠rp;景Āhy㎋㎏cy;䑉;䑈rtɭ㎙\\0\\0㎜iäᑤaraì⹯耻­䂭Āgm㎨㎴maƀ;fv㎱㎲㎲䏃;䏂Ѐ;deglnprካ㏅㏉㏎㏖㏞㏡㏦ot;橪Ā;q኱ኰĀ;E㏓㏔檞;檠Ā;E㏛㏜檝;檟e;扆lus;樤arr;楲aròᄽȀaeit㏸㐈㐏㐗Āls㏽㐄lsetmé㍪hp;樳parsl;槤Ādlᑣ㐔e;挣Ā;e㐜㐝檪Ā;s㐢㐣檬;쀀⪬︀ƀflp㐮㐳㑂tcy;䑌Ā;b㐸㐹䀯Ā;a㐾㐿槄r;挿f;쀀𝕤aĀdr㑍ЂesĀ;u㑔㑕晠it»㑕ƀcsu㑠㑹㒟Āau㑥㑯pĀ;sᆈ㑫;쀀⊓︀pĀ;sᆴ㑵;쀀⊔︀uĀbp㑿㒏ƀ;esᆗᆜ㒆etĀ;eᆗ㒍ñᆝƀ;esᆨᆭ㒖etĀ;eᆨ㒝ñᆮƀ;afᅻ㒦ְrť㒫ֱ»ᅼaròᅈȀcemt㒹㒾㓂㓅r;쀀𝓈tmîñiì㐕aræᆾĀar㓎㓕rĀ;f㓔ឿ昆Āan㓚㓭ightĀep㓣㓪psiloîỠhé⺯s»⡒ʀbcmnp㓻㕞ሉ㖋㖎Ҁ;Edemnprs㔎㔏㔑㔕㔞㔣㔬㔱㔶抂;櫅ot;檽Ā;dᇚ㔚ot;櫃ult;櫁ĀEe㔨㔪;櫋;把lus;檿arr;楹ƀeiu㔽㕒㕕tƀ;en㔎㕅㕋qĀ;qᇚ㔏eqĀ;q㔫㔨m;櫇Ābp㕚㕜;櫕;櫓c̀;acensᇭ㕬㕲㕹㕻㌦pproø㋺urlyeñᇾñᇳƀaes㖂㖈㌛pproø㌚qñ㌗g;晪ڀ123;Edehlmnps㖩㖬㖯ሜ㖲㖴㗀㗉㗕㗚㗟㗨㗭耻¹䂹耻²䂲耻³䂳;櫆Āos㖹㖼t;檾ub;櫘Ā;dሢ㗅ot;櫄sĀou㗏㗒l;柉b;櫗arr;楻ult;櫂ĀEe㗤㗦;櫌;抋lus;櫀ƀeiu㗴㘉㘌tƀ;enሜ㗼㘂qĀ;qሢ㖲eqĀ;q㗧㗤m;櫈Ābp㘑㘓;櫔;櫖ƀAan㘜㘠㘭rr;懙rĀhr㘦㘨ë∮Ā;oਫ਩war;椪lig耻ß䃟௡㙑㙝㙠ዎ㙳㙹\\0㙾㛂\\0\\0\\0\\0\\0㛛㜃\\0㜉㝬\\0\\0\\0㞇ɲ㙖\\0\\0㙛get;挖;䏄rë๟ƀaey㙦㙫㙰ron;䅥dil;䅣;䑂lrec;挕r;쀀𝔱Ȁeiko㚆㚝㚵㚼Dz㚋\\0㚑eĀ4fኄኁaƀ;sv㚘㚙㚛䎸ym;䏑Ācn㚢㚲kĀas㚨㚮pproø዁im»ኬsðኞĀas㚺㚮ð዁rn耻þ䃾Ǭ̟㛆⋧es膀×;bd㛏㛐㛘䃗Ā;aᤏ㛕r;樱;樰ƀeps㛡㛣㜀á⩍Ȁ;bcf҆㛬㛰㛴ot;挶ir;櫱Ā;o㛹㛼쀀𝕥rk;櫚á㍢rime;怴ƀaip㜏㜒㝤dåቈ΀adempst㜡㝍㝀㝑㝗㝜㝟ngleʀ;dlqr㜰㜱㜶㝀㝂斵own»ᶻeftĀ;e⠀㜾ñम;扜ightĀ;e㊪㝋ñၚot;旬inus;樺lus;樹b;槍ime;樻ezium;揢ƀcht㝲㝽㞁Āry㝷㝻;쀀𝓉;䑆cy;䑛rok;䅧Āio㞋㞎xô᝷headĀlr㞗㞠eftarro÷ࡏightarrow»ཝऀAHabcdfghlmoprstuw㟐㟓㟗㟤㟰㟼㠎㠜㠣㠴㡑㡝㡫㢩㣌㣒㣪㣶ròϭar;楣Ācr㟜㟢ute耻ú䃺òᅐrǣ㟪\\0㟭y;䑞ve;䅭Āiy㟵㟺rc耻û䃻;䑃ƀabh㠃㠆㠋ròᎭlac;䅱aòᏃĀir㠓㠘sht;楾;쀀𝔲rave耻ù䃹š㠧㠱rĀlr㠬㠮»ॗ»ႃlk;斀Āct㠹㡍ɯ㠿\\0\\0㡊rnĀ;e㡅㡆挜r»㡆op;挏ri;旸Āal㡖㡚cr;䅫肻¨͉Āgp㡢㡦on;䅳f;쀀𝕦̀adhlsuᅋ㡸㡽፲㢑㢠ownáᎳarpoonĀlr㢈㢌efô㠭ighô㠯iƀ;hl㢙㢚㢜䏅»ᏺon»㢚parrows;懈ƀcit㢰㣄㣈ɯ㢶\\0\\0㣁rnĀ;e㢼㢽挝r»㢽op;挎ng;䅯ri;旹cr;쀀𝓊ƀdir㣙㣝㣢ot;拰lde;䅩iĀ;f㜰㣨»᠓Āam㣯㣲rò㢨l耻ü䃼angle;榧ހABDacdeflnoprsz㤜㤟㤩㤭㦵㦸㦽㧟㧤㧨㧳㧹㧽㨁㨠ròϷarĀ;v㤦㤧櫨;櫩asèϡĀnr㤲㤷grt;榜΀eknprst㓣㥆㥋㥒㥝㥤㦖appá␕othinçẖƀhir㓫⻈㥙opô⾵Ā;hᎷ㥢ïㆍĀiu㥩㥭gmá㎳Ābp㥲㦄setneqĀ;q㥽㦀쀀⊊︀;쀀⫋︀setneqĀ;q㦏㦒쀀⊋︀;쀀⫌︀Āhr㦛㦟etá㚜iangleĀlr㦪㦯eft»थight»ၑy;䐲ash»ံƀelr㧄㧒㧗ƀ;beⷪ㧋㧏ar;抻q;扚lip;拮Ābt㧜ᑨaòᑩr;쀀𝔳tré㦮suĀbp㧯㧱»ജ»൙pf;쀀𝕧roð໻tré㦴Ācu㨆㨋r;쀀𝓋Ābp㨐㨘nĀEe㦀㨖»㥾nĀEe㦒㨞»㦐igzag;榚΀cefoprs㨶㨻㩖㩛㩔㩡㩪irc;䅵Ādi㩀㩑Ābg㩅㩉ar;機eĀ;qᗺ㩏;扙erp;愘r;쀀𝔴pf;쀀𝕨Ā;eᑹ㩦atèᑹcr;쀀𝓌ૣណ㪇\\0㪋\\0㪐㪛\\0\\0㪝㪨㪫㪯\\0\\0㫃㫎\\0㫘ៜ៟tré៑r;쀀𝔵ĀAa㪔㪗ròσrò৶;䎾ĀAa㪡㪤ròθrò৫að✓is;拻ƀdptឤ㪵㪾Āfl㪺ឩ;쀀𝕩imåឲĀAa㫇㫊ròώròਁĀcq㫒ីr;쀀𝓍Āpt៖㫜ré។Ѐacefiosu㫰㫽㬈㬌㬑㬕㬛㬡cĀuy㫶㫻te耻ý䃽;䑏Āiy㬂㬆rc;䅷;䑋n耻¥䂥r;쀀𝔶cy;䑗pf;쀀𝕪cr;쀀𝓎Ācm㬦㬩y;䑎l耻ÿ䃿Ԁacdefhiosw㭂㭈㭔㭘㭤㭩㭭㭴㭺㮀cute;䅺Āay㭍㭒ron;䅾;䐷ot;䅼Āet㭝㭡træᕟa;䎶r;쀀𝔷cy;䐶grarr;懝pf;쀀𝕫cr;쀀𝓏Ājn㮅㮇;怍j;怌'.split(\"\").map((c) => c.charCodeAt(0))\n);\n\n// node_modules/.pnpm/entities@4.5.0/node_modules/entities/lib/esm/generated/decode-data-xml.js\nvar decode_data_xml_default = new Uint16Array(\n // prettier-ignore\n \"Ȁaglq\t\u0015\u0018\\x1Bɭ\u000f\\0\\0\u0012p;䀦os;䀧t;䀾t;䀼uot;䀢\".split(\"\").map((c) => c.charCodeAt(0))\n);\n\n// node_modules/.pnpm/entities@4.5.0/node_modules/entities/lib/esm/decode_codepoint.js\nvar _a;\nvar decodeMap = /* @__PURE__ */ new Map([\n [0, 65533],\n // C1 Unicode control character reference replacements\n [128, 8364],\n [130, 8218],\n [131, 402],\n [132, 8222],\n [133, 8230],\n [134, 8224],\n [135, 8225],\n [136, 710],\n [137, 8240],\n [138, 352],\n [139, 8249],\n [140, 338],\n [142, 381],\n [145, 8216],\n [146, 8217],\n [147, 8220],\n [148, 8221],\n [149, 8226],\n [150, 8211],\n [151, 8212],\n [152, 732],\n [153, 8482],\n [154, 353],\n [155, 8250],\n [156, 339],\n [158, 382],\n [159, 376]\n]);\nvar fromCodePoint = (\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition, node/no-unsupported-features/es-builtins\n (_a = String.fromCodePoint) !== null && _a !== void 0 ? _a : function(codePoint) {\n let output = \"\";\n if (codePoint > 65535) {\n codePoint -= 65536;\n output += String.fromCharCode(codePoint >>> 10 & 1023 | 55296);\n codePoint = 56320 | codePoint & 1023;\n }\n output += String.fromCharCode(codePoint);\n return output;\n }\n);\nfunction replaceCodePoint(codePoint) {\n var _a2;\n if (codePoint >= 55296 && codePoint <= 57343 || codePoint > 1114111) {\n return 65533;\n }\n return (_a2 = decodeMap.get(codePoint)) !== null && _a2 !== void 0 ? _a2 : codePoint;\n}\n\n// node_modules/.pnpm/entities@4.5.0/node_modules/entities/lib/esm/decode.js\nvar CharCodes;\n(function(CharCodes2) {\n CharCodes2[CharCodes2[\"NUM\"] = 35] = \"NUM\";\n CharCodes2[CharCodes2[\"SEMI\"] = 59] = \"SEMI\";\n CharCodes2[CharCodes2[\"EQUALS\"] = 61] = \"EQUALS\";\n CharCodes2[CharCodes2[\"ZERO\"] = 48] = \"ZERO\";\n CharCodes2[CharCodes2[\"NINE\"] = 57] = \"NINE\";\n CharCodes2[CharCodes2[\"LOWER_A\"] = 97] = \"LOWER_A\";\n CharCodes2[CharCodes2[\"LOWER_F\"] = 102] = \"LOWER_F\";\n CharCodes2[CharCodes2[\"LOWER_X\"] = 120] = \"LOWER_X\";\n CharCodes2[CharCodes2[\"LOWER_Z\"] = 122] = \"LOWER_Z\";\n CharCodes2[CharCodes2[\"UPPER_A\"] = 65] = \"UPPER_A\";\n CharCodes2[CharCodes2[\"UPPER_F\"] = 70] = \"UPPER_F\";\n CharCodes2[CharCodes2[\"UPPER_Z\"] = 90] = \"UPPER_Z\";\n})(CharCodes || (CharCodes = {}));\nvar TO_LOWER_BIT = 32;\nvar BinTrieFlags;\n(function(BinTrieFlags2) {\n BinTrieFlags2[BinTrieFlags2[\"VALUE_LENGTH\"] = 49152] = \"VALUE_LENGTH\";\n BinTrieFlags2[BinTrieFlags2[\"BRANCH_LENGTH\"] = 16256] = \"BRANCH_LENGTH\";\n BinTrieFlags2[BinTrieFlags2[\"JUMP_TABLE\"] = 127] = \"JUMP_TABLE\";\n})(BinTrieFlags || (BinTrieFlags = {}));\nfunction isNumber(code2) {\n return code2 >= CharCodes.ZERO && code2 <= CharCodes.NINE;\n}\nfunction isHexadecimalCharacter(code2) {\n return code2 >= CharCodes.UPPER_A && code2 <= CharCodes.UPPER_F || code2 >= CharCodes.LOWER_A && code2 <= CharCodes.LOWER_F;\n}\nfunction isAsciiAlphaNumeric(code2) {\n return code2 >= CharCodes.UPPER_A && code2 <= CharCodes.UPPER_Z || code2 >= CharCodes.LOWER_A && code2 <= CharCodes.LOWER_Z || isNumber(code2);\n}\nfunction isEntityInAttributeInvalidEnd(code2) {\n return code2 === CharCodes.EQUALS || isAsciiAlphaNumeric(code2);\n}\nvar EntityDecoderState;\n(function(EntityDecoderState2) {\n EntityDecoderState2[EntityDecoderState2[\"EntityStart\"] = 0] = \"EntityStart\";\n EntityDecoderState2[EntityDecoderState2[\"NumericStart\"] = 1] = \"NumericStart\";\n EntityDecoderState2[EntityDecoderState2[\"NumericDecimal\"] = 2] = \"NumericDecimal\";\n EntityDecoderState2[EntityDecoderState2[\"NumericHex\"] = 3] = \"NumericHex\";\n EntityDecoderState2[EntityDecoderState2[\"NamedEntity\"] = 4] = \"NamedEntity\";\n})(EntityDecoderState || (EntityDecoderState = {}));\nvar DecodingMode;\n(function(DecodingMode2) {\n DecodingMode2[DecodingMode2[\"Legacy\"] = 0] = \"Legacy\";\n DecodingMode2[DecodingMode2[\"Strict\"] = 1] = \"Strict\";\n DecodingMode2[DecodingMode2[\"Attribute\"] = 2] = \"Attribute\";\n})(DecodingMode || (DecodingMode = {}));\nvar EntityDecoder = class {\n constructor(decodeTree, emitCodePoint, errors2) {\n this.decodeTree = decodeTree;\n this.emitCodePoint = emitCodePoint;\n this.errors = errors2;\n this.state = EntityDecoderState.EntityStart;\n this.consumed = 1;\n this.result = 0;\n this.treeIndex = 0;\n this.excess = 1;\n this.decodeMode = DecodingMode.Strict;\n }\n /** Resets the instance to make it reusable. */\n startEntity(decodeMode) {\n this.decodeMode = decodeMode;\n this.state = EntityDecoderState.EntityStart;\n this.result = 0;\n this.treeIndex = 0;\n this.excess = 1;\n this.consumed = 1;\n }\n /**\n * Write an entity to the decoder. This can be called multiple times with partial entities.\n * If the entity is incomplete, the decoder will return -1.\n *\n * Mirrors the implementation of `getDecoder`, but with the ability to stop decoding if the\n * entity is incomplete, and resume when the next string is written.\n *\n * @param string The string containing the entity (or a continuation of the entity).\n * @param offset The offset at which the entity begins. Should be 0 if this is not the first call.\n * @returns The number of characters that were consumed, or -1 if the entity is incomplete.\n */\n write(str, offset) {\n switch (this.state) {\n case EntityDecoderState.EntityStart: {\n if (str.charCodeAt(offset) === CharCodes.NUM) {\n this.state = EntityDecoderState.NumericStart;\n this.consumed += 1;\n return this.stateNumericStart(str, offset + 1);\n }\n this.state = EntityDecoderState.NamedEntity;\n return this.stateNamedEntity(str, offset);\n }\n case EntityDecoderState.NumericStart: {\n return this.stateNumericStart(str, offset);\n }\n case EntityDecoderState.NumericDecimal: {\n return this.stateNumericDecimal(str, offset);\n }\n case EntityDecoderState.NumericHex: {\n return this.stateNumericHex(str, offset);\n }\n case EntityDecoderState.NamedEntity: {\n return this.stateNamedEntity(str, offset);\n }\n }\n }\n /**\n * Switches between the numeric decimal and hexadecimal states.\n *\n * Equivalent to the `Numeric character reference state` in the HTML spec.\n *\n * @param str The string containing the entity (or a continuation of the entity).\n * @param offset The current offset.\n * @returns The number of characters that were consumed, or -1 if the entity is incomplete.\n */\n stateNumericStart(str, offset) {\n if (offset >= str.length) {\n return -1;\n }\n if ((str.charCodeAt(offset) | TO_LOWER_BIT) === CharCodes.LOWER_X) {\n this.state = EntityDecoderState.NumericHex;\n this.consumed += 1;\n return this.stateNumericHex(str, offset + 1);\n }\n this.state = EntityDecoderState.NumericDecimal;\n return this.stateNumericDecimal(str, offset);\n }\n addToNumericResult(str, start, end, base2) {\n if (start !== end) {\n const digitCount = end - start;\n this.result = this.result * Math.pow(base2, digitCount) + parseInt(str.substr(start, digitCount), base2);\n this.consumed += digitCount;\n }\n }\n /**\n * Parses a hexadecimal numeric entity.\n *\n * Equivalent to the `Hexademical character reference state` in the HTML spec.\n *\n * @param str The string containing the entity (or a continuation of the entity).\n * @param offset The current offset.\n * @returns The number of characters that were consumed, or -1 if the entity is incomplete.\n */\n stateNumericHex(str, offset) {\n const startIdx = offset;\n while (offset < str.length) {\n const char = str.charCodeAt(offset);\n if (isNumber(char) || isHexadecimalCharacter(char)) {\n offset += 1;\n } else {\n this.addToNumericResult(str, startIdx, offset, 16);\n return this.emitNumericEntity(char, 3);\n }\n }\n this.addToNumericResult(str, startIdx, offset, 16);\n return -1;\n }\n /**\n * Parses a decimal numeric entity.\n *\n * Equivalent to the `Decimal character reference state` in the HTML spec.\n *\n * @param str The string containing the entity (or a continuation of the entity).\n * @param offset The current offset.\n * @returns The number of characters that were consumed, or -1 if the entity is incomplete.\n */\n stateNumericDecimal(str, offset) {\n const startIdx = offset;\n while (offset < str.length) {\n const char = str.charCodeAt(offset);\n if (isNumber(char)) {\n offset += 1;\n } else {\n this.addToNumericResult(str, startIdx, offset, 10);\n return this.emitNumericEntity(char, 2);\n }\n }\n this.addToNumericResult(str, startIdx, offset, 10);\n return -1;\n }\n /**\n * Validate and emit a numeric entity.\n *\n * Implements the logic from the `Hexademical character reference start\n * state` and `Numeric character reference end state` in the HTML spec.\n *\n * @param lastCp The last code point of the entity. Used to see if the\n * entity was terminated with a semicolon.\n * @param expectedLength The minimum number of characters that should be\n * consumed. Used to validate that at least one digit\n * was consumed.\n * @returns The number of characters that were consumed.\n */\n emitNumericEntity(lastCp, expectedLength) {\n var _a2;\n if (this.consumed <= expectedLength) {\n (_a2 = this.errors) === null || _a2 === void 0 ? void 0 : _a2.absenceOfDigitsInNumericCharacterReference(this.consumed);\n return 0;\n }\n if (lastCp === CharCodes.SEMI) {\n this.consumed += 1;\n } else if (this.decodeMode === DecodingMode.Strict) {\n return 0;\n }\n this.emitCodePoint(replaceCodePoint(this.result), this.consumed);\n if (this.errors) {\n if (lastCp !== CharCodes.SEMI) {\n this.errors.missingSemicolonAfterCharacterReference();\n }\n this.errors.validateNumericCharacterReference(this.result);\n }\n return this.consumed;\n }\n /**\n * Parses a named entity.\n *\n * Equivalent to the `Named character reference state` in the HTML spec.\n *\n * @param str The string containing the entity (or a continuation of the entity).\n * @param offset The current offset.\n * @returns The number of characters that were consumed, or -1 if the entity is incomplete.\n */\n stateNamedEntity(str, offset) {\n const { decodeTree } = this;\n let current = decodeTree[this.treeIndex];\n let valueLength = (current & BinTrieFlags.VALUE_LENGTH) >> 14;\n for (; offset < str.length; offset++, this.excess++) {\n const char = str.charCodeAt(offset);\n this.treeIndex = determineBranch(decodeTree, current, this.treeIndex + Math.max(1, valueLength), char);\n if (this.treeIndex < 0) {\n return this.result === 0 || // If we are parsing an attribute\n this.decodeMode === DecodingMode.Attribute && // We shouldn't have consumed any characters after the entity,\n (valueLength === 0 || // And there should be no invalid characters.\n isEntityInAttributeInvalidEnd(char)) ? 0 : this.emitNotTerminatedNamedEntity();\n }\n current = decodeTree[this.treeIndex];\n valueLength = (current & BinTrieFlags.VALUE_LENGTH) >> 14;\n if (valueLength !== 0) {\n if (char === CharCodes.SEMI) {\n return this.emitNamedEntityData(this.treeIndex, valueLength, this.consumed + this.excess);\n }\n if (this.decodeMode !== DecodingMode.Strict) {\n this.result = this.treeIndex;\n this.consumed += this.excess;\n this.excess = 0;\n }\n }\n }\n return -1;\n }\n /**\n * Emit a named entity that was not terminated with a semicolon.\n *\n * @returns The number of characters consumed.\n */\n emitNotTerminatedNamedEntity() {\n var _a2;\n const { result, decodeTree } = this;\n const valueLength = (decodeTree[result] & BinTrieFlags.VALUE_LENGTH) >> 14;\n this.emitNamedEntityData(result, valueLength, this.consumed);\n (_a2 = this.errors) === null || _a2 === void 0 ? void 0 : _a2.missingSemicolonAfterCharacterReference();\n return this.consumed;\n }\n /**\n * Emit a named entity.\n *\n * @param result The index of the entity in the decode tree.\n * @param valueLength The number of bytes in the entity.\n * @param consumed The number of characters consumed.\n *\n * @returns The number of characters consumed.\n */\n emitNamedEntityData(result, valueLength, consumed) {\n const { decodeTree } = this;\n this.emitCodePoint(valueLength === 1 ? decodeTree[result] & ~BinTrieFlags.VALUE_LENGTH : decodeTree[result + 1], consumed);\n if (valueLength === 3) {\n this.emitCodePoint(decodeTree[result + 2], consumed);\n }\n return consumed;\n }\n /**\n * Signal to the parser that the end of the input was reached.\n *\n * Remaining data will be emitted and relevant errors will be produced.\n *\n * @returns The number of characters consumed.\n */\n end() {\n var _a2;\n switch (this.state) {\n case EntityDecoderState.NamedEntity: {\n return this.result !== 0 && (this.decodeMode !== DecodingMode.Attribute || this.result === this.treeIndex) ? this.emitNotTerminatedNamedEntity() : 0;\n }\n // Otherwise, emit a numeric entity if we have one.\n case EntityDecoderState.NumericDecimal: {\n return this.emitNumericEntity(0, 2);\n }\n case EntityDecoderState.NumericHex: {\n return this.emitNumericEntity(0, 3);\n }\n case EntityDecoderState.NumericStart: {\n (_a2 = this.errors) === null || _a2 === void 0 ? void 0 : _a2.absenceOfDigitsInNumericCharacterReference(this.consumed);\n return 0;\n }\n case EntityDecoderState.EntityStart: {\n return 0;\n }\n }\n }\n};\nfunction getDecoder(decodeTree) {\n let ret = \"\";\n const decoder = new EntityDecoder(decodeTree, (str) => ret += fromCodePoint(str));\n return function decodeWithTrie(str, decodeMode) {\n let lastIndex = 0;\n let offset = 0;\n while ((offset = str.indexOf(\"&\", offset)) >= 0) {\n ret += str.slice(lastIndex, offset);\n decoder.startEntity(decodeMode);\n const len = decoder.write(\n str,\n // Skip the \"&\"\n offset + 1\n );\n if (len < 0) {\n lastIndex = offset + decoder.end();\n break;\n }\n lastIndex = offset + len;\n offset = len === 0 ? lastIndex + 1 : lastIndex;\n }\n const result = ret + str.slice(lastIndex);\n ret = \"\";\n return result;\n };\n}\nfunction determineBranch(decodeTree, current, nodeIdx, char) {\n const branchCount = (current & BinTrieFlags.BRANCH_LENGTH) >> 7;\n const jumpOffset = current & BinTrieFlags.JUMP_TABLE;\n if (branchCount === 0) {\n return jumpOffset !== 0 && char === jumpOffset ? nodeIdx : -1;\n }\n if (jumpOffset) {\n const value = char - jumpOffset;\n return value < 0 || value >= branchCount ? -1 : decodeTree[nodeIdx + value] - 1;\n }\n let lo = nodeIdx;\n let hi = lo + branchCount - 1;\n while (lo <= hi) {\n const mid = lo + hi >>> 1;\n const midVal = decodeTree[mid];\n if (midVal < char) {\n lo = mid + 1;\n } else if (midVal > char) {\n hi = mid - 1;\n } else {\n return decodeTree[mid + branchCount];\n }\n }\n return -1;\n}\nvar htmlDecoder = getDecoder(decode_data_html_default);\nvar xmlDecoder = getDecoder(decode_data_xml_default);\nfunction decodeHTML(str, mode = DecodingMode.Legacy) {\n return htmlDecoder(str, mode);\n}\n\n// node_modules/.pnpm/entities@4.5.0/node_modules/entities/lib/esm/generated/encode-html.js\nfunction restoreDiff(arr) {\n for (let i = 1; i < arr.length; i++) {\n arr[i][0] += arr[i - 1][0] + 1;\n }\n return arr;\n}\nvar encode_html_default = new Map(/* @__PURE__ */ restoreDiff([[9, \" \"], [0, \" \"], [22, \"!\"], [0, \""\"], [0, \"#\"], [0, \"$\"], [0, \"%\"], [0, \"&\"], [0, \"'\"], [0, \"(\"], [0, \")\"], [0, \"*\"], [0, \"+\"], [0, \",\"], [1, \".\"], [0, \"/\"], [10, \":\"], [0, \";\"], [0, { v: \"<\", n: 8402, o: \"<⃒\" }], [0, { v: \"=\", n: 8421, o: \"=⃥\" }], [0, { v: \">\", n: 8402, o: \">⃒\" }], [0, \"?\"], [0, \"@\"], [26, \"[\"], [0, \"\\"], [0, \"]\"], [0, \"^\"], [0, \"_\"], [0, \"`\"], [5, { n: 106, o: \"fj\" }], [20, \"{\"], [0, \"|\"], [0, \"}\"], [34, \" \"], [0, \"¡\"], [0, \"¢\"], [0, \"£\"], [0, \"¤\"], [0, \"¥\"], [0, \"¦\"], [0, \"§\"], [0, \"¨\"], [0, \"©\"], [0, \"ª\"], [0, \"«\"], [0, \"¬\"], [0, \"­\"], [0, \"®\"], [0, \"¯\"], [0, \"°\"], [0, \"±\"], [0, \"²\"], [0, \"³\"], [0, \"´\"], [0, \"µ\"], [0, \"¶\"], [0, \"·\"], [0, \"¸\"], [0, \"¹\"], [0, \"º\"], [0, \"»\"], [0, \"¼\"], [0, \"½\"], [0, \"¾\"], [0, \"¿\"], [0, \"À\"], [0, \"Á\"], [0, \"Â\"], [0, \"Ã\"], [0, \"Ä\"], [0, \"Å\"], [0, \"Æ\"], [0, \"Ç\"], [0, \"È\"], [0, \"É\"], [0, \"Ê\"], [0, \"Ë\"], [0, \"Ì\"], [0, \"Í\"], [0, \"Î\"], [0, \"Ï\"], [0, \"Ð\"], [0, \"Ñ\"], [0, \"Ò\"], [0, \"Ó\"], [0, \"Ô\"], [0, \"Õ\"], [0, \"Ö\"], [0, \"×\"], [0, \"Ø\"], [0, \"Ù\"], [0, \"Ú\"], [0, \"Û\"], [0, \"Ü\"], [0, \"Ý\"], [0, \"Þ\"], [0, \"ß\"], [0, \"à\"], [0, \"á\"], [0, \"â\"], [0, \"ã\"], [0, \"ä\"], [0, \"å\"], [0, \"æ\"], [0, \"ç\"], [0, \"è\"], [0, \"é\"], [0, \"ê\"], [0, \"ë\"], [0, \"ì\"], [0, \"í\"], [0, \"î\"], [0, \"ï\"], [0, \"ð\"], [0, \"ñ\"], [0, \"ò\"], [0, \"ó\"], [0, \"ô\"], [0, \"õ\"], [0, \"ö\"], [0, \"÷\"], [0, \"ø\"], [0, \"ù\"], [0, \"ú\"], [0, \"û\"], [0, \"ü\"], [0, \"ý\"], [0, \"þ\"], [0, \"ÿ\"], [0, \"Ā\"], [0, \"ā\"], [0, \"Ă\"], [0, \"ă\"], [0, \"Ą\"], [0, \"ą\"], [0, \"Ć\"], [0, \"ć\"], [0, \"Ĉ\"], [0, \"ĉ\"], [0, \"Ċ\"], [0, \"ċ\"], [0, \"Č\"], [0, \"č\"], [0, \"Ď\"], [0, \"ď\"], [0, \"Đ\"], [0, \"đ\"], [0, \"Ē\"], [0, \"ē\"], [2, \"Ė\"], [0, \"ė\"], [0, \"Ę\"], [0, \"ę\"], [0, \"Ě\"], [0, \"ě\"], [0, \"Ĝ\"], [0, \"ĝ\"], [0, \"Ğ\"], [0, \"ğ\"], [0, \"Ġ\"], [0, \"ġ\"], [0, \"Ģ\"], [1, \"Ĥ\"], [0, \"ĥ\"], [0, \"Ħ\"], [0, \"ħ\"], [0, \"Ĩ\"], [0, \"ĩ\"], [0, \"Ī\"], [0, \"ī\"], [2, \"Į\"], [0, \"į\"], [0, \"İ\"], [0, \"ı\"], [0, \"IJ\"], [0, \"ij\"], [0, \"Ĵ\"], [0, \"ĵ\"], [0, \"Ķ\"], [0, \"ķ\"], [0, \"ĸ\"], [0, \"Ĺ\"], [0, \"ĺ\"], [0, \"Ļ\"], [0, \"ļ\"], [0, \"Ľ\"], [0, \"ľ\"], [0, \"Ŀ\"], [0, \"ŀ\"], [0, \"Ł\"], [0, \"ł\"], [0, \"Ń\"], [0, \"ń\"], [0, \"Ņ\"], [0, \"ņ\"], [0, \"Ň\"], [0, \"ň\"], [0, \"ʼn\"], [0, \"Ŋ\"], [0, \"ŋ\"], [0, \"Ō\"], [0, \"ō\"], [2, \"Ő\"], [0, \"ő\"], [0, \"Œ\"], [0, \"œ\"], [0, \"Ŕ\"], [0, \"ŕ\"], [0, \"Ŗ\"], [0, \"ŗ\"], [0, \"Ř\"], [0, \"ř\"], [0, \"Ś\"], [0, \"ś\"], [0, \"Ŝ\"], [0, \"ŝ\"], [0, \"Ş\"], [0, \"ş\"], [0, \"Š\"], [0, \"š\"], [0, \"Ţ\"], [0, \"ţ\"], [0, \"Ť\"], [0, \"ť\"], [0, \"Ŧ\"], [0, \"ŧ\"], [0, \"Ũ\"], [0, \"ũ\"], [0, \"Ū\"], [0, \"ū\"], [0, \"Ŭ\"], [0, \"ŭ\"], [0, \"Ů\"], [0, \"ů\"], [0, \"Ű\"], [0, \"ű\"], [0, \"Ų\"], [0, \"ų\"], [0, \"Ŵ\"], [0, \"ŵ\"], [0, \"Ŷ\"], [0, \"ŷ\"], [0, \"Ÿ\"], [0, \"Ź\"], [0, \"ź\"], [0, \"Ż\"], [0, \"ż\"], [0, \"Ž\"], [0, \"ž\"], [19, \"ƒ\"], [34, \"Ƶ\"], [63, \"ǵ\"], [65, \"ȷ\"], [142, \"ˆ\"], [0, \"ˇ\"], [16, \"˘\"], [0, \"˙\"], [0, \"˚\"], [0, \"˛\"], [0, \"˜\"], [0, \"˝\"], [51, \"̑\"], [127, \"Α\"], [0, \"Β\"], [0, \"Γ\"], [0, \"Δ\"], [0, \"Ε\"], [0, \"Ζ\"], [0, \"Η\"], [0, \"Θ\"], [0, \"Ι\"], [0, \"Κ\"], [0, \"Λ\"], [0, \"Μ\"], [0, \"Ν\"], [0, \"Ξ\"], [0, \"Ο\"], [0, \"Π\"], [0, \"Ρ\"], [1, \"Σ\"], [0, \"Τ\"], [0, \"Υ\"], [0, \"Φ\"], [0, \"Χ\"], [0, \"Ψ\"], [0, \"Ω\"], [7, \"α\"], [0, \"β\"], [0, \"γ\"], [0, \"δ\"], [0, \"ε\"], [0, \"ζ\"], [0, \"η\"], [0, \"θ\"], [0, \"ι\"], [0, \"κ\"], [0, \"λ\"], [0, \"μ\"], [0, \"ν\"], [0, \"ξ\"], [0, \"ο\"], [0, \"π\"], [0, \"ρ\"], [0, \"ς\"], [0, \"σ\"], [0, \"τ\"], [0, \"υ\"], [0, \"φ\"], [0, \"χ\"], [0, \"ψ\"], [0, \"ω\"], [7, \"ϑ\"], [0, \"ϒ\"], [2, \"ϕ\"], [0, \"ϖ\"], [5, \"Ϝ\"], [0, \"ϝ\"], [18, \"ϰ\"], [0, \"ϱ\"], [3, \"ϵ\"], [0, \"϶\"], [10, \"Ё\"], [0, \"Ђ\"], [0, \"Ѓ\"], [0, \"Є\"], [0, \"Ѕ\"], [0, \"І\"], [0, \"Ї\"], [0, \"Ј\"], [0, \"Љ\"], [0, \"Њ\"], [0, \"Ћ\"], [0, \"Ќ\"], [1, \"Ў\"], [0, \"Џ\"], [0, \"А\"], [0, \"Б\"], [0, \"В\"], [0, \"Г\"], [0, \"Д\"], [0, \"Е\"], [0, \"Ж\"], [0, \"З\"], [0, \"И\"], [0, \"Й\"], [0, \"К\"], [0, \"Л\"], [0, \"М\"], [0, \"Н\"], [0, \"О\"], [0, \"П\"], [0, \"Р\"], [0, \"С\"], [0, \"Т\"], [0, \"У\"], [0, \"Ф\"], [0, \"Х\"], [0, \"Ц\"], [0, \"Ч\"], [0, \"Ш\"], [0, \"Щ\"], [0, \"Ъ\"], [0, \"Ы\"], [0, \"Ь\"], [0, \"Э\"], [0, \"Ю\"], [0, \"Я\"], [0, \"а\"], [0, \"б\"], [0, \"в\"], [0, \"г\"], [0, \"д\"], [0, \"е\"], [0, \"ж\"], [0, \"з\"], [0, \"и\"], [0, \"й\"], [0, \"к\"], [0, \"л\"], [0, \"м\"], [0, \"н\"], [0, \"о\"], [0, \"п\"], [0, \"р\"], [0, \"с\"], [0, \"т\"], [0, \"у\"], [0, \"ф\"], [0, \"х\"], [0, \"ц\"], [0, \"ч\"], [0, \"ш\"], [0, \"щ\"], [0, \"ъ\"], [0, \"ы\"], [0, \"ь\"], [0, \"э\"], [0, \"ю\"], [0, \"я\"], [1, \"ё\"], [0, \"ђ\"], [0, \"ѓ\"], [0, \"є\"], [0, \"ѕ\"], [0, \"і\"], [0, \"ї\"], [0, \"ј\"], [0, \"љ\"], [0, \"њ\"], [0, \"ћ\"], [0, \"ќ\"], [1, \"ў\"], [0, \"џ\"], [7074, \" \"], [0, \" \"], [0, \" \"], [0, \" \"], [1, \" \"], [0, \" \"], [0, \" \"], [0, \" \"], [0, \"​\"], [0, \"‌\"], [0, \"‍\"], [0, \"‎\"], [0, \"‏\"], [0, \"‐\"], [2, \"–\"], [0, \"—\"], [0, \"―\"], [0, \"‖\"], [1, \"‘\"], [0, \"’\"], [0, \"‚\"], [1, \"“\"], [0, \"”\"], [0, \"„\"], [1, \"†\"], [0, \"‡\"], [0, \"•\"], [2, \"‥\"], [0, \"…\"], [9, \"‰\"], [0, \"‱\"], [0, \"′\"], [0, \"″\"], [0, \"‴\"], [0, \"‵\"], [3, \"‹\"], [0, \"›\"], [3, \"‾\"], [2, \"⁁\"], [1, \"⁃\"], [0, \"⁄\"], [10, \"⁏\"], [7, \"⁗\"], [7, { v: \" \", n: 8202, o: \"  \" }], [0, \"⁠\"], [0, \"⁡\"], [0, \"⁢\"], [0, \"⁣\"], [72, \"€\"], [46, \"⃛\"], [0, \"⃜\"], [37, \"ℂ\"], [2, \"℅\"], [4, \"ℊ\"], [0, \"ℋ\"], [0, \"ℌ\"], [0, \"ℍ\"], [0, \"ℎ\"], [0, \"ℏ\"], [0, \"ℐ\"], [0, \"ℑ\"], [0, \"ℒ\"], [0, \"ℓ\"], [1, \"ℕ\"], [0, \"№\"], [0, \"℗\"], [0, \"℘\"], [0, \"ℙ\"], [0, \"ℚ\"], [0, \"ℛ\"], [0, \"ℜ\"], [0, \"ℝ\"], [0, \"℞\"], [3, \"™\"], [1, \"ℤ\"], [2, \"℧\"], [0, \"ℨ\"], [0, \"℩\"], [2, \"ℬ\"], [0, \"ℭ\"], [1, \"ℯ\"], [0, \"ℰ\"], [0, \"ℱ\"], [1, \"ℳ\"], [0, \"ℴ\"], [0, \"ℵ\"], [0, \"ℶ\"], [0, \"ℷ\"], [0, \"ℸ\"], [12, \"ⅅ\"], [0, \"ⅆ\"], [0, \"ⅇ\"], [0, \"ⅈ\"], [10, \"⅓\"], [0, \"⅔\"], [0, \"⅕\"], [0, \"⅖\"], [0, \"⅗\"], [0, \"⅘\"], [0, \"⅙\"], [0, \"⅚\"], [0, \"⅛\"], [0, \"⅜\"], [0, \"⅝\"], [0, \"⅞\"], [49, \"←\"], [0, \"↑\"], [0, \"→\"], [0, \"↓\"], [0, \"↔\"], [0, \"↕\"], [0, \"↖\"], [0, \"↗\"], [0, \"↘\"], [0, \"↙\"], [0, \"↚\"], [0, \"↛\"], [1, { v: \"↝\", n: 824, o: \"↝̸\" }], [0, \"↞\"], [0, \"↟\"], [0, \"↠\"], [0, \"↡\"], [0, \"↢\"], [0, \"↣\"], [0, \"↤\"], [0, \"↥\"], [0, \"↦\"], [0, \"↧\"], [1, \"↩\"], [0, \"↪\"], [0, \"↫\"], [0, \"↬\"], [0, \"↭\"], [0, \"↮\"], [1, \"↰\"], [0, \"↱\"], [0, \"↲\"], [0, \"↳\"], [1, \"↵\"], [0, \"↶\"], [0, \"↷\"], [2, \"↺\"], [0, \"↻\"], [0, \"↼\"], [0, \"↽\"], [0, \"↾\"], [0, \"↿\"], [0, \"⇀\"], [0, \"⇁\"], [0, \"⇂\"], [0, \"⇃\"], [0, \"⇄\"], [0, \"⇅\"], [0, \"⇆\"], [0, \"⇇\"], [0, \"⇈\"], [0, \"⇉\"], [0, \"⇊\"], [0, \"⇋\"], [0, \"⇌\"], [0, \"⇍\"], [0, \"⇎\"], [0, \"⇏\"], [0, \"⇐\"], [0, \"⇑\"], [0, \"⇒\"], [0, \"⇓\"], [0, \"⇔\"], [0, \"⇕\"], [0, \"⇖\"], [0, \"⇗\"], [0, \"⇘\"], [0, \"⇙\"], [0, \"⇚\"], [0, \"⇛\"], [1, \"⇝\"], [6, \"⇤\"], [0, \"⇥\"], [15, \"⇵\"], [7, \"⇽\"], [0, \"⇾\"], [0, \"⇿\"], [0, \"∀\"], [0, \"∁\"], [0, { v: \"∂\", n: 824, o: \"∂̸\" }], [0, \"∃\"], [0, \"∄\"], [0, \"∅\"], [1, \"∇\"], [0, \"∈\"], [0, \"∉\"], [1, \"∋\"], [0, \"∌\"], [2, \"∏\"], [0, \"∐\"], [0, \"∑\"], [0, \"−\"], [0, \"∓\"], [0, \"∔\"], [1, \"∖\"], [0, \"∗\"], [0, \"∘\"], [1, \"√\"], [2, \"∝\"], [0, \"∞\"], [0, \"∟\"], [0, { v: \"∠\", n: 8402, o: \"∠⃒\" }], [0, \"∡\"], [0, \"∢\"], [0, \"∣\"], [0, \"∤\"], [0, \"∥\"], [0, \"∦\"], [0, \"∧\"], [0, \"∨\"], [0, { v: \"∩\", n: 65024, o: \"∩︀\" }], [0, { v: \"∪\", n: 65024, o: \"∪︀\" }], [0, \"∫\"], [0, \"∬\"], [0, \"∭\"], [0, \"∮\"], [0, \"∯\"], [0, \"∰\"], [0, \"∱\"], [0, \"∲\"], [0, \"∳\"], [0, \"∴\"], [0, \"∵\"], [0, \"∶\"], [0, \"∷\"], [0, \"∸\"], [1, \"∺\"], [0, \"∻\"], [0, { v: \"∼\", n: 8402, o: \"∼⃒\" }], [0, { v: \"∽\", n: 817, o: \"∽̱\" }], [0, { v: \"∾\", n: 819, o: \"∾̳\" }], [0, \"∿\"], [0, \"≀\"], [0, \"≁\"], [0, { v: \"≂\", n: 824, o: \"≂̸\" }], [0, \"≃\"], [0, \"≄\"], [0, \"≅\"], [0, \"≆\"], [0, \"≇\"], [0, \"≈\"], [0, \"≉\"], [0, \"≊\"], [0, { v: \"≋\", n: 824, o: \"≋̸\" }], [0, \"≌\"], [0, { v: \"≍\", n: 8402, o: \"≍⃒\" }], [0, { v: \"≎\", n: 824, o: \"≎̸\" }], [0, { v: \"≏\", n: 824, o: \"≏̸\" }], [0, { v: \"≐\", n: 824, o: \"≐̸\" }], [0, \"≑\"], [0, \"≒\"], [0, \"≓\"], [0, \"≔\"], [0, \"≕\"], [0, \"≖\"], [0, \"≗\"], [1, \"≙\"], [0, \"≚\"], [1, \"≜\"], [2, \"≟\"], [0, \"≠\"], [0, { v: \"≡\", n: 8421, o: \"≡⃥\" }], [0, \"≢\"], [1, { v: \"≤\", n: 8402, o: \"≤⃒\" }], [0, { v: \"≥\", n: 8402, o: \"≥⃒\" }], [0, { v: \"≦\", n: 824, o: \"≦̸\" }], [0, { v: \"≧\", n: 824, o: \"≧̸\" }], [0, { v: \"≨\", n: 65024, o: \"≨︀\" }], [0, { v: \"≩\", n: 65024, o: \"≩︀\" }], [0, { v: \"≪\", n: new Map(/* @__PURE__ */ restoreDiff([[824, \"≪̸\"], [7577, \"≪⃒\"]])) }], [0, { v: \"≫\", n: new Map(/* @__PURE__ */ restoreDiff([[824, \"≫̸\"], [7577, \"≫⃒\"]])) }], [0, \"≬\"], [0, \"≭\"], [0, \"≮\"], [0, \"≯\"], [0, \"≰\"], [0, \"≱\"], [0, \"≲\"], [0, \"≳\"], [0, \"≴\"], [0, \"≵\"], [0, \"≶\"], [0, \"≷\"], [0, \"≸\"], [0, \"≹\"], [0, \"≺\"], [0, \"≻\"], [0, \"≼\"], [0, \"≽\"], [0, \"≾\"], [0, { v: \"≿\", n: 824, o: \"≿̸\" }], [0, \"⊀\"], [0, \"⊁\"], [0, { v: \"⊂\", n: 8402, o: \"⊂⃒\" }], [0, { v: \"⊃\", n: 8402, o: \"⊃⃒\" }], [0, \"⊄\"], [0, \"⊅\"], [0, \"⊆\"], [0, \"⊇\"], [0, \"⊈\"], [0, \"⊉\"], [0, { v: \"⊊\", n: 65024, o: \"⊊︀\" }], [0, { v: \"⊋\", n: 65024, o: \"⊋︀\" }], [1, \"⊍\"], [0, \"⊎\"], [0, { v: \"⊏\", n: 824, o: \"⊏̸\" }], [0, { v: \"⊐\", n: 824, o: \"⊐̸\" }], [0, \"⊑\"], [0, \"⊒\"], [0, { v: \"⊓\", n: 65024, o: \"⊓︀\" }], [0, { v: \"⊔\", n: 65024, o: \"⊔︀\" }], [0, \"⊕\"], [0, \"⊖\"], [0, \"⊗\"], [0, \"⊘\"], [0, \"⊙\"], [0, \"⊚\"], [0, \"⊛\"], [1, \"⊝\"], [0, \"⊞\"], [0, \"⊟\"], [0, \"⊠\"], [0, \"⊡\"], [0, \"⊢\"], [0, \"⊣\"], [0, \"⊤\"], [0, \"⊥\"], [1, \"⊧\"], [0, \"⊨\"], [0, \"⊩\"], [0, \"⊪\"], [0, \"⊫\"], [0, \"⊬\"], [0, \"⊭\"], [0, \"⊮\"], [0, \"⊯\"], [0, \"⊰\"], [1, \"⊲\"], [0, \"⊳\"], [0, { v: \"⊴\", n: 8402, o: \"⊴⃒\" }], [0, { v: \"⊵\", n: 8402, o: \"⊵⃒\" }], [0, \"⊶\"], [0, \"⊷\"], [0, \"⊸\"], [0, \"⊹\"], [0, \"⊺\"], [0, \"⊻\"], [1, \"⊽\"], [0, \"⊾\"], [0, \"⊿\"], [0, \"⋀\"], [0, \"⋁\"], [0, \"⋂\"], [0, \"⋃\"], [0, \"⋄\"], [0, \"⋅\"], [0, \"⋆\"], [0, \"⋇\"], [0, \"⋈\"], [0, \"⋉\"], [0, \"⋊\"], [0, \"⋋\"], [0, \"⋌\"], [0, \"⋍\"], [0, \"⋎\"], [0, \"⋏\"], [0, \"⋐\"], [0, \"⋑\"], [0, \"⋒\"], [0, \"⋓\"], [0, \"⋔\"], [0, \"⋕\"], [0, \"⋖\"], [0, \"⋗\"], [0, { v: \"⋘\", n: 824, o: \"⋘̸\" }], [0, { v: \"⋙\", n: 824, o: \"⋙̸\" }], [0, { v: \"⋚\", n: 65024, o: \"⋚︀\" }], [0, { v: \"⋛\", n: 65024, o: \"⋛︀\" }], [2, \"⋞\"], [0, \"⋟\"], [0, \"⋠\"], [0, \"⋡\"], [0, \"⋢\"], [0, \"⋣\"], [2, \"⋦\"], [0, \"⋧\"], [0, \"⋨\"], [0, \"⋩\"], [0, \"⋪\"], [0, \"⋫\"], [0, \"⋬\"], [0, \"⋭\"], [0, \"⋮\"], [0, \"⋯\"], [0, \"⋰\"], [0, \"⋱\"], [0, \"⋲\"], [0, \"⋳\"], [0, \"⋴\"], [0, { v: \"⋵\", n: 824, o: \"⋵̸\" }], [0, \"⋶\"], [0, \"⋷\"], [1, { v: \"⋹\", n: 824, o: \"⋹̸\" }], [0, \"⋺\"], [0, \"⋻\"], [0, \"⋼\"], [0, \"⋽\"], [0, \"⋾\"], [6, \"⌅\"], [0, \"⌆\"], [1, \"⌈\"], [0, \"⌉\"], [0, \"⌊\"], [0, \"⌋\"], [0, \"⌌\"], [0, \"⌍\"], [0, \"⌎\"], [0, \"⌏\"], [0, \"⌐\"], [1, \"⌒\"], [0, \"⌓\"], [1, \"⌕\"], [0, \"⌖\"], [5, \"⌜\"], [0, \"⌝\"], [0, \"⌞\"], [0, \"⌟\"], [2, \"⌢\"], [0, \"⌣\"], [9, \"⌭\"], [0, \"⌮\"], [7, \"⌶\"], [6, \"⌽\"], [1, \"⌿\"], [60, \"⍼\"], [51, \"⎰\"], [0, \"⎱\"], [2, \"⎴\"], [0, \"⎵\"], [0, \"⎶\"], [37, \"⏜\"], [0, \"⏝\"], [0, \"⏞\"], [0, \"⏟\"], [2, \"⏢\"], [4, \"⏧\"], [59, \"␣\"], [164, \"Ⓢ\"], [55, \"─\"], [1, \"│\"], [9, \"┌\"], [3, \"┐\"], [3, \"└\"], [3, \"┘\"], [3, \"├\"], [7, \"┤\"], [7, \"┬\"], [7, \"┴\"], [7, \"┼\"], [19, \"═\"], [0, \"║\"], [0, \"╒\"], [0, \"╓\"], [0, \"╔\"], [0, \"╕\"], [0, \"╖\"], [0, \"╗\"], [0, \"╘\"], [0, \"╙\"], [0, \"╚\"], [0, \"╛\"], [0, \"╜\"], [0, \"╝\"], [0, \"╞\"], [0, \"╟\"], [0, \"╠\"], [0, \"╡\"], [0, \"╢\"], [0, \"╣\"], [0, \"╤\"], [0, \"╥\"], [0, \"╦\"], [0, \"╧\"], [0, \"╨\"], [0, \"╩\"], [0, \"╪\"], [0, \"╫\"], [0, \"╬\"], [19, \"▀\"], [3, \"▄\"], [3, \"█\"], [8, \"░\"], [0, \"▒\"], [0, \"▓\"], [13, \"□\"], [8, \"▪\"], [0, \"▫\"], [1, \"▭\"], [0, \"▮\"], [2, \"▱\"], [1, \"△\"], [0, \"▴\"], [0, \"▵\"], [2, \"▸\"], [0, \"▹\"], [3, \"▽\"], [0, \"▾\"], [0, \"▿\"], [2, \"◂\"], [0, \"◃\"], [6, \"◊\"], [0, \"○\"], [32, \"◬\"], [2, \"◯\"], [8, \"◸\"], [0, \"◹\"], [0, \"◺\"], [0, \"◻\"], [0, \"◼\"], [8, \"★\"], [0, \"☆\"], [7, \"☎\"], [49, \"♀\"], [1, \"♂\"], [29, \"♠\"], [2, \"♣\"], [1, \"♥\"], [0, \"♦\"], [3, \"♪\"], [2, \"♭\"], [0, \"♮\"], [0, \"♯\"], [163, \"✓\"], [3, \"✗\"], [8, \"✠\"], [21, \"✶\"], [33, \"❘\"], [25, \"❲\"], [0, \"❳\"], [84, \"⟈\"], [0, \"⟉\"], [28, \"⟦\"], [0, \"⟧\"], [0, \"⟨\"], [0, \"⟩\"], [0, \"⟪\"], [0, \"⟫\"], [0, \"⟬\"], [0, \"⟭\"], [7, \"⟵\"], [0, \"⟶\"], [0, \"⟷\"], [0, \"⟸\"], [0, \"⟹\"], [0, \"⟺\"], [1, \"⟼\"], [2, \"⟿\"], [258, \"⤂\"], [0, \"⤃\"], [0, \"⤄\"], [0, \"⤅\"], [6, \"⤌\"], [0, \"⤍\"], [0, \"⤎\"], [0, \"⤏\"], [0, \"⤐\"], [0, \"⤑\"], [0, \"⤒\"], [0, \"⤓\"], [2, \"⤖\"], [2, \"⤙\"], [0, \"⤚\"], [0, \"⤛\"], [0, \"⤜\"], [0, \"⤝\"], [0, \"⤞\"], [0, \"⤟\"], [0, \"⤠\"], [2, \"⤣\"], [0, \"⤤\"], [0, \"⤥\"], [0, \"⤦\"], [0, \"⤧\"], [0, \"⤨\"], [0, \"⤩\"], [0, \"⤪\"], [8, { v: \"⤳\", n: 824, o: \"⤳̸\" }], [1, \"⤵\"], [0, \"⤶\"], [0, \"⤷\"], [0, \"⤸\"], [0, \"⤹\"], [2, \"⤼\"], [0, \"⤽\"], [7, \"⥅\"], [2, \"⥈\"], [0, \"⥉\"], [0, \"⥊\"], [0, \"⥋\"], [2, \"⥎\"], [0, \"⥏\"], [0, \"⥐\"], [0, \"⥑\"], [0, \"⥒\"], [0, \"⥓\"], [0, \"⥔\"], [0, \"⥕\"], [0, \"⥖\"], [0, \"⥗\"], [0, \"⥘\"], [0, \"⥙\"], [0, \"⥚\"], [0, \"⥛\"], [0, \"⥜\"], [0, \"⥝\"], [0, \"⥞\"], [0, \"⥟\"], [0, \"⥠\"], [0, \"⥡\"], [0, \"⥢\"], [0, \"⥣\"], [0, \"⥤\"], [0, \"⥥\"], [0, \"⥦\"], [0, \"⥧\"], [0, \"⥨\"], [0, \"⥩\"], [0, \"⥪\"], [0, \"⥫\"], [0, \"⥬\"], [0, \"⥭\"], [0, \"⥮\"], [0, \"⥯\"], [0, \"⥰\"], [0, \"⥱\"], [0, \"⥲\"], [0, \"⥳\"], [0, \"⥴\"], [0, \"⥵\"], [0, \"⥶\"], [1, \"⥸\"], [0, \"⥹\"], [1, \"⥻\"], [0, \"⥼\"], [0, \"⥽\"], [0, \"⥾\"], [0, \"⥿\"], [5, \"⦅\"], [0, \"⦆\"], [4, \"⦋\"], [0, \"⦌\"], [0, \"⦍\"], [0, \"⦎\"], [0, \"⦏\"], [0, \"⦐\"], [0, \"⦑\"], [0, \"⦒\"], [0, \"⦓\"], [0, \"⦔\"], [0, \"⦕\"], [0, \"⦖\"], [3, \"⦚\"], [1, \"⦜\"], [0, \"⦝\"], [6, \"⦤\"], [0, \"⦥\"], [0, \"⦦\"], [0, \"⦧\"], [0, \"⦨\"], [0, \"⦩\"], [0, \"⦪\"], [0, \"⦫\"], [0, \"⦬\"], [0, \"⦭\"], [0, \"⦮\"], [0, \"⦯\"], [0, \"⦰\"], [0, \"⦱\"], [0, \"⦲\"], [0, \"⦳\"], [0, \"⦴\"], [0, \"⦵\"], [0, \"⦶\"], [0, \"⦷\"], [1, \"⦹\"], [1, \"⦻\"], [0, \"⦼\"], [1, \"⦾\"], [0, \"⦿\"], [0, \"⧀\"], [0, \"⧁\"], [0, \"⧂\"], [0, \"⧃\"], [0, \"⧄\"], [0, \"⧅\"], [3, \"⧉\"], [3, \"⧍\"], [0, \"⧎\"], [0, { v: \"⧏\", n: 824, o: \"⧏̸\" }], [0, { v: \"⧐\", n: 824, o: \"⧐̸\" }], [11, \"⧜\"], [0, \"⧝\"], [0, \"⧞\"], [4, \"⧣\"], [0, \"⧤\"], [0, \"⧥\"], [5, \"⧫\"], [8, \"⧴\"], [1, \"⧶\"], [9, \"⨀\"], [0, \"⨁\"], [0, \"⨂\"], [1, \"⨄\"], [1, \"⨆\"], [5, \"⨌\"], [0, \"⨍\"], [2, \"⨐\"], [0, \"⨑\"], [0, \"⨒\"], [0, \"⨓\"], [0, \"⨔\"], [0, \"⨕\"], [0, \"⨖\"], [0, \"⨗\"], [10, \"⨢\"], [0, \"⨣\"], [0, \"⨤\"], [0, \"⨥\"], [0, \"⨦\"], [0, \"⨧\"], [1, \"⨩\"], [0, \"⨪\"], [2, \"⨭\"], [0, \"⨮\"], [0, \"⨯\"], [0, \"⨰\"], [0, \"⨱\"], [1, \"⨳\"], [0, \"⨴\"], [0, \"⨵\"], [0, \"⨶\"], [0, \"⨷\"], [0, \"⨸\"], [0, \"⨹\"], [0, \"⨺\"], [0, \"⨻\"], [0, \"⨼\"], [2, \"⨿\"], [0, \"⩀\"], [1, \"⩂\"], [0, \"⩃\"], [0, \"⩄\"], [0, \"⩅\"], [0, \"⩆\"], [0, \"⩇\"], [0, \"⩈\"], [0, \"⩉\"], [0, \"⩊\"], [0, \"⩋\"], [0, \"⩌\"], [0, \"⩍\"], [2, \"⩐\"], [2, \"⩓\"], [0, \"⩔\"], [0, \"⩕\"], [0, \"⩖\"], [0, \"⩗\"], [0, \"⩘\"], [1, \"⩚\"], [0, \"⩛\"], [0, \"⩜\"], [0, \"⩝\"], [1, \"⩟\"], [6, \"⩦\"], [3, \"⩪\"], [2, { v: \"⩭\", n: 824, o: \"⩭̸\" }], [0, \"⩮\"], [0, \"⩯\"], [0, { v: \"⩰\", n: 824, o: \"⩰̸\" }], [0, \"⩱\"], [0, \"⩲\"], [0, \"⩳\"], [0, \"⩴\"], [0, \"⩵\"], [1, \"⩷\"], [0, \"⩸\"], [0, \"⩹\"], [0, \"⩺\"], [0, \"⩻\"], [0, \"⩼\"], [0, { v: \"⩽\", n: 824, o: \"⩽̸\" }], [0, { v: \"⩾\", n: 824, o: \"⩾̸\" }], [0, \"⩿\"], [0, \"⪀\"], [0, \"⪁\"], [0, \"⪂\"], [0, \"⪃\"], [0, \"⪄\"], [0, \"⪅\"], [0, \"⪆\"], [0, \"⪇\"], [0, \"⪈\"], [0, \"⪉\"], [0, \"⪊\"], [0, \"⪋\"], [0, \"⪌\"], [0, \"⪍\"], [0, \"⪎\"], [0, \"⪏\"], [0, \"⪐\"], [0, \"⪑\"], [0, \"⪒\"], [0, \"⪓\"], [0, \"⪔\"], [0, \"⪕\"], [0, \"⪖\"], [0, \"⪗\"], [0, \"⪘\"], [0, \"⪙\"], [0, \"⪚\"], [2, \"⪝\"], [0, \"⪞\"], [0, \"⪟\"], [0, \"⪠\"], [0, { v: \"⪡\", n: 824, o: \"⪡̸\" }], [0, { v: \"⪢\", n: 824, o: \"⪢̸\" }], [1, \"⪤\"], [0, \"⪥\"], [0, \"⪦\"], [0, \"⪧\"], [0, \"⪨\"], [0, \"⪩\"], [0, \"⪪\"], [0, \"⪫\"], [0, { v: \"⪬\", n: 65024, o: \"⪬︀\" }], [0, { v: \"⪭\", n: 65024, o: \"⪭︀\" }], [0, \"⪮\"], [0, { v: \"⪯\", n: 824, o: \"⪯̸\" }], [0, { v: \"⪰\", n: 824, o: \"⪰̸\" }], [2, \"⪳\"], [0, \"⪴\"], [0, \"⪵\"], [0, \"⪶\"], [0, \"⪷\"], [0, \"⪸\"], [0, \"⪹\"], [0, \"⪺\"], [0, \"⪻\"], [0, \"⪼\"], [0, \"⪽\"], [0, \"⪾\"], [0, \"⪿\"], [0, \"⫀\"], [0, \"⫁\"], [0, \"⫂\"], [0, \"⫃\"], [0, \"⫄\"], [0, { v: \"⫅\", n: 824, o: \"⫅̸\" }], [0, { v: \"⫆\", n: 824, o: \"⫆̸\" }], [0, \"⫇\"], [0, \"⫈\"], [2, { v: \"⫋\", n: 65024, o: \"⫋︀\" }], [0, { v: \"⫌\", n: 65024, o: \"⫌︀\" }], [2, \"⫏\"], [0, \"⫐\"], [0, \"⫑\"], [0, \"⫒\"], [0, \"⫓\"], [0, \"⫔\"], [0, \"⫕\"], [0, \"⫖\"], [0, \"⫗\"], [0, \"⫘\"], [0, \"⫙\"], [0, \"⫚\"], [0, \"⫛\"], [8, \"⫤\"], [1, \"⫦\"], [0, \"⫧\"], [0, \"⫨\"], [0, \"⫩\"], [1, \"⫫\"], [0, \"⫬\"], [0, \"⫭\"], [0, \"⫮\"], [0, \"⫯\"], [0, \"⫰\"], [0, \"⫱\"], [0, \"⫲\"], [0, \"⫳\"], [9, { v: \"⫽\", n: 8421, o: \"⫽⃥\" }], [44343, { n: new Map(/* @__PURE__ */ restoreDiff([[56476, \"𝒜\"], [1, \"𝒞\"], [0, \"𝒟\"], [2, \"𝒢\"], [2, \"𝒥\"], [0, \"𝒦\"], [2, \"𝒩\"], [0, \"𝒪\"], [0, \"𝒫\"], [0, \"𝒬\"], [1, \"𝒮\"], [0, \"𝒯\"], [0, \"𝒰\"], [0, \"𝒱\"], [0, \"𝒲\"], [0, \"𝒳\"], [0, \"𝒴\"], [0, \"𝒵\"], [0, \"𝒶\"], [0, \"𝒷\"], [0, \"𝒸\"], [0, \"𝒹\"], [1, \"𝒻\"], [1, \"𝒽\"], [0, \"𝒾\"], [0, \"𝒿\"], [0, \"𝓀\"], [0, \"𝓁\"], [0, \"𝓂\"], [0, \"𝓃\"], [1, \"𝓅\"], [0, \"𝓆\"], [0, \"𝓇\"], [0, \"𝓈\"], [0, \"𝓉\"], [0, \"𝓊\"], [0, \"𝓋\"], [0, \"𝓌\"], [0, \"𝓍\"], [0, \"𝓎\"], [0, \"𝓏\"], [52, \"𝔄\"], [0, \"𝔅\"], [1, \"𝔇\"], [0, \"𝔈\"], [0, \"𝔉\"], [0, \"𝔊\"], [2, \"𝔍\"], [0, \"𝔎\"], [0, \"𝔏\"], [0, \"𝔐\"], [0, \"𝔑\"], [0, \"𝔒\"], [0, \"𝔓\"], [0, \"𝔔\"], [1, \"𝔖\"], [0, \"𝔗\"], [0, \"𝔘\"], [0, \"𝔙\"], [0, \"𝔚\"], [0, \"𝔛\"], [0, \"𝔜\"], [1, \"𝔞\"], [0, \"𝔟\"], [0, \"𝔠\"], [0, \"𝔡\"], [0, \"𝔢\"], [0, \"𝔣\"], [0, \"𝔤\"], [0, \"𝔥\"], [0, \"𝔦\"], [0, \"𝔧\"], [0, \"𝔨\"], [0, \"𝔩\"], [0, \"𝔪\"], [0, \"𝔫\"], [0, \"𝔬\"], [0, \"𝔭\"], [0, \"𝔮\"], [0, \"𝔯\"], [0, \"𝔰\"], [0, \"𝔱\"], [0, \"𝔲\"], [0, \"𝔳\"], [0, \"𝔴\"], [0, \"𝔵\"], [0, \"𝔶\"], [0, \"𝔷\"], [0, \"𝔸\"], [0, \"𝔹\"], [1, \"𝔻\"], [0, \"𝔼\"], [0, \"𝔽\"], [0, \"𝔾\"], [1, \"𝕀\"], [0, \"𝕁\"], [0, \"𝕂\"], [0, \"𝕃\"], [0, \"𝕄\"], [1, \"𝕆\"], [3, \"𝕊\"], [0, \"𝕋\"], [0, \"𝕌\"], [0, \"𝕍\"], [0, \"𝕎\"], [0, \"𝕏\"], [0, \"𝕐\"], [1, \"𝕒\"], [0, \"𝕓\"], [0, \"𝕔\"], [0, \"𝕕\"], [0, \"𝕖\"], [0, \"𝕗\"], [0, \"𝕘\"], [0, \"𝕙\"], [0, \"𝕚\"], [0, \"𝕛\"], [0, \"𝕜\"], [0, \"𝕝\"], [0, \"𝕞\"], [0, \"𝕟\"], [0, \"𝕠\"], [0, \"𝕡\"], [0, \"𝕢\"], [0, \"𝕣\"], [0, \"𝕤\"], [0, \"𝕥\"], [0, \"𝕦\"], [0, \"𝕧\"], [0, \"𝕨\"], [0, \"𝕩\"], [0, \"𝕪\"], [0, \"𝕫\"]])) }], [8906, \"ff\"], [0, \"fi\"], [0, \"fl\"], [0, \"ffi\"], [0, \"ffl\"]]));\n\n// node_modules/.pnpm/entities@4.5.0/node_modules/entities/lib/esm/escape.js\nvar xmlCodeMap = /* @__PURE__ */ new Map([\n [34, \""\"],\n [38, \"&\"],\n [39, \"'\"],\n [60, \"<\"],\n [62, \">\"]\n]);\nvar getCodePoint = (\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n String.prototype.codePointAt != null ? (str, index) => str.codePointAt(index) : (\n // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae\n (c, index) => (c.charCodeAt(index) & 64512) === 55296 ? (c.charCodeAt(index) - 55296) * 1024 + c.charCodeAt(index + 1) - 56320 + 65536 : c.charCodeAt(index)\n )\n);\nfunction getEscaper(regex, map2) {\n return function escape3(data) {\n let match2;\n let lastIdx = 0;\n let result = \"\";\n while (match2 = regex.exec(data)) {\n if (lastIdx !== match2.index) {\n result += data.substring(lastIdx, match2.index);\n }\n result += map2.get(match2[0].charCodeAt(0));\n lastIdx = match2.index + 1;\n }\n return result + data.substring(lastIdx);\n };\n}\nvar escapeUTF8 = getEscaper(/[&<>'\"]/g, xmlCodeMap);\nvar escapeAttribute = getEscaper(/[\"&\\u00A0]/g, /* @__PURE__ */ new Map([\n [34, \""\"],\n [38, \"&\"],\n [160, \" \"]\n]));\nvar escapeText = getEscaper(/[&<>\\u00A0]/g, /* @__PURE__ */ new Map([\n [38, \"&\"],\n [60, \"<\"],\n [62, \">\"],\n [160, \" \"]\n]));\n\n// node_modules/.pnpm/entities@4.5.0/node_modules/entities/lib/esm/index.js\nvar EntityLevel;\n(function(EntityLevel2) {\n EntityLevel2[EntityLevel2[\"XML\"] = 0] = \"XML\";\n EntityLevel2[EntityLevel2[\"HTML\"] = 1] = \"HTML\";\n})(EntityLevel || (EntityLevel = {}));\nvar EncodingMode;\n(function(EncodingMode2) {\n EncodingMode2[EncodingMode2[\"UTF8\"] = 0] = \"UTF8\";\n EncodingMode2[EncodingMode2[\"ASCII\"] = 1] = \"ASCII\";\n EncodingMode2[EncodingMode2[\"Extensive\"] = 2] = \"Extensive\";\n EncodingMode2[EncodingMode2[\"Attribute\"] = 3] = \"Attribute\";\n EncodingMode2[EncodingMode2[\"Text\"] = 4] = \"Text\";\n})(EncodingMode || (EncodingMode = {}));\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/common/utils.mjs\nfunction _class(obj) {\n return Object.prototype.toString.call(obj);\n}\nfunction isString(obj) {\n return _class(obj) === \"[object String]\";\n}\nvar _hasOwnProperty = Object.prototype.hasOwnProperty;\nfunction has(object, key) {\n return _hasOwnProperty.call(object, key);\n}\nfunction assign(obj) {\n const sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source2) {\n if (!source2) {\n return;\n }\n if (typeof source2 !== \"object\") {\n throw new TypeError(source2 + \"must be object\");\n }\n Object.keys(source2).forEach(function(key) {\n obj[key] = source2[key];\n });\n });\n return obj;\n}\nfunction arrayReplaceAt(src, pos, newElements) {\n return [].concat(src.slice(0, pos), newElements, src.slice(pos + 1));\n}\nfunction isValidEntityCode(c) {\n if (c >= 55296 && c <= 57343) {\n return false;\n }\n if (c >= 64976 && c <= 65007) {\n return false;\n }\n if ((c & 65535) === 65535 || (c & 65535) === 65534) {\n return false;\n }\n if (c >= 0 && c <= 8) {\n return false;\n }\n if (c === 11) {\n return false;\n }\n if (c >= 14 && c <= 31) {\n return false;\n }\n if (c >= 127 && c <= 159) {\n return false;\n }\n if (c > 1114111) {\n return false;\n }\n return true;\n}\nfunction fromCodePoint2(c) {\n if (c > 65535) {\n c -= 65536;\n const surrogate1 = 55296 + (c >> 10);\n const surrogate2 = 56320 + (c & 1023);\n return String.fromCharCode(surrogate1, surrogate2);\n }\n return String.fromCharCode(c);\n}\nvar UNESCAPE_MD_RE = /\\\\([!\"#$%&'()*+,\\-./:;<=>?@[\\\\\\]^_`{|}~])/g;\nvar ENTITY_RE = /&([a-z#][a-z0-9]{1,31});/gi;\nvar UNESCAPE_ALL_RE = new RegExp(UNESCAPE_MD_RE.source + \"|\" + ENTITY_RE.source, \"gi\");\nvar DIGITAL_ENTITY_TEST_RE = /^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))$/i;\nfunction replaceEntityPattern(match2, name) {\n if (name.charCodeAt(0) === 35 && DIGITAL_ENTITY_TEST_RE.test(name)) {\n const code2 = name[1].toLowerCase() === \"x\" ? parseInt(name.slice(2), 16) : parseInt(name.slice(1), 10);\n if (isValidEntityCode(code2)) {\n return fromCodePoint2(code2);\n }\n return match2;\n }\n const decoded = decodeHTML(match2);\n if (decoded !== match2) {\n return decoded;\n }\n return match2;\n}\nfunction unescapeMd(str) {\n if (str.indexOf(\"\\\\\") < 0) {\n return str;\n }\n return str.replace(UNESCAPE_MD_RE, \"$1\");\n}\nfunction unescapeAll(str) {\n if (str.indexOf(\"\\\\\") < 0 && str.indexOf(\"&\") < 0) {\n return str;\n }\n return str.replace(UNESCAPE_ALL_RE, function(match2, escaped, entity2) {\n if (escaped) {\n return escaped;\n }\n return replaceEntityPattern(match2, entity2);\n });\n}\nvar HTML_ESCAPE_TEST_RE = /[&<>\"]/;\nvar HTML_ESCAPE_REPLACE_RE = /[&<>\"]/g;\nvar HTML_REPLACEMENTS = {\n \"&\": \"&\",\n \"<\": \"<\",\n \">\": \">\",\n '\"': \""\"\n};\nfunction replaceUnsafeChar(ch) {\n return HTML_REPLACEMENTS[ch];\n}\nfunction escapeHtml(str) {\n if (HTML_ESCAPE_TEST_RE.test(str)) {\n return str.replace(HTML_ESCAPE_REPLACE_RE, replaceUnsafeChar);\n }\n return str;\n}\nvar REGEXP_ESCAPE_RE = /[.?*+^$[\\]\\\\(){}|-]/g;\nfunction escapeRE(str) {\n return str.replace(REGEXP_ESCAPE_RE, \"\\\\$&\");\n}\nfunction isSpace(code2) {\n switch (code2) {\n case 9:\n case 32:\n return true;\n }\n return false;\n}\nfunction isWhiteSpace(code2) {\n if (code2 >= 8192 && code2 <= 8202) {\n return true;\n }\n switch (code2) {\n case 9:\n // \\t\n case 10:\n // \\n\n case 11:\n // \\v\n case 12:\n // \\f\n case 13:\n // \\r\n case 32:\n case 160:\n case 5760:\n case 8239:\n case 8287:\n case 12288:\n return true;\n }\n return false;\n}\nfunction isPunctChar(ch) {\n return regex_default4.test(ch) || regex_default5.test(ch);\n}\nfunction isMdAsciiPunct(ch) {\n switch (ch) {\n case 33:\n case 34:\n case 35:\n case 36:\n case 37:\n case 38:\n case 39:\n case 40:\n case 41:\n case 42:\n case 43:\n case 44:\n case 45:\n case 46:\n case 47:\n case 58:\n case 59:\n case 60:\n case 61:\n case 62:\n case 63:\n case 64:\n case 91:\n case 92:\n case 93:\n case 94:\n case 95:\n case 96:\n case 123:\n case 124:\n case 125:\n case 126:\n return true;\n default:\n return false;\n }\n}\nfunction normalizeReference(str) {\n str = str.trim().replace(/\\s+/g, \" \");\n if (\"ẞ\".toLowerCase() === \"Ṿ\") {\n str = str.replace(/ẞ/g, \"ß\");\n }\n return str.toLowerCase().toUpperCase();\n}\nvar lib = { mdurl: mdurl_exports, ucmicro: uc_exports };\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/helpers/index.mjs\nvar helpers_exports = {};\n__export(helpers_exports, {\n parseLinkDestination: () => parseLinkDestination,\n parseLinkLabel: () => parseLinkLabel,\n parseLinkTitle: () => parseLinkTitle\n});\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/helpers/parse_link_label.mjs\nfunction parseLinkLabel(state, start, disableNested) {\n let level, found, marker, prevPos;\n const max = state.posMax;\n const oldPos = state.pos;\n state.pos = start + 1;\n level = 1;\n while (state.pos < max) {\n marker = state.src.charCodeAt(state.pos);\n if (marker === 93) {\n level--;\n if (level === 0) {\n found = true;\n break;\n }\n }\n prevPos = state.pos;\n state.md.inline.skipToken(state);\n if (marker === 91) {\n if (prevPos === state.pos - 1) {\n level++;\n } else if (disableNested) {\n state.pos = oldPos;\n return -1;\n }\n }\n }\n let labelEnd = -1;\n if (found) {\n labelEnd = state.pos;\n }\n state.pos = oldPos;\n return labelEnd;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/helpers/parse_link_destination.mjs\nfunction parseLinkDestination(str, start, max) {\n let code2;\n let pos = start;\n const result = {\n ok: false,\n pos: 0,\n str: \"\"\n };\n if (str.charCodeAt(pos) === 60) {\n pos++;\n while (pos < max) {\n code2 = str.charCodeAt(pos);\n if (code2 === 10) {\n return result;\n }\n if (code2 === 60) {\n return result;\n }\n if (code2 === 62) {\n result.pos = pos + 1;\n result.str = unescapeAll(str.slice(start + 1, pos));\n result.ok = true;\n return result;\n }\n if (code2 === 92 && pos + 1 < max) {\n pos += 2;\n continue;\n }\n pos++;\n }\n return result;\n }\n let level = 0;\n while (pos < max) {\n code2 = str.charCodeAt(pos);\n if (code2 === 32) {\n break;\n }\n if (code2 < 32 || code2 === 127) {\n break;\n }\n if (code2 === 92 && pos + 1 < max) {\n if (str.charCodeAt(pos + 1) === 32) {\n break;\n }\n pos += 2;\n continue;\n }\n if (code2 === 40) {\n level++;\n if (level > 32) {\n return result;\n }\n }\n if (code2 === 41) {\n if (level === 0) {\n break;\n }\n level--;\n }\n pos++;\n }\n if (start === pos) {\n return result;\n }\n if (level !== 0) {\n return result;\n }\n result.str = unescapeAll(str.slice(start, pos));\n result.pos = pos;\n result.ok = true;\n return result;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/helpers/parse_link_title.mjs\nfunction parseLinkTitle(str, start, max, prev_state) {\n let code2;\n let pos = start;\n const state = {\n // if `true`, this is a valid link title\n ok: false,\n // if `true`, this link can be continued on the next line\n can_continue: false,\n // if `ok`, it's the position of the first character after the closing marker\n pos: 0,\n // if `ok`, it's the unescaped title\n str: \"\",\n // expected closing marker character code\n marker: 0\n };\n if (prev_state) {\n state.str = prev_state.str;\n state.marker = prev_state.marker;\n } else {\n if (pos >= max) {\n return state;\n }\n let marker = str.charCodeAt(pos);\n if (marker !== 34 && marker !== 39 && marker !== 40) {\n return state;\n }\n start++;\n pos++;\n if (marker === 40) {\n marker = 41;\n }\n state.marker = marker;\n }\n while (pos < max) {\n code2 = str.charCodeAt(pos);\n if (code2 === state.marker) {\n state.pos = pos + 1;\n state.str += unescapeAll(str.slice(start, pos));\n state.ok = true;\n return state;\n } else if (code2 === 40 && state.marker === 41) {\n return state;\n } else if (code2 === 92 && pos + 1 < max) {\n pos++;\n }\n pos++;\n }\n state.can_continue = true;\n state.str += unescapeAll(str.slice(start, pos));\n return state;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/renderer.mjs\nvar default_rules = {};\ndefault_rules.code_inline = function(tokens2, idx, options, env, slf) {\n const token = tokens2[idx];\n return \"\" + escapeHtml(token.content) + \"\";\n};\ndefault_rules.code_block = function(tokens2, idx, options, env, slf) {\n const token = tokens2[idx];\n return \"\" + escapeHtml(tokens2[idx].content) + \"\\n\";\n};\ndefault_rules.fence = function(tokens2, idx, options, env, slf) {\n const token = tokens2[idx];\n const info = token.info ? unescapeAll(token.info).trim() : \"\";\n let langName = \"\";\n let langAttrs = \"\";\n if (info) {\n const arr = info.split(/(\\s+)/g);\n langName = arr[0];\n langAttrs = arr.slice(2).join(\"\");\n }\n let highlighted;\n if (options.highlight) {\n highlighted = options.highlight(token.content, langName, langAttrs) || escapeHtml(token.content);\n } else {\n highlighted = escapeHtml(token.content);\n }\n if (highlighted.indexOf(\"${highlighted}\n`;\n }\n return `
${highlighted}
\n`;\n};\ndefault_rules.image = function(tokens2, idx, options, env, slf) {\n const token = tokens2[idx];\n token.attrs[token.attrIndex(\"alt\")][1] = slf.renderInlineAsText(token.children, options, env);\n return slf.renderToken(tokens2, idx, options);\n};\ndefault_rules.hardbreak = function(tokens2, idx, options) {\n return options.xhtmlOut ? \"
\\n\" : \"
\\n\";\n};\ndefault_rules.softbreak = function(tokens2, idx, options) {\n return options.breaks ? options.xhtmlOut ? \"
\\n\" : \"
\\n\" : \"\\n\";\n};\ndefault_rules.text = function(tokens2, idx) {\n return escapeHtml(tokens2[idx].content);\n};\ndefault_rules.html_block = function(tokens2, idx) {\n return tokens2[idx].content;\n};\ndefault_rules.html_inline = function(tokens2, idx) {\n return tokens2[idx].content;\n};\nfunction Renderer() {\n this.rules = assign({}, default_rules);\n}\nRenderer.prototype.renderAttrs = function renderAttrs(token) {\n let i, l, result;\n if (!token.attrs) {\n return \"\";\n }\n result = \"\";\n for (i = 0, l = token.attrs.length; i < l; i++) {\n result += \" \" + escapeHtml(token.attrs[i][0]) + '=\"' + escapeHtml(token.attrs[i][1]) + '\"';\n }\n return result;\n};\nRenderer.prototype.renderToken = function renderToken(tokens2, idx, options) {\n const token = tokens2[idx];\n let result = \"\";\n if (token.hidden) {\n return \"\";\n }\n if (token.block && token.nesting !== -1 && idx && tokens2[idx - 1].hidden) {\n result += \"\\n\";\n }\n result += (token.nesting === -1 ? \"\\n\" : \">\";\n return result;\n};\nRenderer.prototype.renderInline = function(tokens2, options, env) {\n let result = \"\";\n const rules = this.rules;\n for (let i = 0, len = tokens2.length; i < len; i++) {\n const type = tokens2[i].type;\n if (typeof rules[type] !== \"undefined\") {\n result += rules[type](tokens2, i, options, env, this);\n } else {\n result += this.renderToken(tokens2, i, options);\n }\n }\n return result;\n};\nRenderer.prototype.renderInlineAsText = function(tokens2, options, env) {\n let result = \"\";\n for (let i = 0, len = tokens2.length; i < len; i++) {\n switch (tokens2[i].type) {\n case \"text\":\n result += tokens2[i].content;\n break;\n case \"image\":\n result += this.renderInlineAsText(tokens2[i].children, options, env);\n break;\n case \"html_inline\":\n case \"html_block\":\n result += tokens2[i].content;\n break;\n case \"softbreak\":\n case \"hardbreak\":\n result += \"\\n\";\n break;\n default:\n }\n }\n return result;\n};\nRenderer.prototype.render = function(tokens2, options, env) {\n let result = \"\";\n const rules = this.rules;\n for (let i = 0, len = tokens2.length; i < len; i++) {\n const type = tokens2[i].type;\n if (type === \"inline\") {\n result += this.renderInline(tokens2[i].children, options, env);\n } else if (typeof rules[type] !== \"undefined\") {\n result += rules[type](tokens2, i, options, env, this);\n } else {\n result += this.renderToken(tokens2, i, options, env);\n }\n }\n return result;\n};\nvar renderer_default = Renderer;\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/ruler.mjs\nfunction Ruler() {\n this.__rules__ = [];\n this.__cache__ = null;\n}\nRuler.prototype.__find__ = function(name) {\n for (let i = 0; i < this.__rules__.length; i++) {\n if (this.__rules__[i].name === name) {\n return i;\n }\n }\n return -1;\n};\nRuler.prototype.__compile__ = function() {\n const self = this;\n const chains = [\"\"];\n self.__rules__.forEach(function(rule) {\n if (!rule.enabled) {\n return;\n }\n rule.alt.forEach(function(altName) {\n if (chains.indexOf(altName) < 0) {\n chains.push(altName);\n }\n });\n });\n self.__cache__ = {};\n chains.forEach(function(chain) {\n self.__cache__[chain] = [];\n self.__rules__.forEach(function(rule) {\n if (!rule.enabled) {\n return;\n }\n if (chain && rule.alt.indexOf(chain) < 0) {\n return;\n }\n self.__cache__[chain].push(rule.fn);\n });\n });\n};\nRuler.prototype.at = function(name, fn, options) {\n const index = this.__find__(name);\n const opt = options || {};\n if (index === -1) {\n throw new Error(\"Parser rule not found: \" + name);\n }\n this.__rules__[index].fn = fn;\n this.__rules__[index].alt = opt.alt || [];\n this.__cache__ = null;\n};\nRuler.prototype.before = function(beforeName, ruleName, fn, options) {\n const index = this.__find__(beforeName);\n const opt = options || {};\n if (index === -1) {\n throw new Error(\"Parser rule not found: \" + beforeName);\n }\n this.__rules__.splice(index, 0, {\n name: ruleName,\n enabled: true,\n fn,\n alt: opt.alt || []\n });\n this.__cache__ = null;\n};\nRuler.prototype.after = function(afterName, ruleName, fn, options) {\n const index = this.__find__(afterName);\n const opt = options || {};\n if (index === -1) {\n throw new Error(\"Parser rule not found: \" + afterName);\n }\n this.__rules__.splice(index + 1, 0, {\n name: ruleName,\n enabled: true,\n fn,\n alt: opt.alt || []\n });\n this.__cache__ = null;\n};\nRuler.prototype.push = function(ruleName, fn, options) {\n const opt = options || {};\n this.__rules__.push({\n name: ruleName,\n enabled: true,\n fn,\n alt: opt.alt || []\n });\n this.__cache__ = null;\n};\nRuler.prototype.enable = function(list2, ignoreInvalid) {\n if (!Array.isArray(list2)) {\n list2 = [list2];\n }\n const result = [];\n list2.forEach(function(name) {\n const idx = this.__find__(name);\n if (idx < 0) {\n if (ignoreInvalid) {\n return;\n }\n throw new Error(\"Rules manager: invalid rule name \" + name);\n }\n this.__rules__[idx].enabled = true;\n result.push(name);\n }, this);\n this.__cache__ = null;\n return result;\n};\nRuler.prototype.enableOnly = function(list2, ignoreInvalid) {\n if (!Array.isArray(list2)) {\n list2 = [list2];\n }\n this.__rules__.forEach(function(rule) {\n rule.enabled = false;\n });\n this.enable(list2, ignoreInvalid);\n};\nRuler.prototype.disable = function(list2, ignoreInvalid) {\n if (!Array.isArray(list2)) {\n list2 = [list2];\n }\n const result = [];\n list2.forEach(function(name) {\n const idx = this.__find__(name);\n if (idx < 0) {\n if (ignoreInvalid) {\n return;\n }\n throw new Error(\"Rules manager: invalid rule name \" + name);\n }\n this.__rules__[idx].enabled = false;\n result.push(name);\n }, this);\n this.__cache__ = null;\n return result;\n};\nRuler.prototype.getRules = function(chainName) {\n if (this.__cache__ === null) {\n this.__compile__();\n }\n return this.__cache__[chainName] || [];\n};\nvar ruler_default = Ruler;\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/token.mjs\nfunction Token(type, tag, nesting) {\n this.type = type;\n this.tag = tag;\n this.attrs = null;\n this.map = null;\n this.nesting = nesting;\n this.level = 0;\n this.children = null;\n this.content = \"\";\n this.markup = \"\";\n this.info = \"\";\n this.meta = null;\n this.block = false;\n this.hidden = false;\n}\nToken.prototype.attrIndex = function attrIndex(name) {\n if (!this.attrs) {\n return -1;\n }\n const attrs = this.attrs;\n for (let i = 0, len = attrs.length; i < len; i++) {\n if (attrs[i][0] === name) {\n return i;\n }\n }\n return -1;\n};\nToken.prototype.attrPush = function attrPush(attrData) {\n if (this.attrs) {\n this.attrs.push(attrData);\n } else {\n this.attrs = [attrData];\n }\n};\nToken.prototype.attrSet = function attrSet(name, value) {\n const idx = this.attrIndex(name);\n const attrData = [name, value];\n if (idx < 0) {\n this.attrPush(attrData);\n } else {\n this.attrs[idx] = attrData;\n }\n};\nToken.prototype.attrGet = function attrGet(name) {\n const idx = this.attrIndex(name);\n let value = null;\n if (idx >= 0) {\n value = this.attrs[idx][1];\n }\n return value;\n};\nToken.prototype.attrJoin = function attrJoin(name, value) {\n const idx = this.attrIndex(name);\n if (idx < 0) {\n this.attrPush([name, value]);\n } else {\n this.attrs[idx][1] = this.attrs[idx][1] + \" \" + value;\n }\n};\nvar token_default = Token;\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_core/state_core.mjs\nfunction StateCore(src, md2, env) {\n this.src = src;\n this.env = env;\n this.tokens = [];\n this.inlineMode = false;\n this.md = md2;\n}\nStateCore.prototype.Token = token_default;\nvar state_core_default = StateCore;\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_core/normalize.mjs\nvar NEWLINES_RE = /\\r\\n?|\\n/g;\nvar NULL_RE = /\\0/g;\nfunction normalize(state) {\n let str;\n str = state.src.replace(NEWLINES_RE, \"\\n\");\n str = str.replace(NULL_RE, \"�\");\n state.src = str;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_core/block.mjs\nfunction block(state) {\n let token;\n if (state.inlineMode) {\n token = new state.Token(\"inline\", \"\", 0);\n token.content = state.src;\n token.map = [0, 1];\n token.children = [];\n state.tokens.push(token);\n } else {\n state.md.block.parse(state.src, state.md, state.env, state.tokens);\n }\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_core/inline.mjs\nfunction inline(state) {\n const tokens2 = state.tokens;\n for (let i = 0, l = tokens2.length; i < l; i++) {\n const tok = tokens2[i];\n if (tok.type === \"inline\") {\n state.md.inline.parse(tok.content, state.md, state.env, tok.children);\n }\n }\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_core/linkify.mjs\nfunction isLinkOpen(str) {\n return /^\\s]/i.test(str);\n}\nfunction isLinkClose(str) {\n return /^<\\/a\\s*>/i.test(str);\n}\nfunction linkify(state) {\n const blockTokens = state.tokens;\n if (!state.md.options.linkify) {\n return;\n }\n for (let j = 0, l = blockTokens.length; j < l; j++) {\n if (blockTokens[j].type !== \"inline\" || !state.md.linkify.pretest(blockTokens[j].content)) {\n continue;\n }\n let tokens2 = blockTokens[j].children;\n let htmlLinkLevel = 0;\n for (let i = tokens2.length - 1; i >= 0; i--) {\n const currentToken = tokens2[i];\n if (currentToken.type === \"link_close\") {\n i--;\n while (tokens2[i].level !== currentToken.level && tokens2[i].type !== \"link_open\") {\n i--;\n }\n continue;\n }\n if (currentToken.type === \"html_inline\") {\n if (isLinkOpen(currentToken.content) && htmlLinkLevel > 0) {\n htmlLinkLevel--;\n }\n if (isLinkClose(currentToken.content)) {\n htmlLinkLevel++;\n }\n }\n if (htmlLinkLevel > 0) {\n continue;\n }\n if (currentToken.type === \"text\" && state.md.linkify.test(currentToken.content)) {\n const text2 = currentToken.content;\n let links2 = state.md.linkify.match(text2);\n const nodes = [];\n let level = currentToken.level;\n let lastPos = 0;\n if (links2.length > 0 && links2[0].index === 0 && i > 0 && tokens2[i - 1].type === \"text_special\") {\n links2 = links2.slice(1);\n }\n for (let ln = 0; ln < links2.length; ln++) {\n const url = links2[ln].url;\n const fullUrl = state.md.normalizeLink(url);\n if (!state.md.validateLink(fullUrl)) {\n continue;\n }\n let urlText = links2[ln].text;\n if (!links2[ln].schema) {\n urlText = state.md.normalizeLinkText(\"http://\" + urlText).replace(/^http:\\/\\//, \"\");\n } else if (links2[ln].schema === \"mailto:\" && !/^mailto:/i.test(urlText)) {\n urlText = state.md.normalizeLinkText(\"mailto:\" + urlText).replace(/^mailto:/, \"\");\n } else {\n urlText = state.md.normalizeLinkText(urlText);\n }\n const pos = links2[ln].index;\n if (pos > lastPos) {\n const token = new state.Token(\"text\", \"\", 0);\n token.content = text2.slice(lastPos, pos);\n token.level = level;\n nodes.push(token);\n }\n const token_o = new state.Token(\"link_open\", \"a\", 1);\n token_o.attrs = [[\"href\", fullUrl]];\n token_o.level = level++;\n token_o.markup = \"linkify\";\n token_o.info = \"auto\";\n nodes.push(token_o);\n const token_t = new state.Token(\"text\", \"\", 0);\n token_t.content = urlText;\n token_t.level = level;\n nodes.push(token_t);\n const token_c = new state.Token(\"link_close\", \"a\", -1);\n token_c.level = --level;\n token_c.markup = \"linkify\";\n token_c.info = \"auto\";\n nodes.push(token_c);\n lastPos = links2[ln].lastIndex;\n }\n if (lastPos < text2.length) {\n const token = new state.Token(\"text\", \"\", 0);\n token.content = text2.slice(lastPos);\n token.level = level;\n nodes.push(token);\n }\n blockTokens[j].children = tokens2 = arrayReplaceAt(tokens2, i, nodes);\n }\n }\n }\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_core/replacements.mjs\nvar RARE_RE = /\\+-|\\.\\.|\\?\\?\\?\\?|!!!!|,,|--/;\nvar SCOPED_ABBR_TEST_RE = /\\((c|tm|r)\\)/i;\nvar SCOPED_ABBR_RE = /\\((c|tm|r)\\)/ig;\nvar SCOPED_ABBR = {\n c: \"©\",\n r: \"®\",\n tm: \"™\"\n};\nfunction replaceFn(match2, name) {\n return SCOPED_ABBR[name.toLowerCase()];\n}\nfunction replace_scoped(inlineTokens) {\n let inside_autolink = 0;\n for (let i = inlineTokens.length - 1; i >= 0; i--) {\n const token = inlineTokens[i];\n if (token.type === \"text\" && !inside_autolink) {\n token.content = token.content.replace(SCOPED_ABBR_RE, replaceFn);\n }\n if (token.type === \"link_open\" && token.info === \"auto\") {\n inside_autolink--;\n }\n if (token.type === \"link_close\" && token.info === \"auto\") {\n inside_autolink++;\n }\n }\n}\nfunction replace_rare(inlineTokens) {\n let inside_autolink = 0;\n for (let i = inlineTokens.length - 1; i >= 0; i--) {\n const token = inlineTokens[i];\n if (token.type === \"text\" && !inside_autolink) {\n if (RARE_RE.test(token.content)) {\n token.content = token.content.replace(/\\+-/g, \"±\").replace(/\\.{2,}/g, \"…\").replace(/([?!])…/g, \"$1..\").replace(/([?!]){4,}/g, \"$1$1$1\").replace(/,{2,}/g, \",\").replace(/(^|[^-])---(?=[^-]|$)/mg, \"$1—\").replace(/(^|\\s)--(?=\\s|$)/mg, \"$1–\").replace(/(^|[^-\\s])--(?=[^-\\s]|$)/mg, \"$1–\");\n }\n }\n if (token.type === \"link_open\" && token.info === \"auto\") {\n inside_autolink--;\n }\n if (token.type === \"link_close\" && token.info === \"auto\") {\n inside_autolink++;\n }\n }\n}\nfunction replace(state) {\n let blkIdx;\n if (!state.md.options.typographer) {\n return;\n }\n for (blkIdx = state.tokens.length - 1; blkIdx >= 0; blkIdx--) {\n if (state.tokens[blkIdx].type !== \"inline\") {\n continue;\n }\n if (SCOPED_ABBR_TEST_RE.test(state.tokens[blkIdx].content)) {\n replace_scoped(state.tokens[blkIdx].children);\n }\n if (RARE_RE.test(state.tokens[blkIdx].content)) {\n replace_rare(state.tokens[blkIdx].children);\n }\n }\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_core/smartquotes.mjs\nvar QUOTE_TEST_RE = /['\"]/;\nvar QUOTE_RE = /['\"]/g;\nvar APOSTROPHE = \"’\";\nfunction replaceAt(str, index, ch) {\n return str.slice(0, index) + ch + str.slice(index + 1);\n}\nfunction process_inlines(tokens2, state) {\n let j;\n const stack = [];\n for (let i = 0; i < tokens2.length; i++) {\n const token = tokens2[i];\n const thisLevel = tokens2[i].level;\n for (j = stack.length - 1; j >= 0; j--) {\n if (stack[j].level <= thisLevel) {\n break;\n }\n }\n stack.length = j + 1;\n if (token.type !== \"text\") {\n continue;\n }\n let text2 = token.content;\n let pos = 0;\n let max = text2.length;\n OUTER:\n while (pos < max) {\n QUOTE_RE.lastIndex = pos;\n const t = QUOTE_RE.exec(text2);\n if (!t) {\n break;\n }\n let canOpen = true;\n let canClose = true;\n pos = t.index + 1;\n const isSingle = t[0] === \"'\";\n let lastChar = 32;\n if (t.index - 1 >= 0) {\n lastChar = text2.charCodeAt(t.index - 1);\n } else {\n for (j = i - 1; j >= 0; j--) {\n if (tokens2[j].type === \"softbreak\" || tokens2[j].type === \"hardbreak\") break;\n if (!tokens2[j].content) continue;\n lastChar = tokens2[j].content.charCodeAt(tokens2[j].content.length - 1);\n break;\n }\n }\n let nextChar = 32;\n if (pos < max) {\n nextChar = text2.charCodeAt(pos);\n } else {\n for (j = i + 1; j < tokens2.length; j++) {\n if (tokens2[j].type === \"softbreak\" || tokens2[j].type === \"hardbreak\") break;\n if (!tokens2[j].content) continue;\n nextChar = tokens2[j].content.charCodeAt(0);\n break;\n }\n }\n const isLastPunctChar = isMdAsciiPunct(lastChar) || isPunctChar(String.fromCharCode(lastChar));\n const isNextPunctChar = isMdAsciiPunct(nextChar) || isPunctChar(String.fromCharCode(nextChar));\n const isLastWhiteSpace = isWhiteSpace(lastChar);\n const isNextWhiteSpace = isWhiteSpace(nextChar);\n if (isNextWhiteSpace) {\n canOpen = false;\n } else if (isNextPunctChar) {\n if (!(isLastWhiteSpace || isLastPunctChar)) {\n canOpen = false;\n }\n }\n if (isLastWhiteSpace) {\n canClose = false;\n } else if (isLastPunctChar) {\n if (!(isNextWhiteSpace || isNextPunctChar)) {\n canClose = false;\n }\n }\n if (nextChar === 34 && t[0] === '\"') {\n if (lastChar >= 48 && lastChar <= 57) {\n canClose = canOpen = false;\n }\n }\n if (canOpen && canClose) {\n canOpen = isLastPunctChar;\n canClose = isNextPunctChar;\n }\n if (!canOpen && !canClose) {\n if (isSingle) {\n token.content = replaceAt(token.content, t.index, APOSTROPHE);\n }\n continue;\n }\n if (canClose) {\n for (j = stack.length - 1; j >= 0; j--) {\n let item = stack[j];\n if (stack[j].level < thisLevel) {\n break;\n }\n if (item.single === isSingle && stack[j].level === thisLevel) {\n item = stack[j];\n let openQuote;\n let closeQuote;\n if (isSingle) {\n openQuote = state.md.options.quotes[2];\n closeQuote = state.md.options.quotes[3];\n } else {\n openQuote = state.md.options.quotes[0];\n closeQuote = state.md.options.quotes[1];\n }\n token.content = replaceAt(token.content, t.index, closeQuote);\n tokens2[item.token].content = replaceAt(\n tokens2[item.token].content,\n item.pos,\n openQuote\n );\n pos += closeQuote.length - 1;\n if (item.token === i) {\n pos += openQuote.length - 1;\n }\n text2 = token.content;\n max = text2.length;\n stack.length = j;\n continue OUTER;\n }\n }\n }\n if (canOpen) {\n stack.push({\n token: i,\n pos: t.index,\n single: isSingle,\n level: thisLevel\n });\n } else if (canClose && isSingle) {\n token.content = replaceAt(token.content, t.index, APOSTROPHE);\n }\n }\n }\n}\nfunction smartquotes(state) {\n if (!state.md.options.typographer) {\n return;\n }\n for (let blkIdx = state.tokens.length - 1; blkIdx >= 0; blkIdx--) {\n if (state.tokens[blkIdx].type !== \"inline\" || !QUOTE_TEST_RE.test(state.tokens[blkIdx].content)) {\n continue;\n }\n process_inlines(state.tokens[blkIdx].children, state);\n }\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_core/text_join.mjs\nfunction text_join(state) {\n let curr, last;\n const blockTokens = state.tokens;\n const l = blockTokens.length;\n for (let j = 0; j < l; j++) {\n if (blockTokens[j].type !== \"inline\") continue;\n const tokens2 = blockTokens[j].children;\n const max = tokens2.length;\n for (curr = 0; curr < max; curr++) {\n if (tokens2[curr].type === \"text_special\") {\n tokens2[curr].type = \"text\";\n }\n }\n for (curr = last = 0; curr < max; curr++) {\n if (tokens2[curr].type === \"text\" && curr + 1 < max && tokens2[curr + 1].type === \"text\") {\n tokens2[curr + 1].content = tokens2[curr].content + tokens2[curr + 1].content;\n } else {\n if (curr !== last) {\n tokens2[last] = tokens2[curr];\n }\n last++;\n }\n }\n if (curr !== last) {\n tokens2.length = last;\n }\n }\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/parser_core.mjs\nvar _rules = [\n [\"normalize\", normalize],\n [\"block\", block],\n [\"inline\", inline],\n [\"linkify\", linkify],\n [\"replacements\", replace],\n [\"smartquotes\", smartquotes],\n // `text_join` finds `text_special` tokens (for escape sequences)\n // and joins them with the rest of the text\n [\"text_join\", text_join]\n];\nfunction Core() {\n this.ruler = new ruler_default();\n for (let i = 0; i < _rules.length; i++) {\n this.ruler.push(_rules[i][0], _rules[i][1]);\n }\n}\nCore.prototype.process = function(state) {\n const rules = this.ruler.getRules(\"\");\n for (let i = 0, l = rules.length; i < l; i++) {\n rules[i](state);\n }\n};\nCore.prototype.State = state_core_default;\nvar parser_core_default = Core;\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/state_block.mjs\nfunction StateBlock(src, md2, env, tokens2) {\n this.src = src;\n this.md = md2;\n this.env = env;\n this.tokens = tokens2;\n this.bMarks = [];\n this.eMarks = [];\n this.tShift = [];\n this.sCount = [];\n this.bsCount = [];\n this.blkIndent = 0;\n this.line = 0;\n this.lineMax = 0;\n this.tight = false;\n this.ddIndent = -1;\n this.listIndent = -1;\n this.parentType = \"root\";\n this.level = 0;\n const s = this.src;\n for (let start = 0, pos = 0, indent = 0, offset = 0, len = s.length, indent_found = false; pos < len; pos++) {\n const ch = s.charCodeAt(pos);\n if (!indent_found) {\n if (isSpace(ch)) {\n indent++;\n if (ch === 9) {\n offset += 4 - offset % 4;\n } else {\n offset++;\n }\n continue;\n } else {\n indent_found = true;\n }\n }\n if (ch === 10 || pos === len - 1) {\n if (ch !== 10) {\n pos++;\n }\n this.bMarks.push(start);\n this.eMarks.push(pos);\n this.tShift.push(indent);\n this.sCount.push(offset);\n this.bsCount.push(0);\n indent_found = false;\n indent = 0;\n offset = 0;\n start = pos + 1;\n }\n }\n this.bMarks.push(s.length);\n this.eMarks.push(s.length);\n this.tShift.push(0);\n this.sCount.push(0);\n this.bsCount.push(0);\n this.lineMax = this.bMarks.length - 1;\n}\nStateBlock.prototype.push = function(type, tag, nesting) {\n const token = new token_default(type, tag, nesting);\n token.block = true;\n if (nesting < 0) this.level--;\n token.level = this.level;\n if (nesting > 0) this.level++;\n this.tokens.push(token);\n return token;\n};\nStateBlock.prototype.isEmpty = function isEmpty(line) {\n return this.bMarks[line] + this.tShift[line] >= this.eMarks[line];\n};\nStateBlock.prototype.skipEmptyLines = function skipEmptyLines(from) {\n for (let max = this.lineMax; from < max; from++) {\n if (this.bMarks[from] + this.tShift[from] < this.eMarks[from]) {\n break;\n }\n }\n return from;\n};\nStateBlock.prototype.skipSpaces = function skipSpaces(pos) {\n for (let max = this.src.length; pos < max; pos++) {\n const ch = this.src.charCodeAt(pos);\n if (!isSpace(ch)) {\n break;\n }\n }\n return pos;\n};\nStateBlock.prototype.skipSpacesBack = function skipSpacesBack(pos, min) {\n if (pos <= min) {\n return pos;\n }\n while (pos > min) {\n if (!isSpace(this.src.charCodeAt(--pos))) {\n return pos + 1;\n }\n }\n return pos;\n};\nStateBlock.prototype.skipChars = function skipChars(pos, code2) {\n for (let max = this.src.length; pos < max; pos++) {\n if (this.src.charCodeAt(pos) !== code2) {\n break;\n }\n }\n return pos;\n};\nStateBlock.prototype.skipCharsBack = function skipCharsBack(pos, code2, min) {\n if (pos <= min) {\n return pos;\n }\n while (pos > min) {\n if (code2 !== this.src.charCodeAt(--pos)) {\n return pos + 1;\n }\n }\n return pos;\n};\nStateBlock.prototype.getLines = function getLines(begin, end, indent, keepLastLF) {\n if (begin >= end) {\n return \"\";\n }\n const queue = new Array(end - begin);\n for (let i = 0, line = begin; line < end; line++, i++) {\n let lineIndent = 0;\n const lineStart = this.bMarks[line];\n let first = lineStart;\n let last;\n if (line + 1 < end || keepLastLF) {\n last = this.eMarks[line] + 1;\n } else {\n last = this.eMarks[line];\n }\n while (first < last && lineIndent < indent) {\n const ch = this.src.charCodeAt(first);\n if (isSpace(ch)) {\n if (ch === 9) {\n lineIndent += 4 - (lineIndent + this.bsCount[line]) % 4;\n } else {\n lineIndent++;\n }\n } else if (first - lineStart < this.tShift[line]) {\n lineIndent++;\n } else {\n break;\n }\n first++;\n }\n if (lineIndent > indent) {\n queue[i] = new Array(lineIndent - indent + 1).join(\" \") + this.src.slice(first, last);\n } else {\n queue[i] = this.src.slice(first, last);\n }\n }\n return queue.join(\"\");\n};\nStateBlock.prototype.Token = token_default;\nvar state_block_default = StateBlock;\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/table.mjs\nvar MAX_AUTOCOMPLETED_CELLS = 65536;\nfunction getLine(state, line) {\n const pos = state.bMarks[line] + state.tShift[line];\n const max = state.eMarks[line];\n return state.src.slice(pos, max);\n}\nfunction escapedSplit(str) {\n const result = [];\n const max = str.length;\n let pos = 0;\n let ch = str.charCodeAt(pos);\n let isEscaped = false;\n let lastPos = 0;\n let current = \"\";\n while (pos < max) {\n if (ch === 124) {\n if (!isEscaped) {\n result.push(current + str.substring(lastPos, pos));\n current = \"\";\n lastPos = pos + 1;\n } else {\n current += str.substring(lastPos, pos - 1);\n lastPos = pos;\n }\n }\n isEscaped = ch === 92;\n pos++;\n ch = str.charCodeAt(pos);\n }\n result.push(current + str.substring(lastPos));\n return result;\n}\nfunction table(state, startLine, endLine, silent) {\n if (startLine + 2 > endLine) {\n return false;\n }\n let nextLine = startLine + 1;\n if (state.sCount[nextLine] < state.blkIndent) {\n return false;\n }\n if (state.sCount[nextLine] - state.blkIndent >= 4) {\n return false;\n }\n let pos = state.bMarks[nextLine] + state.tShift[nextLine];\n if (pos >= state.eMarks[nextLine]) {\n return false;\n }\n const firstCh = state.src.charCodeAt(pos++);\n if (firstCh !== 124 && firstCh !== 45 && firstCh !== 58) {\n return false;\n }\n if (pos >= state.eMarks[nextLine]) {\n return false;\n }\n const secondCh = state.src.charCodeAt(pos++);\n if (secondCh !== 124 && secondCh !== 45 && secondCh !== 58 && !isSpace(secondCh)) {\n return false;\n }\n if (firstCh === 45 && isSpace(secondCh)) {\n return false;\n }\n while (pos < state.eMarks[nextLine]) {\n const ch = state.src.charCodeAt(pos);\n if (ch !== 124 && ch !== 45 && ch !== 58 && !isSpace(ch)) {\n return false;\n }\n pos++;\n }\n let lineText = getLine(state, startLine + 1);\n let columns = lineText.split(\"|\");\n const aligns = [];\n for (let i = 0; i < columns.length; i++) {\n const t = columns[i].trim();\n if (!t) {\n if (i === 0 || i === columns.length - 1) {\n continue;\n } else {\n return false;\n }\n }\n if (!/^:?-+:?$/.test(t)) {\n return false;\n }\n if (t.charCodeAt(t.length - 1) === 58) {\n aligns.push(t.charCodeAt(0) === 58 ? \"center\" : \"right\");\n } else if (t.charCodeAt(0) === 58) {\n aligns.push(\"left\");\n } else {\n aligns.push(\"\");\n }\n }\n lineText = getLine(state, startLine).trim();\n if (lineText.indexOf(\"|\") === -1) {\n return false;\n }\n if (state.sCount[startLine] - state.blkIndent >= 4) {\n return false;\n }\n columns = escapedSplit(lineText);\n if (columns.length && columns[0] === \"\") columns.shift();\n if (columns.length && columns[columns.length - 1] === \"\") columns.pop();\n const columnCount = columns.length;\n if (columnCount === 0 || columnCount !== aligns.length) {\n return false;\n }\n if (silent) {\n return true;\n }\n const oldParentType = state.parentType;\n state.parentType = \"table\";\n const terminatorRules = state.md.block.ruler.getRules(\"blockquote\");\n const token_to = state.push(\"table_open\", \"table\", 1);\n const tableLines = [startLine, 0];\n token_to.map = tableLines;\n const token_tho = state.push(\"thead_open\", \"thead\", 1);\n token_tho.map = [startLine, startLine + 1];\n const token_htro = state.push(\"tr_open\", \"tr\", 1);\n token_htro.map = [startLine, startLine + 1];\n for (let i = 0; i < columns.length; i++) {\n const token_ho = state.push(\"th_open\", \"th\", 1);\n if (aligns[i]) {\n token_ho.attrs = [[\"style\", \"text-align:\" + aligns[i]]];\n }\n const token_il = state.push(\"inline\", \"\", 0);\n token_il.content = columns[i].trim();\n token_il.children = [];\n state.push(\"th_close\", \"th\", -1);\n }\n state.push(\"tr_close\", \"tr\", -1);\n state.push(\"thead_close\", \"thead\", -1);\n let tbodyLines;\n let autocompletedCells = 0;\n for (nextLine = startLine + 2; nextLine < endLine; nextLine++) {\n if (state.sCount[nextLine] < state.blkIndent) {\n break;\n }\n let terminate = false;\n for (let i = 0, l = terminatorRules.length; i < l; i++) {\n if (terminatorRules[i](state, nextLine, endLine, true)) {\n terminate = true;\n break;\n }\n }\n if (terminate) {\n break;\n }\n lineText = getLine(state, nextLine).trim();\n if (!lineText) {\n break;\n }\n if (state.sCount[nextLine] - state.blkIndent >= 4) {\n break;\n }\n columns = escapedSplit(lineText);\n if (columns.length && columns[0] === \"\") columns.shift();\n if (columns.length && columns[columns.length - 1] === \"\") columns.pop();\n autocompletedCells += columnCount - columns.length;\n if (autocompletedCells > MAX_AUTOCOMPLETED_CELLS) {\n break;\n }\n if (nextLine === startLine + 2) {\n const token_tbo = state.push(\"tbody_open\", \"tbody\", 1);\n token_tbo.map = tbodyLines = [startLine + 2, 0];\n }\n const token_tro = state.push(\"tr_open\", \"tr\", 1);\n token_tro.map = [nextLine, nextLine + 1];\n for (let i = 0; i < columnCount; i++) {\n const token_tdo = state.push(\"td_open\", \"td\", 1);\n if (aligns[i]) {\n token_tdo.attrs = [[\"style\", \"text-align:\" + aligns[i]]];\n }\n const token_il = state.push(\"inline\", \"\", 0);\n token_il.content = columns[i] ? columns[i].trim() : \"\";\n token_il.children = [];\n state.push(\"td_close\", \"td\", -1);\n }\n state.push(\"tr_close\", \"tr\", -1);\n }\n if (tbodyLines) {\n state.push(\"tbody_close\", \"tbody\", -1);\n tbodyLines[1] = nextLine;\n }\n state.push(\"table_close\", \"table\", -1);\n tableLines[1] = nextLine;\n state.parentType = oldParentType;\n state.line = nextLine;\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/code.mjs\nfunction code(state, startLine, endLine) {\n if (state.sCount[startLine] - state.blkIndent < 4) {\n return false;\n }\n let nextLine = startLine + 1;\n let last = nextLine;\n while (nextLine < endLine) {\n if (state.isEmpty(nextLine)) {\n nextLine++;\n continue;\n }\n if (state.sCount[nextLine] - state.blkIndent >= 4) {\n nextLine++;\n last = nextLine;\n continue;\n }\n break;\n }\n state.line = last;\n const token = state.push(\"code_block\", \"code\", 0);\n token.content = state.getLines(startLine, last, 4 + state.blkIndent, false) + \"\\n\";\n token.map = [startLine, state.line];\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/fence.mjs\nfunction fence(state, startLine, endLine, silent) {\n let pos = state.bMarks[startLine] + state.tShift[startLine];\n let max = state.eMarks[startLine];\n if (state.sCount[startLine] - state.blkIndent >= 4) {\n return false;\n }\n if (pos + 3 > max) {\n return false;\n }\n const marker = state.src.charCodeAt(pos);\n if (marker !== 126 && marker !== 96) {\n return false;\n }\n let mem = pos;\n pos = state.skipChars(pos, marker);\n let len = pos - mem;\n if (len < 3) {\n return false;\n }\n const markup = state.src.slice(mem, pos);\n const params = state.src.slice(pos, max);\n if (marker === 96) {\n if (params.indexOf(String.fromCharCode(marker)) >= 0) {\n return false;\n }\n }\n if (silent) {\n return true;\n }\n let nextLine = startLine;\n let haveEndMarker = false;\n for (; ; ) {\n nextLine++;\n if (nextLine >= endLine) {\n break;\n }\n pos = mem = state.bMarks[nextLine] + state.tShift[nextLine];\n max = state.eMarks[nextLine];\n if (pos < max && state.sCount[nextLine] < state.blkIndent) {\n break;\n }\n if (state.src.charCodeAt(pos) !== marker) {\n continue;\n }\n if (state.sCount[nextLine] - state.blkIndent >= 4) {\n continue;\n }\n pos = state.skipChars(pos, marker);\n if (pos - mem < len) {\n continue;\n }\n pos = state.skipSpaces(pos);\n if (pos < max) {\n continue;\n }\n haveEndMarker = true;\n break;\n }\n len = state.sCount[startLine];\n state.line = nextLine + (haveEndMarker ? 1 : 0);\n const token = state.push(\"fence\", \"code\", 0);\n token.info = params;\n token.content = state.getLines(startLine + 1, nextLine, len, true);\n token.markup = markup;\n token.map = [startLine, state.line];\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/blockquote.mjs\nfunction blockquote(state, startLine, endLine, silent) {\n let pos = state.bMarks[startLine] + state.tShift[startLine];\n let max = state.eMarks[startLine];\n const oldLineMax = state.lineMax;\n if (state.sCount[startLine] - state.blkIndent >= 4) {\n return false;\n }\n if (state.src.charCodeAt(pos) !== 62) {\n return false;\n }\n if (silent) {\n return true;\n }\n const oldBMarks = [];\n const oldBSCount = [];\n const oldSCount = [];\n const oldTShift = [];\n const terminatorRules = state.md.block.ruler.getRules(\"blockquote\");\n const oldParentType = state.parentType;\n state.parentType = \"blockquote\";\n let lastLineEmpty = false;\n let nextLine;\n for (nextLine = startLine; nextLine < endLine; nextLine++) {\n const isOutdented = state.sCount[nextLine] < state.blkIndent;\n pos = state.bMarks[nextLine] + state.tShift[nextLine];\n max = state.eMarks[nextLine];\n if (pos >= max) {\n break;\n }\n if (state.src.charCodeAt(pos++) === 62 && !isOutdented) {\n let initial = state.sCount[nextLine] + 1;\n let spaceAfterMarker;\n let adjustTab;\n if (state.src.charCodeAt(pos) === 32) {\n pos++;\n initial++;\n adjustTab = false;\n spaceAfterMarker = true;\n } else if (state.src.charCodeAt(pos) === 9) {\n spaceAfterMarker = true;\n if ((state.bsCount[nextLine] + initial) % 4 === 3) {\n pos++;\n initial++;\n adjustTab = false;\n } else {\n adjustTab = true;\n }\n } else {\n spaceAfterMarker = false;\n }\n let offset = initial;\n oldBMarks.push(state.bMarks[nextLine]);\n state.bMarks[nextLine] = pos;\n while (pos < max) {\n const ch = state.src.charCodeAt(pos);\n if (isSpace(ch)) {\n if (ch === 9) {\n offset += 4 - (offset + state.bsCount[nextLine] + (adjustTab ? 1 : 0)) % 4;\n } else {\n offset++;\n }\n } else {\n break;\n }\n pos++;\n }\n lastLineEmpty = pos >= max;\n oldBSCount.push(state.bsCount[nextLine]);\n state.bsCount[nextLine] = state.sCount[nextLine] + 1 + (spaceAfterMarker ? 1 : 0);\n oldSCount.push(state.sCount[nextLine]);\n state.sCount[nextLine] = offset - initial;\n oldTShift.push(state.tShift[nextLine]);\n state.tShift[nextLine] = pos - state.bMarks[nextLine];\n continue;\n }\n if (lastLineEmpty) {\n break;\n }\n let terminate = false;\n for (let i = 0, l = terminatorRules.length; i < l; i++) {\n if (terminatorRules[i](state, nextLine, endLine, true)) {\n terminate = true;\n break;\n }\n }\n if (terminate) {\n state.lineMax = nextLine;\n if (state.blkIndent !== 0) {\n oldBMarks.push(state.bMarks[nextLine]);\n oldBSCount.push(state.bsCount[nextLine]);\n oldTShift.push(state.tShift[nextLine]);\n oldSCount.push(state.sCount[nextLine]);\n state.sCount[nextLine] -= state.blkIndent;\n }\n break;\n }\n oldBMarks.push(state.bMarks[nextLine]);\n oldBSCount.push(state.bsCount[nextLine]);\n oldTShift.push(state.tShift[nextLine]);\n oldSCount.push(state.sCount[nextLine]);\n state.sCount[nextLine] = -1;\n }\n const oldIndent = state.blkIndent;\n state.blkIndent = 0;\n const token_o = state.push(\"blockquote_open\", \"blockquote\", 1);\n token_o.markup = \">\";\n const lines = [startLine, 0];\n token_o.map = lines;\n state.md.block.tokenize(state, startLine, nextLine);\n const token_c = state.push(\"blockquote_close\", \"blockquote\", -1);\n token_c.markup = \">\";\n state.lineMax = oldLineMax;\n state.parentType = oldParentType;\n lines[1] = state.line;\n for (let i = 0; i < oldTShift.length; i++) {\n state.bMarks[i + startLine] = oldBMarks[i];\n state.tShift[i + startLine] = oldTShift[i];\n state.sCount[i + startLine] = oldSCount[i];\n state.bsCount[i + startLine] = oldBSCount[i];\n }\n state.blkIndent = oldIndent;\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/hr.mjs\nfunction hr(state, startLine, endLine, silent) {\n const max = state.eMarks[startLine];\n if (state.sCount[startLine] - state.blkIndent >= 4) {\n return false;\n }\n let pos = state.bMarks[startLine] + state.tShift[startLine];\n const marker = state.src.charCodeAt(pos++);\n if (marker !== 42 && marker !== 45 && marker !== 95) {\n return false;\n }\n let cnt = 1;\n while (pos < max) {\n const ch = state.src.charCodeAt(pos++);\n if (ch !== marker && !isSpace(ch)) {\n return false;\n }\n if (ch === marker) {\n cnt++;\n }\n }\n if (cnt < 3) {\n return false;\n }\n if (silent) {\n return true;\n }\n state.line = startLine + 1;\n const token = state.push(\"hr\", \"hr\", 0);\n token.map = [startLine, state.line];\n token.markup = Array(cnt + 1).join(String.fromCharCode(marker));\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/list.mjs\nfunction skipBulletListMarker(state, startLine) {\n const max = state.eMarks[startLine];\n let pos = state.bMarks[startLine] + state.tShift[startLine];\n const marker = state.src.charCodeAt(pos++);\n if (marker !== 42 && marker !== 45 && marker !== 43) {\n return -1;\n }\n if (pos < max) {\n const ch = state.src.charCodeAt(pos);\n if (!isSpace(ch)) {\n return -1;\n }\n }\n return pos;\n}\nfunction skipOrderedListMarker(state, startLine) {\n const start = state.bMarks[startLine] + state.tShift[startLine];\n const max = state.eMarks[startLine];\n let pos = start;\n if (pos + 1 >= max) {\n return -1;\n }\n let ch = state.src.charCodeAt(pos++);\n if (ch < 48 || ch > 57) {\n return -1;\n }\n for (; ; ) {\n if (pos >= max) {\n return -1;\n }\n ch = state.src.charCodeAt(pos++);\n if (ch >= 48 && ch <= 57) {\n if (pos - start >= 10) {\n return -1;\n }\n continue;\n }\n if (ch === 41 || ch === 46) {\n break;\n }\n return -1;\n }\n if (pos < max) {\n ch = state.src.charCodeAt(pos);\n if (!isSpace(ch)) {\n return -1;\n }\n }\n return pos;\n}\nfunction markTightParagraphs(state, idx) {\n const level = state.level + 2;\n for (let i = idx + 2, l = state.tokens.length - 2; i < l; i++) {\n if (state.tokens[i].level === level && state.tokens[i].type === \"paragraph_open\") {\n state.tokens[i + 2].hidden = true;\n state.tokens[i].hidden = true;\n i += 2;\n }\n }\n}\nfunction list(state, startLine, endLine, silent) {\n let max, pos, start, token;\n let nextLine = startLine;\n let tight = true;\n if (state.sCount[nextLine] - state.blkIndent >= 4) {\n return false;\n }\n if (state.listIndent >= 0 && state.sCount[nextLine] - state.listIndent >= 4 && state.sCount[nextLine] < state.blkIndent) {\n return false;\n }\n let isTerminatingParagraph = false;\n if (silent && state.parentType === \"paragraph\") {\n if (state.sCount[nextLine] >= state.blkIndent) {\n isTerminatingParagraph = true;\n }\n }\n let isOrdered;\n let markerValue;\n let posAfterMarker;\n if ((posAfterMarker = skipOrderedListMarker(state, nextLine)) >= 0) {\n isOrdered = true;\n start = state.bMarks[nextLine] + state.tShift[nextLine];\n markerValue = Number(state.src.slice(start, posAfterMarker - 1));\n if (isTerminatingParagraph && markerValue !== 1) return false;\n } else if ((posAfterMarker = skipBulletListMarker(state, nextLine)) >= 0) {\n isOrdered = false;\n } else {\n return false;\n }\n if (isTerminatingParagraph) {\n if (state.skipSpaces(posAfterMarker) >= state.eMarks[nextLine]) return false;\n }\n if (silent) {\n return true;\n }\n const markerCharCode = state.src.charCodeAt(posAfterMarker - 1);\n const listTokIdx = state.tokens.length;\n if (isOrdered) {\n token = state.push(\"ordered_list_open\", \"ol\", 1);\n if (markerValue !== 1) {\n token.attrs = [[\"start\", markerValue]];\n }\n } else {\n token = state.push(\"bullet_list_open\", \"ul\", 1);\n }\n const listLines = [nextLine, 0];\n token.map = listLines;\n token.markup = String.fromCharCode(markerCharCode);\n let prevEmptyEnd = false;\n const terminatorRules = state.md.block.ruler.getRules(\"list\");\n const oldParentType = state.parentType;\n state.parentType = \"list\";\n while (nextLine < endLine) {\n pos = posAfterMarker;\n max = state.eMarks[nextLine];\n const initial = state.sCount[nextLine] + posAfterMarker - (state.bMarks[nextLine] + state.tShift[nextLine]);\n let offset = initial;\n while (pos < max) {\n const ch = state.src.charCodeAt(pos);\n if (ch === 9) {\n offset += 4 - (offset + state.bsCount[nextLine]) % 4;\n } else if (ch === 32) {\n offset++;\n } else {\n break;\n }\n pos++;\n }\n const contentStart = pos;\n let indentAfterMarker;\n if (contentStart >= max) {\n indentAfterMarker = 1;\n } else {\n indentAfterMarker = offset - initial;\n }\n if (indentAfterMarker > 4) {\n indentAfterMarker = 1;\n }\n const indent = initial + indentAfterMarker;\n token = state.push(\"list_item_open\", \"li\", 1);\n token.markup = String.fromCharCode(markerCharCode);\n const itemLines = [nextLine, 0];\n token.map = itemLines;\n if (isOrdered) {\n token.info = state.src.slice(start, posAfterMarker - 1);\n }\n const oldTight = state.tight;\n const oldTShift = state.tShift[nextLine];\n const oldSCount = state.sCount[nextLine];\n const oldListIndent = state.listIndent;\n state.listIndent = state.blkIndent;\n state.blkIndent = indent;\n state.tight = true;\n state.tShift[nextLine] = contentStart - state.bMarks[nextLine];\n state.sCount[nextLine] = offset;\n if (contentStart >= max && state.isEmpty(nextLine + 1)) {\n state.line = Math.min(state.line + 2, endLine);\n } else {\n state.md.block.tokenize(state, nextLine, endLine, true);\n }\n if (!state.tight || prevEmptyEnd) {\n tight = false;\n }\n prevEmptyEnd = state.line - nextLine > 1 && state.isEmpty(state.line - 1);\n state.blkIndent = state.listIndent;\n state.listIndent = oldListIndent;\n state.tShift[nextLine] = oldTShift;\n state.sCount[nextLine] = oldSCount;\n state.tight = oldTight;\n token = state.push(\"list_item_close\", \"li\", -1);\n token.markup = String.fromCharCode(markerCharCode);\n nextLine = state.line;\n itemLines[1] = nextLine;\n if (nextLine >= endLine) {\n break;\n }\n if (state.sCount[nextLine] < state.blkIndent) {\n break;\n }\n if (state.sCount[nextLine] - state.blkIndent >= 4) {\n break;\n }\n let terminate = false;\n for (let i = 0, l = terminatorRules.length; i < l; i++) {\n if (terminatorRules[i](state, nextLine, endLine, true)) {\n terminate = true;\n break;\n }\n }\n if (terminate) {\n break;\n }\n if (isOrdered) {\n posAfterMarker = skipOrderedListMarker(state, nextLine);\n if (posAfterMarker < 0) {\n break;\n }\n start = state.bMarks[nextLine] + state.tShift[nextLine];\n } else {\n posAfterMarker = skipBulletListMarker(state, nextLine);\n if (posAfterMarker < 0) {\n break;\n }\n }\n if (markerCharCode !== state.src.charCodeAt(posAfterMarker - 1)) {\n break;\n }\n }\n if (isOrdered) {\n token = state.push(\"ordered_list_close\", \"ol\", -1);\n } else {\n token = state.push(\"bullet_list_close\", \"ul\", -1);\n }\n token.markup = String.fromCharCode(markerCharCode);\n listLines[1] = nextLine;\n state.line = nextLine;\n state.parentType = oldParentType;\n if (tight) {\n markTightParagraphs(state, listTokIdx);\n }\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/reference.mjs\nfunction reference(state, startLine, _endLine, silent) {\n let pos = state.bMarks[startLine] + state.tShift[startLine];\n let max = state.eMarks[startLine];\n let nextLine = startLine + 1;\n if (state.sCount[startLine] - state.blkIndent >= 4) {\n return false;\n }\n if (state.src.charCodeAt(pos) !== 91) {\n return false;\n }\n function getNextLine(nextLine2) {\n const endLine = state.lineMax;\n if (nextLine2 >= endLine || state.isEmpty(nextLine2)) {\n return null;\n }\n let isContinuation = false;\n if (state.sCount[nextLine2] - state.blkIndent > 3) {\n isContinuation = true;\n }\n if (state.sCount[nextLine2] < 0) {\n isContinuation = true;\n }\n if (!isContinuation) {\n const terminatorRules = state.md.block.ruler.getRules(\"reference\");\n const oldParentType = state.parentType;\n state.parentType = \"reference\";\n let terminate = false;\n for (let i = 0, l = terminatorRules.length; i < l; i++) {\n if (terminatorRules[i](state, nextLine2, endLine, true)) {\n terminate = true;\n break;\n }\n }\n state.parentType = oldParentType;\n if (terminate) {\n return null;\n }\n }\n const pos2 = state.bMarks[nextLine2] + state.tShift[nextLine2];\n const max2 = state.eMarks[nextLine2];\n return state.src.slice(pos2, max2 + 1);\n }\n let str = state.src.slice(pos, max + 1);\n max = str.length;\n let labelEnd = -1;\n for (pos = 1; pos < max; pos++) {\n const ch = str.charCodeAt(pos);\n if (ch === 91) {\n return false;\n } else if (ch === 93) {\n labelEnd = pos;\n break;\n } else if (ch === 10) {\n const lineContent = getNextLine(nextLine);\n if (lineContent !== null) {\n str += lineContent;\n max = str.length;\n nextLine++;\n }\n } else if (ch === 92) {\n pos++;\n if (pos < max && str.charCodeAt(pos) === 10) {\n const lineContent = getNextLine(nextLine);\n if (lineContent !== null) {\n str += lineContent;\n max = str.length;\n nextLine++;\n }\n }\n }\n }\n if (labelEnd < 0 || str.charCodeAt(labelEnd + 1) !== 58) {\n return false;\n }\n for (pos = labelEnd + 2; pos < max; pos++) {\n const ch = str.charCodeAt(pos);\n if (ch === 10) {\n const lineContent = getNextLine(nextLine);\n if (lineContent !== null) {\n str += lineContent;\n max = str.length;\n nextLine++;\n }\n } else if (isSpace(ch)) {\n } else {\n break;\n }\n }\n const destRes = state.md.helpers.parseLinkDestination(str, pos, max);\n if (!destRes.ok) {\n return false;\n }\n const href = state.md.normalizeLink(destRes.str);\n if (!state.md.validateLink(href)) {\n return false;\n }\n pos = destRes.pos;\n const destEndPos = pos;\n const destEndLineNo = nextLine;\n const start = pos;\n for (; pos < max; pos++) {\n const ch = str.charCodeAt(pos);\n if (ch === 10) {\n const lineContent = getNextLine(nextLine);\n if (lineContent !== null) {\n str += lineContent;\n max = str.length;\n nextLine++;\n }\n } else if (isSpace(ch)) {\n } else {\n break;\n }\n }\n let titleRes = state.md.helpers.parseLinkTitle(str, pos, max);\n while (titleRes.can_continue) {\n const lineContent = getNextLine(nextLine);\n if (lineContent === null) break;\n str += lineContent;\n pos = max;\n max = str.length;\n nextLine++;\n titleRes = state.md.helpers.parseLinkTitle(str, pos, max, titleRes);\n }\n let title;\n if (pos < max && start !== pos && titleRes.ok) {\n title = titleRes.str;\n pos = titleRes.pos;\n } else {\n title = \"\";\n pos = destEndPos;\n nextLine = destEndLineNo;\n }\n while (pos < max) {\n const ch = str.charCodeAt(pos);\n if (!isSpace(ch)) {\n break;\n }\n pos++;\n }\n if (pos < max && str.charCodeAt(pos) !== 10) {\n if (title) {\n title = \"\";\n pos = destEndPos;\n nextLine = destEndLineNo;\n while (pos < max) {\n const ch = str.charCodeAt(pos);\n if (!isSpace(ch)) {\n break;\n }\n pos++;\n }\n }\n }\n if (pos < max && str.charCodeAt(pos) !== 10) {\n return false;\n }\n const label = normalizeReference(str.slice(1, labelEnd));\n if (!label) {\n return false;\n }\n if (silent) {\n return true;\n }\n if (typeof state.env.references === \"undefined\") {\n state.env.references = {};\n }\n if (typeof state.env.references[label] === \"undefined\") {\n state.env.references[label] = { title, href };\n }\n state.line = nextLine;\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/common/html_blocks.mjs\nvar html_blocks_default = [\n \"address\",\n \"article\",\n \"aside\",\n \"base\",\n \"basefont\",\n \"blockquote\",\n \"body\",\n \"caption\",\n \"center\",\n \"col\",\n \"colgroup\",\n \"dd\",\n \"details\",\n \"dialog\",\n \"dir\",\n \"div\",\n \"dl\",\n \"dt\",\n \"fieldset\",\n \"figcaption\",\n \"figure\",\n \"footer\",\n \"form\",\n \"frame\",\n \"frameset\",\n \"h1\",\n \"h2\",\n \"h3\",\n \"h4\",\n \"h5\",\n \"h6\",\n \"head\",\n \"header\",\n \"hr\",\n \"html\",\n \"iframe\",\n \"legend\",\n \"li\",\n \"link\",\n \"main\",\n \"menu\",\n \"menuitem\",\n \"nav\",\n \"noframes\",\n \"ol\",\n \"optgroup\",\n \"option\",\n \"p\",\n \"param\",\n \"search\",\n \"section\",\n \"summary\",\n \"table\",\n \"tbody\",\n \"td\",\n \"tfoot\",\n \"th\",\n \"thead\",\n \"title\",\n \"tr\",\n \"track\",\n \"ul\"\n];\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/common/html_re.mjs\nvar attr_name = \"[a-zA-Z_:][a-zA-Z0-9:._-]*\";\nvar unquoted = \"[^\\\"'=<>`\\\\x00-\\\\x20]+\";\nvar single_quoted = \"'[^']*'\";\nvar double_quoted = '\"[^\"]*\"';\nvar attr_value = \"(?:\" + unquoted + \"|\" + single_quoted + \"|\" + double_quoted + \")\";\nvar attribute = \"(?:\\\\s+\" + attr_name + \"(?:\\\\s*=\\\\s*\" + attr_value + \")?)\";\nvar open_tag = \"<[A-Za-z][A-Za-z0-9\\\\-]*\" + attribute + \"*\\\\s*\\\\/?>\";\nvar close_tag = \"<\\\\/[A-Za-z][A-Za-z0-9\\\\-]*\\\\s*>\";\nvar comment = \"\";\nvar processing = \"<[?][\\\\s\\\\S]*?[?]>\";\nvar declaration = \"]*>\";\nvar cdata = \"\";\nvar HTML_TAG_RE = new RegExp(\"^(?:\" + open_tag + \"|\" + close_tag + \"|\" + comment + \"|\" + processing + \"|\" + declaration + \"|\" + cdata + \")\");\nvar HTML_OPEN_CLOSE_TAG_RE = new RegExp(\"^(?:\" + open_tag + \"|\" + close_tag + \")\");\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/html_block.mjs\nvar HTML_SEQUENCES = [\n [/^<(script|pre|style|textarea)(?=(\\s|>|$))/i, /<\\/(script|pre|style|textarea)>/i, true],\n [/^/, true],\n [/^<\\?/, /\\?>/, true],\n [/^/, true],\n [/^/, true],\n [new RegExp(\"^|$))\", \"i\"), /^$/, true],\n [new RegExp(HTML_OPEN_CLOSE_TAG_RE.source + \"\\\\s*$\"), /^$/, false]\n];\nfunction html_block(state, startLine, endLine, silent) {\n let pos = state.bMarks[startLine] + state.tShift[startLine];\n let max = state.eMarks[startLine];\n if (state.sCount[startLine] - state.blkIndent >= 4) {\n return false;\n }\n if (!state.md.options.html) {\n return false;\n }\n if (state.src.charCodeAt(pos) !== 60) {\n return false;\n }\n let lineText = state.src.slice(pos, max);\n let i = 0;\n for (; i < HTML_SEQUENCES.length; i++) {\n if (HTML_SEQUENCES[i][0].test(lineText)) {\n break;\n }\n }\n if (i === HTML_SEQUENCES.length) {\n return false;\n }\n if (silent) {\n return HTML_SEQUENCES[i][2];\n }\n let nextLine = startLine + 1;\n if (!HTML_SEQUENCES[i][1].test(lineText)) {\n for (; nextLine < endLine; nextLine++) {\n if (state.sCount[nextLine] < state.blkIndent) {\n break;\n }\n pos = state.bMarks[nextLine] + state.tShift[nextLine];\n max = state.eMarks[nextLine];\n lineText = state.src.slice(pos, max);\n if (HTML_SEQUENCES[i][1].test(lineText)) {\n if (lineText.length !== 0) {\n nextLine++;\n }\n break;\n }\n }\n }\n state.line = nextLine;\n const token = state.push(\"html_block\", \"\", 0);\n token.map = [startLine, nextLine];\n token.content = state.getLines(startLine, nextLine, state.blkIndent, true);\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/heading.mjs\nfunction heading(state, startLine, endLine, silent) {\n let pos = state.bMarks[startLine] + state.tShift[startLine];\n let max = state.eMarks[startLine];\n if (state.sCount[startLine] - state.blkIndent >= 4) {\n return false;\n }\n let ch = state.src.charCodeAt(pos);\n if (ch !== 35 || pos >= max) {\n return false;\n }\n let level = 1;\n ch = state.src.charCodeAt(++pos);\n while (ch === 35 && pos < max && level <= 6) {\n level++;\n ch = state.src.charCodeAt(++pos);\n }\n if (level > 6 || pos < max && !isSpace(ch)) {\n return false;\n }\n if (silent) {\n return true;\n }\n max = state.skipSpacesBack(max, pos);\n const tmp = state.skipCharsBack(max, 35, pos);\n if (tmp > pos && isSpace(state.src.charCodeAt(tmp - 1))) {\n max = tmp;\n }\n state.line = startLine + 1;\n const token_o = state.push(\"heading_open\", \"h\" + String(level), 1);\n token_o.markup = \"########\".slice(0, level);\n token_o.map = [startLine, state.line];\n const token_i = state.push(\"inline\", \"\", 0);\n token_i.content = state.src.slice(pos, max).trim();\n token_i.map = [startLine, state.line];\n token_i.children = [];\n const token_c = state.push(\"heading_close\", \"h\" + String(level), -1);\n token_c.markup = \"########\".slice(0, level);\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/lheading.mjs\nfunction lheading(state, startLine, endLine) {\n const terminatorRules = state.md.block.ruler.getRules(\"paragraph\");\n if (state.sCount[startLine] - state.blkIndent >= 4) {\n return false;\n }\n const oldParentType = state.parentType;\n state.parentType = \"paragraph\";\n let level = 0;\n let marker;\n let nextLine = startLine + 1;\n for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) {\n if (state.sCount[nextLine] - state.blkIndent > 3) {\n continue;\n }\n if (state.sCount[nextLine] >= state.blkIndent) {\n let pos = state.bMarks[nextLine] + state.tShift[nextLine];\n const max = state.eMarks[nextLine];\n if (pos < max) {\n marker = state.src.charCodeAt(pos);\n if (marker === 45 || marker === 61) {\n pos = state.skipChars(pos, marker);\n pos = state.skipSpaces(pos);\n if (pos >= max) {\n level = marker === 61 ? 1 : 2;\n break;\n }\n }\n }\n }\n if (state.sCount[nextLine] < 0) {\n continue;\n }\n let terminate = false;\n for (let i = 0, l = terminatorRules.length; i < l; i++) {\n if (terminatorRules[i](state, nextLine, endLine, true)) {\n terminate = true;\n break;\n }\n }\n if (terminate) {\n break;\n }\n }\n if (!level) {\n return false;\n }\n const content = state.getLines(startLine, nextLine, state.blkIndent, false).trim();\n state.line = nextLine + 1;\n const token_o = state.push(\"heading_open\", \"h\" + String(level), 1);\n token_o.markup = String.fromCharCode(marker);\n token_o.map = [startLine, state.line];\n const token_i = state.push(\"inline\", \"\", 0);\n token_i.content = content;\n token_i.map = [startLine, state.line - 1];\n token_i.children = [];\n const token_c = state.push(\"heading_close\", \"h\" + String(level), -1);\n token_c.markup = String.fromCharCode(marker);\n state.parentType = oldParentType;\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/paragraph.mjs\nfunction paragraph(state, startLine, endLine) {\n const terminatorRules = state.md.block.ruler.getRules(\"paragraph\");\n const oldParentType = state.parentType;\n let nextLine = startLine + 1;\n state.parentType = \"paragraph\";\n for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) {\n if (state.sCount[nextLine] - state.blkIndent > 3) {\n continue;\n }\n if (state.sCount[nextLine] < 0) {\n continue;\n }\n let terminate = false;\n for (let i = 0, l = terminatorRules.length; i < l; i++) {\n if (terminatorRules[i](state, nextLine, endLine, true)) {\n terminate = true;\n break;\n }\n }\n if (terminate) {\n break;\n }\n }\n const content = state.getLines(startLine, nextLine, state.blkIndent, false).trim();\n state.line = nextLine;\n const token_o = state.push(\"paragraph_open\", \"p\", 1);\n token_o.map = [startLine, state.line];\n const token_i = state.push(\"inline\", \"\", 0);\n token_i.content = content;\n token_i.map = [startLine, state.line];\n token_i.children = [];\n state.push(\"paragraph_close\", \"p\", -1);\n state.parentType = oldParentType;\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/parser_block.mjs\nvar _rules2 = [\n // First 2 params - rule name & source. Secondary array - list of rules,\n // which can be terminated by this one.\n [\"table\", table, [\"paragraph\", \"reference\"]],\n [\"code\", code],\n [\"fence\", fence, [\"paragraph\", \"reference\", \"blockquote\", \"list\"]],\n [\"blockquote\", blockquote, [\"paragraph\", \"reference\", \"blockquote\", \"list\"]],\n [\"hr\", hr, [\"paragraph\", \"reference\", \"blockquote\", \"list\"]],\n [\"list\", list, [\"paragraph\", \"reference\", \"blockquote\"]],\n [\"reference\", reference],\n [\"html_block\", html_block, [\"paragraph\", \"reference\", \"blockquote\"]],\n [\"heading\", heading, [\"paragraph\", \"reference\", \"blockquote\"]],\n [\"lheading\", lheading],\n [\"paragraph\", paragraph]\n];\nfunction ParserBlock() {\n this.ruler = new ruler_default();\n for (let i = 0; i < _rules2.length; i++) {\n this.ruler.push(_rules2[i][0], _rules2[i][1], { alt: (_rules2[i][2] || []).slice() });\n }\n}\nParserBlock.prototype.tokenize = function(state, startLine, endLine) {\n const rules = this.ruler.getRules(\"\");\n const len = rules.length;\n const maxNesting = state.md.options.maxNesting;\n let line = startLine;\n let hasEmptyLines = false;\n while (line < endLine) {\n state.line = line = state.skipEmptyLines(line);\n if (line >= endLine) {\n break;\n }\n if (state.sCount[line] < state.blkIndent) {\n break;\n }\n if (state.level >= maxNesting) {\n state.line = endLine;\n break;\n }\n const prevLine = state.line;\n let ok = false;\n for (let i = 0; i < len; i++) {\n ok = rules[i](state, line, endLine, false);\n if (ok) {\n if (prevLine >= state.line) {\n throw new Error(\"block rule didn't increment state.line\");\n }\n break;\n }\n }\n if (!ok) throw new Error(\"none of the block rules matched\");\n state.tight = !hasEmptyLines;\n if (state.isEmpty(state.line - 1)) {\n hasEmptyLines = true;\n }\n line = state.line;\n if (line < endLine && state.isEmpty(line)) {\n hasEmptyLines = true;\n line++;\n state.line = line;\n }\n }\n};\nParserBlock.prototype.parse = function(src, md2, env, outTokens) {\n if (!src) {\n return;\n }\n const state = new this.State(src, md2, env, outTokens);\n this.tokenize(state, state.line, state.lineMax);\n};\nParserBlock.prototype.State = state_block_default;\nvar parser_block_default = ParserBlock;\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/state_inline.mjs\nfunction StateInline(src, md2, env, outTokens) {\n this.src = src;\n this.env = env;\n this.md = md2;\n this.tokens = outTokens;\n this.tokens_meta = Array(outTokens.length);\n this.pos = 0;\n this.posMax = this.src.length;\n this.level = 0;\n this.pending = \"\";\n this.pendingLevel = 0;\n this.cache = {};\n this.delimiters = [];\n this._prev_delimiters = [];\n this.backticks = {};\n this.backticksScanned = false;\n this.linkLevel = 0;\n}\nStateInline.prototype.pushPending = function() {\n const token = new token_default(\"text\", \"\", 0);\n token.content = this.pending;\n token.level = this.pendingLevel;\n this.tokens.push(token);\n this.pending = \"\";\n return token;\n};\nStateInline.prototype.push = function(type, tag, nesting) {\n if (this.pending) {\n this.pushPending();\n }\n const token = new token_default(type, tag, nesting);\n let token_meta = null;\n if (nesting < 0) {\n this.level--;\n this.delimiters = this._prev_delimiters.pop();\n }\n token.level = this.level;\n if (nesting > 0) {\n this.level++;\n this._prev_delimiters.push(this.delimiters);\n this.delimiters = [];\n token_meta = { delimiters: this.delimiters };\n }\n this.pendingLevel = this.level;\n this.tokens.push(token);\n this.tokens_meta.push(token_meta);\n return token;\n};\nStateInline.prototype.scanDelims = function(start, canSplitWord) {\n const max = this.posMax;\n const marker = this.src.charCodeAt(start);\n const lastChar = start > 0 ? this.src.charCodeAt(start - 1) : 32;\n let pos = start;\n while (pos < max && this.src.charCodeAt(pos) === marker) {\n pos++;\n }\n const count = pos - start;\n const nextChar = pos < max ? this.src.charCodeAt(pos) : 32;\n const isLastPunctChar = isMdAsciiPunct(lastChar) || isPunctChar(String.fromCharCode(lastChar));\n const isNextPunctChar = isMdAsciiPunct(nextChar) || isPunctChar(String.fromCharCode(nextChar));\n const isLastWhiteSpace = isWhiteSpace(lastChar);\n const isNextWhiteSpace = isWhiteSpace(nextChar);\n const left_flanking = !isNextWhiteSpace && (!isNextPunctChar || isLastWhiteSpace || isLastPunctChar);\n const right_flanking = !isLastWhiteSpace && (!isLastPunctChar || isNextWhiteSpace || isNextPunctChar);\n const can_open = left_flanking && (canSplitWord || !right_flanking || isLastPunctChar);\n const can_close = right_flanking && (canSplitWord || !left_flanking || isNextPunctChar);\n return { can_open, can_close, length: count };\n};\nStateInline.prototype.Token = token_default;\nvar state_inline_default = StateInline;\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/text.mjs\nfunction isTerminatorChar(ch) {\n switch (ch) {\n case 10:\n case 33:\n case 35:\n case 36:\n case 37:\n case 38:\n case 42:\n case 43:\n case 45:\n case 58:\n case 60:\n case 61:\n case 62:\n case 64:\n case 91:\n case 92:\n case 93:\n case 94:\n case 95:\n case 96:\n case 123:\n case 125:\n case 126:\n return true;\n default:\n return false;\n }\n}\nfunction text(state, silent) {\n let pos = state.pos;\n while (pos < state.posMax && !isTerminatorChar(state.src.charCodeAt(pos))) {\n pos++;\n }\n if (pos === state.pos) {\n return false;\n }\n if (!silent) {\n state.pending += state.src.slice(state.pos, pos);\n }\n state.pos = pos;\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/linkify.mjs\nvar SCHEME_RE = /(?:^|[^a-z0-9.+-])([a-z][a-z0-9.+-]*)$/i;\nfunction linkify2(state, silent) {\n if (!state.md.options.linkify) return false;\n if (state.linkLevel > 0) return false;\n const pos = state.pos;\n const max = state.posMax;\n if (pos + 3 > max) return false;\n if (state.src.charCodeAt(pos) !== 58) return false;\n if (state.src.charCodeAt(pos + 1) !== 47) return false;\n if (state.src.charCodeAt(pos + 2) !== 47) return false;\n const match2 = state.pending.match(SCHEME_RE);\n if (!match2) return false;\n const proto = match2[1];\n const link2 = state.md.linkify.matchAtStart(state.src.slice(pos - proto.length));\n if (!link2) return false;\n let url = link2.url;\n if (url.length <= proto.length) return false;\n let urlEnd = url.length;\n while (urlEnd > 0 && url.charCodeAt(urlEnd - 1) === 42) {\n urlEnd--;\n }\n if (urlEnd !== url.length) {\n url = url.slice(0, urlEnd);\n }\n const fullUrl = state.md.normalizeLink(url);\n if (!state.md.validateLink(fullUrl)) return false;\n if (!silent) {\n state.pending = state.pending.slice(0, -proto.length);\n const token_o = state.push(\"link_open\", \"a\", 1);\n token_o.attrs = [[\"href\", fullUrl]];\n token_o.markup = \"linkify\";\n token_o.info = \"auto\";\n const token_t = state.push(\"text\", \"\", 0);\n token_t.content = state.md.normalizeLinkText(url);\n const token_c = state.push(\"link_close\", \"a\", -1);\n token_c.markup = \"linkify\";\n token_c.info = \"auto\";\n }\n state.pos += url.length - proto.length;\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/newline.mjs\nfunction newline(state, silent) {\n let pos = state.pos;\n if (state.src.charCodeAt(pos) !== 10) {\n return false;\n }\n const pmax = state.pending.length - 1;\n const max = state.posMax;\n if (!silent) {\n if (pmax >= 0 && state.pending.charCodeAt(pmax) === 32) {\n if (pmax >= 1 && state.pending.charCodeAt(pmax - 1) === 32) {\n let ws = pmax - 1;\n while (ws >= 1 && state.pending.charCodeAt(ws - 1) === 32) ws--;\n state.pending = state.pending.slice(0, ws);\n state.push(\"hardbreak\", \"br\", 0);\n } else {\n state.pending = state.pending.slice(0, -1);\n state.push(\"softbreak\", \"br\", 0);\n }\n } else {\n state.push(\"softbreak\", \"br\", 0);\n }\n }\n pos++;\n while (pos < max && isSpace(state.src.charCodeAt(pos))) {\n pos++;\n }\n state.pos = pos;\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/escape.mjs\nvar ESCAPED = [];\nfor (let i = 0; i < 256; i++) {\n ESCAPED.push(0);\n}\n\"\\\\!\\\"#$%&'()*+,./:;<=>?@[]^_`{|}~-\".split(\"\").forEach(function(ch) {\n ESCAPED[ch.charCodeAt(0)] = 1;\n});\nfunction escape2(state, silent) {\n let pos = state.pos;\n const max = state.posMax;\n if (state.src.charCodeAt(pos) !== 92) return false;\n pos++;\n if (pos >= max) return false;\n let ch1 = state.src.charCodeAt(pos);\n if (ch1 === 10) {\n if (!silent) {\n state.push(\"hardbreak\", \"br\", 0);\n }\n pos++;\n while (pos < max) {\n ch1 = state.src.charCodeAt(pos);\n if (!isSpace(ch1)) break;\n pos++;\n }\n state.pos = pos;\n return true;\n }\n let escapedStr = state.src[pos];\n if (ch1 >= 55296 && ch1 <= 56319 && pos + 1 < max) {\n const ch2 = state.src.charCodeAt(pos + 1);\n if (ch2 >= 56320 && ch2 <= 57343) {\n escapedStr += state.src[pos + 1];\n pos++;\n }\n }\n const origStr = \"\\\\\" + escapedStr;\n if (!silent) {\n const token = state.push(\"text_special\", \"\", 0);\n if (ch1 < 256 && ESCAPED[ch1] !== 0) {\n token.content = escapedStr;\n } else {\n token.content = origStr;\n }\n token.markup = origStr;\n token.info = \"escape\";\n }\n state.pos = pos + 1;\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/backticks.mjs\nfunction backtick(state, silent) {\n let pos = state.pos;\n const ch = state.src.charCodeAt(pos);\n if (ch !== 96) {\n return false;\n }\n const start = pos;\n pos++;\n const max = state.posMax;\n while (pos < max && state.src.charCodeAt(pos) === 96) {\n pos++;\n }\n const marker = state.src.slice(start, pos);\n const openerLength = marker.length;\n if (state.backticksScanned && (state.backticks[openerLength] || 0) <= start) {\n if (!silent) state.pending += marker;\n state.pos += openerLength;\n return true;\n }\n let matchEnd = pos;\n let matchStart;\n while ((matchStart = state.src.indexOf(\"`\", matchEnd)) !== -1) {\n matchEnd = matchStart + 1;\n while (matchEnd < max && state.src.charCodeAt(matchEnd) === 96) {\n matchEnd++;\n }\n const closerLength = matchEnd - matchStart;\n if (closerLength === openerLength) {\n if (!silent) {\n const token = state.push(\"code_inline\", \"code\", 0);\n token.markup = marker;\n token.content = state.src.slice(pos, matchStart).replace(/\\n/g, \" \").replace(/^ (.+) $/, \"$1\");\n }\n state.pos = matchEnd;\n return true;\n }\n state.backticks[closerLength] = matchStart;\n }\n state.backticksScanned = true;\n if (!silent) state.pending += marker;\n state.pos += openerLength;\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/strikethrough.mjs\nfunction strikethrough_tokenize(state, silent) {\n const start = state.pos;\n const marker = state.src.charCodeAt(start);\n if (silent) {\n return false;\n }\n if (marker !== 126) {\n return false;\n }\n const scanned = state.scanDelims(state.pos, true);\n let len = scanned.length;\n const ch = String.fromCharCode(marker);\n if (len < 2) {\n return false;\n }\n let token;\n if (len % 2) {\n token = state.push(\"text\", \"\", 0);\n token.content = ch;\n len--;\n }\n for (let i = 0; i < len; i += 2) {\n token = state.push(\"text\", \"\", 0);\n token.content = ch + ch;\n state.delimiters.push({\n marker,\n length: 0,\n // disable \"rule of 3\" length checks meant for emphasis\n token: state.tokens.length - 1,\n end: -1,\n open: scanned.can_open,\n close: scanned.can_close\n });\n }\n state.pos += scanned.length;\n return true;\n}\nfunction postProcess(state, delimiters) {\n let token;\n const loneMarkers = [];\n const max = delimiters.length;\n for (let i = 0; i < max; i++) {\n const startDelim = delimiters[i];\n if (startDelim.marker !== 126) {\n continue;\n }\n if (startDelim.end === -1) {\n continue;\n }\n const endDelim = delimiters[startDelim.end];\n token = state.tokens[startDelim.token];\n token.type = \"s_open\";\n token.tag = \"s\";\n token.nesting = 1;\n token.markup = \"~~\";\n token.content = \"\";\n token = state.tokens[endDelim.token];\n token.type = \"s_close\";\n token.tag = \"s\";\n token.nesting = -1;\n token.markup = \"~~\";\n token.content = \"\";\n if (state.tokens[endDelim.token - 1].type === \"text\" && state.tokens[endDelim.token - 1].content === \"~\") {\n loneMarkers.push(endDelim.token - 1);\n }\n }\n while (loneMarkers.length) {\n const i = loneMarkers.pop();\n let j = i + 1;\n while (j < state.tokens.length && state.tokens[j].type === \"s_close\") {\n j++;\n }\n j--;\n if (i !== j) {\n token = state.tokens[j];\n state.tokens[j] = state.tokens[i];\n state.tokens[i] = token;\n }\n }\n}\nfunction strikethrough_postProcess(state) {\n const tokens_meta = state.tokens_meta;\n const max = state.tokens_meta.length;\n postProcess(state, state.delimiters);\n for (let curr = 0; curr < max; curr++) {\n if (tokens_meta[curr] && tokens_meta[curr].delimiters) {\n postProcess(state, tokens_meta[curr].delimiters);\n }\n }\n}\nvar strikethrough_default = {\n tokenize: strikethrough_tokenize,\n postProcess: strikethrough_postProcess\n};\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/emphasis.mjs\nfunction emphasis_tokenize(state, silent) {\n const start = state.pos;\n const marker = state.src.charCodeAt(start);\n if (silent) {\n return false;\n }\n if (marker !== 95 && marker !== 42) {\n return false;\n }\n const scanned = state.scanDelims(state.pos, marker === 42);\n for (let i = 0; i < scanned.length; i++) {\n const token = state.push(\"text\", \"\", 0);\n token.content = String.fromCharCode(marker);\n state.delimiters.push({\n // Char code of the starting marker (number).\n //\n marker,\n // Total length of these series of delimiters.\n //\n length: scanned.length,\n // A position of the token this delimiter corresponds to.\n //\n token: state.tokens.length - 1,\n // If this delimiter is matched as a valid opener, `end` will be\n // equal to its position, otherwise it's `-1`.\n //\n end: -1,\n // Boolean flags that determine if this delimiter could open or close\n // an emphasis.\n //\n open: scanned.can_open,\n close: scanned.can_close\n });\n }\n state.pos += scanned.length;\n return true;\n}\nfunction postProcess2(state, delimiters) {\n const max = delimiters.length;\n for (let i = max - 1; i >= 0; i--) {\n const startDelim = delimiters[i];\n if (startDelim.marker !== 95 && startDelim.marker !== 42) {\n continue;\n }\n if (startDelim.end === -1) {\n continue;\n }\n const endDelim = delimiters[startDelim.end];\n const isStrong = i > 0 && delimiters[i - 1].end === startDelim.end + 1 && // check that first two markers match and adjacent\n delimiters[i - 1].marker === startDelim.marker && delimiters[i - 1].token === startDelim.token - 1 && // check that last two markers are adjacent (we can safely assume they match)\n delimiters[startDelim.end + 1].token === endDelim.token + 1;\n const ch = String.fromCharCode(startDelim.marker);\n const token_o = state.tokens[startDelim.token];\n token_o.type = isStrong ? \"strong_open\" : \"em_open\";\n token_o.tag = isStrong ? \"strong\" : \"em\";\n token_o.nesting = 1;\n token_o.markup = isStrong ? ch + ch : ch;\n token_o.content = \"\";\n const token_c = state.tokens[endDelim.token];\n token_c.type = isStrong ? \"strong_close\" : \"em_close\";\n token_c.tag = isStrong ? \"strong\" : \"em\";\n token_c.nesting = -1;\n token_c.markup = isStrong ? ch + ch : ch;\n token_c.content = \"\";\n if (isStrong) {\n state.tokens[delimiters[i - 1].token].content = \"\";\n state.tokens[delimiters[startDelim.end + 1].token].content = \"\";\n i--;\n }\n }\n}\nfunction emphasis_post_process(state) {\n const tokens_meta = state.tokens_meta;\n const max = state.tokens_meta.length;\n postProcess2(state, state.delimiters);\n for (let curr = 0; curr < max; curr++) {\n if (tokens_meta[curr] && tokens_meta[curr].delimiters) {\n postProcess2(state, tokens_meta[curr].delimiters);\n }\n }\n}\nvar emphasis_default = {\n tokenize: emphasis_tokenize,\n postProcess: emphasis_post_process\n};\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/link.mjs\nfunction link(state, silent) {\n let code2, label, res, ref;\n let href = \"\";\n let title = \"\";\n let start = state.pos;\n let parseReference = true;\n if (state.src.charCodeAt(state.pos) !== 91) {\n return false;\n }\n const oldPos = state.pos;\n const max = state.posMax;\n const labelStart = state.pos + 1;\n const labelEnd = state.md.helpers.parseLinkLabel(state, state.pos, true);\n if (labelEnd < 0) {\n return false;\n }\n let pos = labelEnd + 1;\n if (pos < max && state.src.charCodeAt(pos) === 40) {\n parseReference = false;\n pos++;\n for (; pos < max; pos++) {\n code2 = state.src.charCodeAt(pos);\n if (!isSpace(code2) && code2 !== 10) {\n break;\n }\n }\n if (pos >= max) {\n return false;\n }\n start = pos;\n res = state.md.helpers.parseLinkDestination(state.src, pos, state.posMax);\n if (res.ok) {\n href = state.md.normalizeLink(res.str);\n if (state.md.validateLink(href)) {\n pos = res.pos;\n } else {\n href = \"\";\n }\n start = pos;\n for (; pos < max; pos++) {\n code2 = state.src.charCodeAt(pos);\n if (!isSpace(code2) && code2 !== 10) {\n break;\n }\n }\n res = state.md.helpers.parseLinkTitle(state.src, pos, state.posMax);\n if (pos < max && start !== pos && res.ok) {\n title = res.str;\n pos = res.pos;\n for (; pos < max; pos++) {\n code2 = state.src.charCodeAt(pos);\n if (!isSpace(code2) && code2 !== 10) {\n break;\n }\n }\n }\n }\n if (pos >= max || state.src.charCodeAt(pos) !== 41) {\n parseReference = true;\n }\n pos++;\n }\n if (parseReference) {\n if (typeof state.env.references === \"undefined\") {\n return false;\n }\n if (pos < max && state.src.charCodeAt(pos) === 91) {\n start = pos + 1;\n pos = state.md.helpers.parseLinkLabel(state, pos);\n if (pos >= 0) {\n label = state.src.slice(start, pos++);\n } else {\n pos = labelEnd + 1;\n }\n } else {\n pos = labelEnd + 1;\n }\n if (!label) {\n label = state.src.slice(labelStart, labelEnd);\n }\n ref = state.env.references[normalizeReference(label)];\n if (!ref) {\n state.pos = oldPos;\n return false;\n }\n href = ref.href;\n title = ref.title;\n }\n if (!silent) {\n state.pos = labelStart;\n state.posMax = labelEnd;\n const token_o = state.push(\"link_open\", \"a\", 1);\n const attrs = [[\"href\", href]];\n token_o.attrs = attrs;\n if (title) {\n attrs.push([\"title\", title]);\n }\n state.linkLevel++;\n state.md.inline.tokenize(state);\n state.linkLevel--;\n state.push(\"link_close\", \"a\", -1);\n }\n state.pos = pos;\n state.posMax = max;\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/image.mjs\nfunction image(state, silent) {\n let code2, content, label, pos, ref, res, title, start;\n let href = \"\";\n const oldPos = state.pos;\n const max = state.posMax;\n if (state.src.charCodeAt(state.pos) !== 33) {\n return false;\n }\n if (state.src.charCodeAt(state.pos + 1) !== 91) {\n return false;\n }\n const labelStart = state.pos + 2;\n const labelEnd = state.md.helpers.parseLinkLabel(state, state.pos + 1, false);\n if (labelEnd < 0) {\n return false;\n }\n pos = labelEnd + 1;\n if (pos < max && state.src.charCodeAt(pos) === 40) {\n pos++;\n for (; pos < max; pos++) {\n code2 = state.src.charCodeAt(pos);\n if (!isSpace(code2) && code2 !== 10) {\n break;\n }\n }\n if (pos >= max) {\n return false;\n }\n start = pos;\n res = state.md.helpers.parseLinkDestination(state.src, pos, state.posMax);\n if (res.ok) {\n href = state.md.normalizeLink(res.str);\n if (state.md.validateLink(href)) {\n pos = res.pos;\n } else {\n href = \"\";\n }\n }\n start = pos;\n for (; pos < max; pos++) {\n code2 = state.src.charCodeAt(pos);\n if (!isSpace(code2) && code2 !== 10) {\n break;\n }\n }\n res = state.md.helpers.parseLinkTitle(state.src, pos, state.posMax);\n if (pos < max && start !== pos && res.ok) {\n title = res.str;\n pos = res.pos;\n for (; pos < max; pos++) {\n code2 = state.src.charCodeAt(pos);\n if (!isSpace(code2) && code2 !== 10) {\n break;\n }\n }\n } else {\n title = \"\";\n }\n if (pos >= max || state.src.charCodeAt(pos) !== 41) {\n state.pos = oldPos;\n return false;\n }\n pos++;\n } else {\n if (typeof state.env.references === \"undefined\") {\n return false;\n }\n if (pos < max && state.src.charCodeAt(pos) === 91) {\n start = pos + 1;\n pos = state.md.helpers.parseLinkLabel(state, pos);\n if (pos >= 0) {\n label = state.src.slice(start, pos++);\n } else {\n pos = labelEnd + 1;\n }\n } else {\n pos = labelEnd + 1;\n }\n if (!label) {\n label = state.src.slice(labelStart, labelEnd);\n }\n ref = state.env.references[normalizeReference(label)];\n if (!ref) {\n state.pos = oldPos;\n return false;\n }\n href = ref.href;\n title = ref.title;\n }\n if (!silent) {\n content = state.src.slice(labelStart, labelEnd);\n const tokens2 = [];\n state.md.inline.parse(\n content,\n state.md,\n state.env,\n tokens2\n );\n const token = state.push(\"image\", \"img\", 0);\n const attrs = [[\"src\", href], [\"alt\", \"\"]];\n token.attrs = attrs;\n token.children = tokens2;\n token.content = content;\n if (title) {\n attrs.push([\"title\", title]);\n }\n }\n state.pos = pos;\n state.posMax = max;\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/autolink.mjs\nvar EMAIL_RE = /^([a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)$/;\nvar AUTOLINK_RE = /^([a-zA-Z][a-zA-Z0-9+.-]{1,31}):([^<>\\x00-\\x20]*)$/;\nfunction autolink(state, silent) {\n let pos = state.pos;\n if (state.src.charCodeAt(pos) !== 60) {\n return false;\n }\n const start = state.pos;\n const max = state.posMax;\n for (; ; ) {\n if (++pos >= max) return false;\n const ch = state.src.charCodeAt(pos);\n if (ch === 60) return false;\n if (ch === 62) break;\n }\n const url = state.src.slice(start + 1, pos);\n if (AUTOLINK_RE.test(url)) {\n const fullUrl = state.md.normalizeLink(url);\n if (!state.md.validateLink(fullUrl)) {\n return false;\n }\n if (!silent) {\n const token_o = state.push(\"link_open\", \"a\", 1);\n token_o.attrs = [[\"href\", fullUrl]];\n token_o.markup = \"autolink\";\n token_o.info = \"auto\";\n const token_t = state.push(\"text\", \"\", 0);\n token_t.content = state.md.normalizeLinkText(url);\n const token_c = state.push(\"link_close\", \"a\", -1);\n token_c.markup = \"autolink\";\n token_c.info = \"auto\";\n }\n state.pos += url.length + 2;\n return true;\n }\n if (EMAIL_RE.test(url)) {\n const fullUrl = state.md.normalizeLink(\"mailto:\" + url);\n if (!state.md.validateLink(fullUrl)) {\n return false;\n }\n if (!silent) {\n const token_o = state.push(\"link_open\", \"a\", 1);\n token_o.attrs = [[\"href\", fullUrl]];\n token_o.markup = \"autolink\";\n token_o.info = \"auto\";\n const token_t = state.push(\"text\", \"\", 0);\n token_t.content = state.md.normalizeLinkText(url);\n const token_c = state.push(\"link_close\", \"a\", -1);\n token_c.markup = \"autolink\";\n token_c.info = \"auto\";\n }\n state.pos += url.length + 2;\n return true;\n }\n return false;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/html_inline.mjs\nfunction isLinkOpen2(str) {\n return /^\\s]/i.test(str);\n}\nfunction isLinkClose2(str) {\n return /^<\\/a\\s*>/i.test(str);\n}\nfunction isLetter(ch) {\n const lc = ch | 32;\n return lc >= 97 && lc <= 122;\n}\nfunction html_inline(state, silent) {\n if (!state.md.options.html) {\n return false;\n }\n const max = state.posMax;\n const pos = state.pos;\n if (state.src.charCodeAt(pos) !== 60 || pos + 2 >= max) {\n return false;\n }\n const ch = state.src.charCodeAt(pos + 1);\n if (ch !== 33 && ch !== 63 && ch !== 47 && !isLetter(ch)) {\n return false;\n }\n const match2 = state.src.slice(pos).match(HTML_TAG_RE);\n if (!match2) {\n return false;\n }\n if (!silent) {\n const token = state.push(\"html_inline\", \"\", 0);\n token.content = match2[0];\n if (isLinkOpen2(token.content)) state.linkLevel++;\n if (isLinkClose2(token.content)) state.linkLevel--;\n }\n state.pos += match2[0].length;\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/entity.mjs\nvar DIGITAL_RE = /^&#((?:x[a-f0-9]{1,6}|[0-9]{1,7}));/i;\nvar NAMED_RE = /^&([a-z][a-z0-9]{1,31});/i;\nfunction entity(state, silent) {\n const pos = state.pos;\n const max = state.posMax;\n if (state.src.charCodeAt(pos) !== 38) return false;\n if (pos + 1 >= max) return false;\n const ch = state.src.charCodeAt(pos + 1);\n if (ch === 35) {\n const match2 = state.src.slice(pos).match(DIGITAL_RE);\n if (match2) {\n if (!silent) {\n const code2 = match2[1][0].toLowerCase() === \"x\" ? parseInt(match2[1].slice(1), 16) : parseInt(match2[1], 10);\n const token = state.push(\"text_special\", \"\", 0);\n token.content = isValidEntityCode(code2) ? fromCodePoint2(code2) : fromCodePoint2(65533);\n token.markup = match2[0];\n token.info = \"entity\";\n }\n state.pos += match2[0].length;\n return true;\n }\n } else {\n const match2 = state.src.slice(pos).match(NAMED_RE);\n if (match2) {\n const decoded = decodeHTML(match2[0]);\n if (decoded !== match2[0]) {\n if (!silent) {\n const token = state.push(\"text_special\", \"\", 0);\n token.content = decoded;\n token.markup = match2[0];\n token.info = \"entity\";\n }\n state.pos += match2[0].length;\n return true;\n }\n }\n }\n return false;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/balance_pairs.mjs\nfunction processDelimiters(delimiters) {\n const openersBottom = {};\n const max = delimiters.length;\n if (!max) return;\n let headerIdx = 0;\n let lastTokenIdx = -2;\n const jumps = [];\n for (let closerIdx = 0; closerIdx < max; closerIdx++) {\n const closer = delimiters[closerIdx];\n jumps.push(0);\n if (delimiters[headerIdx].marker !== closer.marker || lastTokenIdx !== closer.token - 1) {\n headerIdx = closerIdx;\n }\n lastTokenIdx = closer.token;\n closer.length = closer.length || 0;\n if (!closer.close) continue;\n if (!openersBottom.hasOwnProperty(closer.marker)) {\n openersBottom[closer.marker] = [-1, -1, -1, -1, -1, -1];\n }\n const minOpenerIdx = openersBottom[closer.marker][(closer.open ? 3 : 0) + closer.length % 3];\n let openerIdx = headerIdx - jumps[headerIdx] - 1;\n let newMinOpenerIdx = openerIdx;\n for (; openerIdx > minOpenerIdx; openerIdx -= jumps[openerIdx] + 1) {\n const opener = delimiters[openerIdx];\n if (opener.marker !== closer.marker) continue;\n if (opener.open && opener.end < 0) {\n let isOddMatch = false;\n if (opener.close || closer.open) {\n if ((opener.length + closer.length) % 3 === 0) {\n if (opener.length % 3 !== 0 || closer.length % 3 !== 0) {\n isOddMatch = true;\n }\n }\n }\n if (!isOddMatch) {\n const lastJump = openerIdx > 0 && !delimiters[openerIdx - 1].open ? jumps[openerIdx - 1] + 1 : 0;\n jumps[closerIdx] = closerIdx - openerIdx + lastJump;\n jumps[openerIdx] = lastJump;\n closer.open = false;\n opener.end = closerIdx;\n opener.close = false;\n newMinOpenerIdx = -1;\n lastTokenIdx = -2;\n break;\n }\n }\n }\n if (newMinOpenerIdx !== -1) {\n openersBottom[closer.marker][(closer.open ? 3 : 0) + (closer.length || 0) % 3] = newMinOpenerIdx;\n }\n }\n}\nfunction link_pairs(state) {\n const tokens_meta = state.tokens_meta;\n const max = state.tokens_meta.length;\n processDelimiters(state.delimiters);\n for (let curr = 0; curr < max; curr++) {\n if (tokens_meta[curr] && tokens_meta[curr].delimiters) {\n processDelimiters(tokens_meta[curr].delimiters);\n }\n }\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/fragments_join.mjs\nfunction fragments_join(state) {\n let curr, last;\n let level = 0;\n const tokens2 = state.tokens;\n const max = state.tokens.length;\n for (curr = last = 0; curr < max; curr++) {\n if (tokens2[curr].nesting < 0) level--;\n tokens2[curr].level = level;\n if (tokens2[curr].nesting > 0) level++;\n if (tokens2[curr].type === \"text\" && curr + 1 < max && tokens2[curr + 1].type === \"text\") {\n tokens2[curr + 1].content = tokens2[curr].content + tokens2[curr + 1].content;\n } else {\n if (curr !== last) {\n tokens2[last] = tokens2[curr];\n }\n last++;\n }\n }\n if (curr !== last) {\n tokens2.length = last;\n }\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/parser_inline.mjs\nvar _rules3 = [\n [\"text\", text],\n [\"linkify\", linkify2],\n [\"newline\", newline],\n [\"escape\", escape2],\n [\"backticks\", backtick],\n [\"strikethrough\", strikethrough_default.tokenize],\n [\"emphasis\", emphasis_default.tokenize],\n [\"link\", link],\n [\"image\", image],\n [\"autolink\", autolink],\n [\"html_inline\", html_inline],\n [\"entity\", entity]\n];\nvar _rules22 = [\n [\"balance_pairs\", link_pairs],\n [\"strikethrough\", strikethrough_default.postProcess],\n [\"emphasis\", emphasis_default.postProcess],\n // rules for pairs separate '**' into its own text tokens, which may be left unused,\n // rule below merges unused segments back with the rest of the text\n [\"fragments_join\", fragments_join]\n];\nfunction ParserInline() {\n this.ruler = new ruler_default();\n for (let i = 0; i < _rules3.length; i++) {\n this.ruler.push(_rules3[i][0], _rules3[i][1]);\n }\n this.ruler2 = new ruler_default();\n for (let i = 0; i < _rules22.length; i++) {\n this.ruler2.push(_rules22[i][0], _rules22[i][1]);\n }\n}\nParserInline.prototype.skipToken = function(state) {\n const pos = state.pos;\n const rules = this.ruler.getRules(\"\");\n const len = rules.length;\n const maxNesting = state.md.options.maxNesting;\n const cache = state.cache;\n if (typeof cache[pos] !== \"undefined\") {\n state.pos = cache[pos];\n return;\n }\n let ok = false;\n if (state.level < maxNesting) {\n for (let i = 0; i < len; i++) {\n state.level++;\n ok = rules[i](state, true);\n state.level--;\n if (ok) {\n if (pos >= state.pos) {\n throw new Error(\"inline rule didn't increment state.pos\");\n }\n break;\n }\n }\n } else {\n state.pos = state.posMax;\n }\n if (!ok) {\n state.pos++;\n }\n cache[pos] = state.pos;\n};\nParserInline.prototype.tokenize = function(state) {\n const rules = this.ruler.getRules(\"\");\n const len = rules.length;\n const end = state.posMax;\n const maxNesting = state.md.options.maxNesting;\n while (state.pos < end) {\n const prevPos = state.pos;\n let ok = false;\n if (state.level < maxNesting) {\n for (let i = 0; i < len; i++) {\n ok = rules[i](state, false);\n if (ok) {\n if (prevPos >= state.pos) {\n throw new Error(\"inline rule didn't increment state.pos\");\n }\n break;\n }\n }\n }\n if (ok) {\n if (state.pos >= end) {\n break;\n }\n continue;\n }\n state.pending += state.src[state.pos++];\n }\n if (state.pending) {\n state.pushPending();\n }\n};\nParserInline.prototype.parse = function(str, md2, env, outTokens) {\n const state = new this.State(str, md2, env, outTokens);\n this.tokenize(state);\n const rules = this.ruler2.getRules(\"\");\n const len = rules.length;\n for (let i = 0; i < len; i++) {\n rules[i](state);\n }\n};\nParserInline.prototype.State = state_inline_default;\nvar parser_inline_default = ParserInline;\n\n// node_modules/.pnpm/linkify-it@5.0.0/node_modules/linkify-it/lib/re.mjs\nfunction re_default(opts) {\n const re = {};\n opts = opts || {};\n re.src_Any = regex_default.source;\n re.src_Cc = regex_default2.source;\n re.src_Z = regex_default6.source;\n re.src_P = regex_default4.source;\n re.src_ZPCc = [re.src_Z, re.src_P, re.src_Cc].join(\"|\");\n re.src_ZCc = [re.src_Z, re.src_Cc].join(\"|\");\n const text_separators = \"[><|]\";\n re.src_pseudo_letter = \"(?:(?!\" + text_separators + \"|\" + re.src_ZPCc + \")\" + re.src_Any + \")\";\n re.src_ip4 = \"(?:(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\";\n re.src_auth = \"(?:(?:(?!\" + re.src_ZCc + \"|[@/\\\\[\\\\]()]).)+@)?\";\n re.src_port = \"(?::(?:6(?:[0-4]\\\\d{3}|5(?:[0-4]\\\\d{2}|5(?:[0-2]\\\\d|3[0-5])))|[1-5]?\\\\d{1,4}))?\";\n re.src_host_terminator = \"(?=$|\" + text_separators + \"|\" + re.src_ZPCc + \")(?!\" + (opts[\"---\"] ? \"-(?!--)|\" : \"-|\") + \"_|:\\\\d|\\\\.-|\\\\.(?!$|\" + re.src_ZPCc + \"))\";\n re.src_path = \"(?:[/?#](?:(?!\" + re.src_ZCc + \"|\" + text_separators + `|[()[\\\\]{}.,\"'?!\\\\-;]).|\\\\[(?:(?!` + re.src_ZCc + \"|\\\\]).)*\\\\]|\\\\((?:(?!\" + re.src_ZCc + \"|[)]).)*\\\\)|\\\\{(?:(?!\" + re.src_ZCc + '|[}]).)*\\\\}|\\\\\"(?:(?!' + re.src_ZCc + `|[\"]).)+\\\\\"|\\\\'(?:(?!` + re.src_ZCc + \"|[']).)+\\\\'|\\\\'(?=\" + re.src_pseudo_letter + \"|[-])|\\\\.{2,}[a-zA-Z0-9%/&]|\\\\.(?!\" + re.src_ZCc + \"|[.]|$)|\" + (opts[\"---\"] ? \"\\\\-(?!--(?:[^-]|$))(?:-*)|\" : \"\\\\-+|\") + // allow `,,,` in paths\n \",(?!\" + re.src_ZCc + \"|$)|;(?!\" + re.src_ZCc + \"|$)|\\\\!+(?!\" + re.src_ZCc + \"|[!]|$)|\\\\?(?!\" + re.src_ZCc + \"|[?]|$))+|\\\\/)?\";\n re.src_email_name = '[\\\\-;:&=\\\\+\\\\$,\\\\.a-zA-Z0-9_][\\\\-;:&=\\\\+\\\\$,\\\\\"\\\\.a-zA-Z0-9_]*';\n re.src_xn = \"xn--[a-z0-9\\\\-]{1,59}\";\n re.src_domain_root = // Allow letters & digits (http://test1)\n \"(?:\" + re.src_xn + \"|\" + re.src_pseudo_letter + \"{1,63})\";\n re.src_domain = \"(?:\" + re.src_xn + \"|(?:\" + re.src_pseudo_letter + \")|(?:\" + re.src_pseudo_letter + \"(?:-|\" + re.src_pseudo_letter + \"){0,61}\" + re.src_pseudo_letter + \"))\";\n re.src_host = \"(?:(?:(?:(?:\" + re.src_domain + \")\\\\.)*\" + re.src_domain + \"))\";\n re.tpl_host_fuzzy = \"(?:\" + re.src_ip4 + \"|(?:(?:(?:\" + re.src_domain + \")\\\\.)+(?:%TLDS%)))\";\n re.tpl_host_no_ip_fuzzy = \"(?:(?:(?:\" + re.src_domain + \")\\\\.)+(?:%TLDS%))\";\n re.src_host_strict = re.src_host + re.src_host_terminator;\n re.tpl_host_fuzzy_strict = re.tpl_host_fuzzy + re.src_host_terminator;\n re.src_host_port_strict = re.src_host + re.src_port + re.src_host_terminator;\n re.tpl_host_port_fuzzy_strict = re.tpl_host_fuzzy + re.src_port + re.src_host_terminator;\n re.tpl_host_port_no_ip_fuzzy_strict = re.tpl_host_no_ip_fuzzy + re.src_port + re.src_host_terminator;\n re.tpl_host_fuzzy_test = \"localhost|www\\\\.|\\\\.\\\\d{1,3}\\\\.|(?:\\\\.(?:%TLDS%)(?:\" + re.src_ZPCc + \"|>|$))\";\n re.tpl_email_fuzzy = \"(^|\" + text_separators + '|\"|\\\\(|' + re.src_ZCc + \")(\" + re.src_email_name + \"@\" + re.tpl_host_fuzzy_strict + \")\";\n re.tpl_link_fuzzy = // Fuzzy link can't be prepended with .:/\\- and non punctuation.\n // but can start with > (markdown blockquote)\n \"(^|(?![.:/\\\\-_@])(?:[$+<=>^`||]|\" + re.src_ZPCc + \"))((?![$+<=>^`||])\" + re.tpl_host_port_fuzzy_strict + re.src_path + \")\";\n re.tpl_link_no_ip_fuzzy = // Fuzzy link can't be prepended with .:/\\- and non punctuation.\n // but can start with > (markdown blockquote)\n \"(^|(?![.:/\\\\-_@])(?:[$+<=>^`||]|\" + re.src_ZPCc + \"))((?![$+<=>^`||])\" + re.tpl_host_port_no_ip_fuzzy_strict + re.src_path + \")\";\n return re;\n}\n\n// node_modules/.pnpm/linkify-it@5.0.0/node_modules/linkify-it/index.mjs\nfunction assign2(obj) {\n const sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source2) {\n if (!source2) {\n return;\n }\n Object.keys(source2).forEach(function(key) {\n obj[key] = source2[key];\n });\n });\n return obj;\n}\nfunction _class2(obj) {\n return Object.prototype.toString.call(obj);\n}\nfunction isString2(obj) {\n return _class2(obj) === \"[object String]\";\n}\nfunction isObject(obj) {\n return _class2(obj) === \"[object Object]\";\n}\nfunction isRegExp(obj) {\n return _class2(obj) === \"[object RegExp]\";\n}\nfunction isFunction(obj) {\n return _class2(obj) === \"[object Function]\";\n}\nfunction escapeRE2(str) {\n return str.replace(/[.?*+^$[\\]\\\\(){}|-]/g, \"\\\\$&\");\n}\nvar defaultOptions = {\n fuzzyLink: true,\n fuzzyEmail: true,\n fuzzyIP: false\n};\nfunction isOptionsObj(obj) {\n return Object.keys(obj || {}).reduce(function(acc, k) {\n return acc || defaultOptions.hasOwnProperty(k);\n }, false);\n}\nvar defaultSchemas = {\n \"http:\": {\n validate: function(text2, pos, self) {\n const tail = text2.slice(pos);\n if (!self.re.http) {\n self.re.http = new RegExp(\n \"^\\\\/\\\\/\" + self.re.src_auth + self.re.src_host_port_strict + self.re.src_path,\n \"i\"\n );\n }\n if (self.re.http.test(tail)) {\n return tail.match(self.re.http)[0].length;\n }\n return 0;\n }\n },\n \"https:\": \"http:\",\n \"ftp:\": \"http:\",\n \"//\": {\n validate: function(text2, pos, self) {\n const tail = text2.slice(pos);\n if (!self.re.no_http) {\n self.re.no_http = new RegExp(\n \"^\" + self.re.src_auth + // Don't allow single-level domains, because of false positives like '//test'\n // with code comments\n \"(?:localhost|(?:(?:\" + self.re.src_domain + \")\\\\.)+\" + self.re.src_domain_root + \")\" + self.re.src_port + self.re.src_host_terminator + self.re.src_path,\n \"i\"\n );\n }\n if (self.re.no_http.test(tail)) {\n if (pos >= 3 && text2[pos - 3] === \":\") {\n return 0;\n }\n if (pos >= 3 && text2[pos - 3] === \"/\") {\n return 0;\n }\n return tail.match(self.re.no_http)[0].length;\n }\n return 0;\n }\n },\n \"mailto:\": {\n validate: function(text2, pos, self) {\n const tail = text2.slice(pos);\n if (!self.re.mailto) {\n self.re.mailto = new RegExp(\n \"^\" + self.re.src_email_name + \"@\" + self.re.src_host_strict,\n \"i\"\n );\n }\n if (self.re.mailto.test(tail)) {\n return tail.match(self.re.mailto)[0].length;\n }\n return 0;\n }\n }\n};\nvar tlds_2ch_src_re = \"a[cdefgilmnoqrstuwxz]|b[abdefghijmnorstvwyz]|c[acdfghiklmnoruvwxyz]|d[ejkmoz]|e[cegrstu]|f[ijkmor]|g[abdefghilmnpqrstuwy]|h[kmnrtu]|i[delmnoqrst]|j[emop]|k[eghimnprwyz]|l[abcikrstuvy]|m[acdeghklmnopqrstuvwxyz]|n[acefgilopruz]|om|p[aefghklmnrstwy]|qa|r[eosuw]|s[abcdeghijklmnortuvxyz]|t[cdfghjklmnortvwz]|u[agksyz]|v[aceginu]|w[fs]|y[et]|z[amw]\";\nvar tlds_default = \"biz|com|edu|gov|net|org|pro|web|xxx|aero|asia|coop|info|museum|name|shop|рф\".split(\"|\");\nfunction resetScanCache(self) {\n self.__index__ = -1;\n self.__text_cache__ = \"\";\n}\nfunction createValidator(re) {\n return function(text2, pos) {\n const tail = text2.slice(pos);\n if (re.test(tail)) {\n return tail.match(re)[0].length;\n }\n return 0;\n };\n}\nfunction createNormalizer() {\n return function(match2, self) {\n self.normalize(match2);\n };\n}\nfunction compile(self) {\n const re = self.re = re_default(self.__opts__);\n const tlds2 = self.__tlds__.slice();\n self.onCompile();\n if (!self.__tlds_replaced__) {\n tlds2.push(tlds_2ch_src_re);\n }\n tlds2.push(re.src_xn);\n re.src_tlds = tlds2.join(\"|\");\n function untpl(tpl) {\n return tpl.replace(\"%TLDS%\", re.src_tlds);\n }\n re.email_fuzzy = RegExp(untpl(re.tpl_email_fuzzy), \"i\");\n re.link_fuzzy = RegExp(untpl(re.tpl_link_fuzzy), \"i\");\n re.link_no_ip_fuzzy = RegExp(untpl(re.tpl_link_no_ip_fuzzy), \"i\");\n re.host_fuzzy_test = RegExp(untpl(re.tpl_host_fuzzy_test), \"i\");\n const aliases = [];\n self.__compiled__ = {};\n function schemaError(name, val) {\n throw new Error('(LinkifyIt) Invalid schema \"' + name + '\": ' + val);\n }\n Object.keys(self.__schemas__).forEach(function(name) {\n const val = self.__schemas__[name];\n if (val === null) {\n return;\n }\n const compiled = { validate: null, link: null };\n self.__compiled__[name] = compiled;\n if (isObject(val)) {\n if (isRegExp(val.validate)) {\n compiled.validate = createValidator(val.validate);\n } else if (isFunction(val.validate)) {\n compiled.validate = val.validate;\n } else {\n schemaError(name, val);\n }\n if (isFunction(val.normalize)) {\n compiled.normalize = val.normalize;\n } else if (!val.normalize) {\n compiled.normalize = createNormalizer();\n } else {\n schemaError(name, val);\n }\n return;\n }\n if (isString2(val)) {\n aliases.push(name);\n return;\n }\n schemaError(name, val);\n });\n aliases.forEach(function(alias) {\n if (!self.__compiled__[self.__schemas__[alias]]) {\n return;\n }\n self.__compiled__[alias].validate = self.__compiled__[self.__schemas__[alias]].validate;\n self.__compiled__[alias].normalize = self.__compiled__[self.__schemas__[alias]].normalize;\n });\n self.__compiled__[\"\"] = { validate: null, normalize: createNormalizer() };\n const slist = Object.keys(self.__compiled__).filter(function(name) {\n return name.length > 0 && self.__compiled__[name];\n }).map(escapeRE2).join(\"|\");\n self.re.schema_test = RegExp(\"(^|(?!_)(?:[><|]|\" + re.src_ZPCc + \"))(\" + slist + \")\", \"i\");\n self.re.schema_search = RegExp(\"(^|(?!_)(?:[><|]|\" + re.src_ZPCc + \"))(\" + slist + \")\", \"ig\");\n self.re.schema_at_start = RegExp(\"^\" + self.re.schema_search.source, \"i\");\n self.re.pretest = RegExp(\n \"(\" + self.re.schema_test.source + \")|(\" + self.re.host_fuzzy_test.source + \")|@\",\n \"i\"\n );\n resetScanCache(self);\n}\nfunction Match(self, shift) {\n const start = self.__index__;\n const end = self.__last_index__;\n const text2 = self.__text_cache__.slice(start, end);\n this.schema = self.__schema__.toLowerCase();\n this.index = start + shift;\n this.lastIndex = end + shift;\n this.raw = text2;\n this.text = text2;\n this.url = text2;\n}\nfunction createMatch(self, shift) {\n const match2 = new Match(self, shift);\n self.__compiled__[match2.schema].normalize(match2, self);\n return match2;\n}\nfunction LinkifyIt(schemas, options) {\n if (!(this instanceof LinkifyIt)) {\n return new LinkifyIt(schemas, options);\n }\n if (!options) {\n if (isOptionsObj(schemas)) {\n options = schemas;\n schemas = {};\n }\n }\n this.__opts__ = assign2({}, defaultOptions, options);\n this.__index__ = -1;\n this.__last_index__ = -1;\n this.__schema__ = \"\";\n this.__text_cache__ = \"\";\n this.__schemas__ = assign2({}, defaultSchemas, schemas);\n this.__compiled__ = {};\n this.__tlds__ = tlds_default;\n this.__tlds_replaced__ = false;\n this.re = {};\n compile(this);\n}\nLinkifyIt.prototype.add = function add(schema, definition) {\n this.__schemas__[schema] = definition;\n compile(this);\n return this;\n};\nLinkifyIt.prototype.set = function set(options) {\n this.__opts__ = assign2(this.__opts__, options);\n return this;\n};\nLinkifyIt.prototype.test = function test(text2) {\n this.__text_cache__ = text2;\n this.__index__ = -1;\n if (!text2.length) {\n return false;\n }\n let m, ml, me, len, shift, next, re, tld_pos, at_pos;\n if (this.re.schema_test.test(text2)) {\n re = this.re.schema_search;\n re.lastIndex = 0;\n while ((m = re.exec(text2)) !== null) {\n len = this.testSchemaAt(text2, m[2], re.lastIndex);\n if (len) {\n this.__schema__ = m[2];\n this.__index__ = m.index + m[1].length;\n this.__last_index__ = m.index + m[0].length + len;\n break;\n }\n }\n }\n if (this.__opts__.fuzzyLink && this.__compiled__[\"http:\"]) {\n tld_pos = text2.search(this.re.host_fuzzy_test);\n if (tld_pos >= 0) {\n if (this.__index__ < 0 || tld_pos < this.__index__) {\n if ((ml = text2.match(this.__opts__.fuzzyIP ? this.re.link_fuzzy : this.re.link_no_ip_fuzzy)) !== null) {\n shift = ml.index + ml[1].length;\n if (this.__index__ < 0 || shift < this.__index__) {\n this.__schema__ = \"\";\n this.__index__ = shift;\n this.__last_index__ = ml.index + ml[0].length;\n }\n }\n }\n }\n }\n if (this.__opts__.fuzzyEmail && this.__compiled__[\"mailto:\"]) {\n at_pos = text2.indexOf(\"@\");\n if (at_pos >= 0) {\n if ((me = text2.match(this.re.email_fuzzy)) !== null) {\n shift = me.index + me[1].length;\n next = me.index + me[0].length;\n if (this.__index__ < 0 || shift < this.__index__ || shift === this.__index__ && next > this.__last_index__) {\n this.__schema__ = \"mailto:\";\n this.__index__ = shift;\n this.__last_index__ = next;\n }\n }\n }\n }\n return this.__index__ >= 0;\n};\nLinkifyIt.prototype.pretest = function pretest(text2) {\n return this.re.pretest.test(text2);\n};\nLinkifyIt.prototype.testSchemaAt = function testSchemaAt(text2, schema, pos) {\n if (!this.__compiled__[schema.toLowerCase()]) {\n return 0;\n }\n return this.__compiled__[schema.toLowerCase()].validate(text2, pos, this);\n};\nLinkifyIt.prototype.match = function match(text2) {\n const result = [];\n let shift = 0;\n if (this.__index__ >= 0 && this.__text_cache__ === text2) {\n result.push(createMatch(this, shift));\n shift = this.__last_index__;\n }\n let tail = shift ? text2.slice(shift) : text2;\n while (this.test(tail)) {\n result.push(createMatch(this, shift));\n tail = tail.slice(this.__last_index__);\n shift += this.__last_index__;\n }\n if (result.length) {\n return result;\n }\n return null;\n};\nLinkifyIt.prototype.matchAtStart = function matchAtStart(text2) {\n this.__text_cache__ = text2;\n this.__index__ = -1;\n if (!text2.length) return null;\n const m = this.re.schema_at_start.exec(text2);\n if (!m) return null;\n const len = this.testSchemaAt(text2, m[2], m[0].length);\n if (!len) return null;\n this.__schema__ = m[2];\n this.__index__ = m.index + m[1].length;\n this.__last_index__ = m.index + m[0].length + len;\n return createMatch(this, 0);\n};\nLinkifyIt.prototype.tlds = function tlds(list2, keepOld) {\n list2 = Array.isArray(list2) ? list2 : [list2];\n if (!keepOld) {\n this.__tlds__ = list2.slice();\n this.__tlds_replaced__ = true;\n compile(this);\n return this;\n }\n this.__tlds__ = this.__tlds__.concat(list2).sort().filter(function(el, idx, arr) {\n return el !== arr[idx - 1];\n }).reverse();\n compile(this);\n return this;\n};\nLinkifyIt.prototype.normalize = function normalize2(match2) {\n if (!match2.schema) {\n match2.url = \"http://\" + match2.url;\n }\n if (match2.schema === \"mailto:\" && !/^mailto:/i.test(match2.url)) {\n match2.url = \"mailto:\" + match2.url;\n }\n};\nLinkifyIt.prototype.onCompile = function onCompile() {\n};\nvar linkify_it_default = LinkifyIt;\n\n// node_modules/.pnpm/punycode.js@2.3.1/node_modules/punycode.js/punycode.es6.js\nvar maxInt = 2147483647;\nvar base = 36;\nvar tMin = 1;\nvar tMax = 26;\nvar skew = 38;\nvar damp = 700;\nvar initialBias = 72;\nvar initialN = 128;\nvar delimiter = \"-\";\nvar regexPunycode = /^xn--/;\nvar regexNonASCII = /[^\\0-\\x7F]/;\nvar regexSeparators = /[\\x2E\\u3002\\uFF0E\\uFF61]/g;\nvar errors = {\n \"overflow\": \"Overflow: input needs wider integers to process\",\n \"not-basic\": \"Illegal input >= 0x80 (not a basic code point)\",\n \"invalid-input\": \"Invalid input\"\n};\nvar baseMinusTMin = base - tMin;\nvar floor = Math.floor;\nvar stringFromCharCode = String.fromCharCode;\nfunction error(type) {\n throw new RangeError(errors[type]);\n}\nfunction map(array, callback) {\n const result = [];\n let length = array.length;\n while (length--) {\n result[length] = callback(array[length]);\n }\n return result;\n}\nfunction mapDomain(domain, callback) {\n const parts = domain.split(\"@\");\n let result = \"\";\n if (parts.length > 1) {\n result = parts[0] + \"@\";\n domain = parts[1];\n }\n domain = domain.replace(regexSeparators, \".\");\n const labels = domain.split(\".\");\n const encoded = map(labels, callback).join(\".\");\n return result + encoded;\n}\nfunction ucs2decode(string) {\n const output = [];\n let counter = 0;\n const length = string.length;\n while (counter < length) {\n const value = string.charCodeAt(counter++);\n if (value >= 55296 && value <= 56319 && counter < length) {\n const extra = string.charCodeAt(counter++);\n if ((extra & 64512) == 56320) {\n output.push(((value & 1023) << 10) + (extra & 1023) + 65536);\n } else {\n output.push(value);\n counter--;\n }\n } else {\n output.push(value);\n }\n }\n return output;\n}\nvar ucs2encode = (codePoints) => String.fromCodePoint(...codePoints);\nvar basicToDigit = function(codePoint) {\n if (codePoint >= 48 && codePoint < 58) {\n return 26 + (codePoint - 48);\n }\n if (codePoint >= 65 && codePoint < 91) {\n return codePoint - 65;\n }\n if (codePoint >= 97 && codePoint < 123) {\n return codePoint - 97;\n }\n return base;\n};\nvar digitToBasic = function(digit, flag) {\n return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);\n};\nvar adapt = function(delta, numPoints, firstTime) {\n let k = 0;\n delta = firstTime ? floor(delta / damp) : delta >> 1;\n delta += floor(delta / numPoints);\n for (; delta > baseMinusTMin * tMax >> 1; k += base) {\n delta = floor(delta / baseMinusTMin);\n }\n return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));\n};\nvar decode2 = function(input) {\n const output = [];\n const inputLength = input.length;\n let i = 0;\n let n = initialN;\n let bias = initialBias;\n let basic = input.lastIndexOf(delimiter);\n if (basic < 0) {\n basic = 0;\n }\n for (let j = 0; j < basic; ++j) {\n if (input.charCodeAt(j) >= 128) {\n error(\"not-basic\");\n }\n output.push(input.charCodeAt(j));\n }\n for (let index = basic > 0 ? basic + 1 : 0; index < inputLength; ) {\n const oldi = i;\n for (let w = 1, k = base; ; k += base) {\n if (index >= inputLength) {\n error(\"invalid-input\");\n }\n const digit = basicToDigit(input.charCodeAt(index++));\n if (digit >= base) {\n error(\"invalid-input\");\n }\n if (digit > floor((maxInt - i) / w)) {\n error(\"overflow\");\n }\n i += digit * w;\n const t = k <= bias ? tMin : k >= bias + tMax ? tMax : k - bias;\n if (digit < t) {\n break;\n }\n const baseMinusT = base - t;\n if (w > floor(maxInt / baseMinusT)) {\n error(\"overflow\");\n }\n w *= baseMinusT;\n }\n const out = output.length + 1;\n bias = adapt(i - oldi, out, oldi == 0);\n if (floor(i / out) > maxInt - n) {\n error(\"overflow\");\n }\n n += floor(i / out);\n i %= out;\n output.splice(i++, 0, n);\n }\n return String.fromCodePoint(...output);\n};\nvar encode2 = function(input) {\n const output = [];\n input = ucs2decode(input);\n const inputLength = input.length;\n let n = initialN;\n let delta = 0;\n let bias = initialBias;\n for (const currentValue of input) {\n if (currentValue < 128) {\n output.push(stringFromCharCode(currentValue));\n }\n }\n const basicLength = output.length;\n let handledCPCount = basicLength;\n if (basicLength) {\n output.push(delimiter);\n }\n while (handledCPCount < inputLength) {\n let m = maxInt;\n for (const currentValue of input) {\n if (currentValue >= n && currentValue < m) {\n m = currentValue;\n }\n }\n const handledCPCountPlusOne = handledCPCount + 1;\n if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {\n error(\"overflow\");\n }\n delta += (m - n) * handledCPCountPlusOne;\n n = m;\n for (const currentValue of input) {\n if (currentValue < n && ++delta > maxInt) {\n error(\"overflow\");\n }\n if (currentValue === n) {\n let q = delta;\n for (let k = base; ; k += base) {\n const t = k <= bias ? tMin : k >= bias + tMax ? tMax : k - bias;\n if (q < t) {\n break;\n }\n const qMinusT = q - t;\n const baseMinusT = base - t;\n output.push(\n stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))\n );\n q = floor(qMinusT / baseMinusT);\n }\n output.push(stringFromCharCode(digitToBasic(q, 0)));\n bias = adapt(delta, handledCPCountPlusOne, handledCPCount === basicLength);\n delta = 0;\n ++handledCPCount;\n }\n }\n ++delta;\n ++n;\n }\n return output.join(\"\");\n};\nvar toUnicode = function(input) {\n return mapDomain(input, function(string) {\n return regexPunycode.test(string) ? decode2(string.slice(4).toLowerCase()) : string;\n });\n};\nvar toASCII = function(input) {\n return mapDomain(input, function(string) {\n return regexNonASCII.test(string) ? \"xn--\" + encode2(string) : string;\n });\n};\nvar punycode = {\n /**\n * A string representing the current Punycode.js version number.\n * @memberOf punycode\n * @type String\n */\n \"version\": \"2.3.1\",\n /**\n * An object of methods to convert from JavaScript's internal character\n * representation (UCS-2) to Unicode code points, and back.\n * @see \n * @memberOf punycode\n * @type Object\n */\n \"ucs2\": {\n \"decode\": ucs2decode,\n \"encode\": ucs2encode\n },\n \"decode\": decode2,\n \"encode\": encode2,\n \"toASCII\": toASCII,\n \"toUnicode\": toUnicode\n};\nvar punycode_es6_default = punycode;\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/presets/default.mjs\nvar default_default = {\n options: {\n // Enable HTML tags in source\n html: false,\n // Use '/' to close single tags (
)\n xhtmlOut: false,\n // Convert '\\n' in paragraphs into
\n breaks: false,\n // CSS language prefix for fenced blocks\n langPrefix: \"language-\",\n // autoconvert URL-like texts to links\n linkify: false,\n // Enable some language-neutral replacements + quotes beautification\n typographer: false,\n // Double + single quotes replacement pairs, when typographer enabled,\n // and smartquotes on. Could be either a String or an Array.\n //\n // For example, you can use '«»„“' for Russian, '„“‚‘' for German,\n // and ['«\\xA0', '\\xA0»', '‹\\xA0', '\\xA0›'] for French (including nbsp).\n quotes: \"“”‘’\",\n /* “”‘’ */\n // Highlighter function. Should return escaped HTML,\n // or '' if the source string is not changed and should be escaped externaly.\n // If result starts with )\n xhtmlOut: false,\n // Convert '\\n' in paragraphs into
\n breaks: false,\n // CSS language prefix for fenced blocks\n langPrefix: \"language-\",\n // autoconvert URL-like texts to links\n linkify: false,\n // Enable some language-neutral replacements + quotes beautification\n typographer: false,\n // Double + single quotes replacement pairs, when typographer enabled,\n // and smartquotes on. Could be either a String or an Array.\n //\n // For example, you can use '«»„“' for Russian, '„“‚‘' for German,\n // and ['«\\xA0', '\\xA0»', '‹\\xA0', '\\xA0›'] for French (including nbsp).\n quotes: \"“”‘’\",\n /* “”‘’ */\n // Highlighter function. Should return escaped HTML,\n // or '' if the source string is not changed and should be escaped externaly.\n // If result starts with )\n xhtmlOut: true,\n // Convert '\\n' in paragraphs into
\n breaks: false,\n // CSS language prefix for fenced blocks\n langPrefix: \"language-\",\n // autoconvert URL-like texts to links\n linkify: false,\n // Enable some language-neutral replacements + quotes beautification\n typographer: false,\n // Double + single quotes replacement pairs, when typographer enabled,\n // and smartquotes on. Could be either a String or an Array.\n //\n // For example, you can use '«»„“' for Russian, '„“‚‘' for German,\n // and ['«\\xA0', '\\xA0»', '‹\\xA0', '\\xA0›'] for French (including nbsp).\n quotes: \"“”‘’\",\n /* “”‘’ */\n // Highlighter function. Should return escaped HTML,\n // or '' if the source string is not changed and should be escaped externaly.\n // If result starts with = 0) {\n try {\n parsed.hostname = punycode_es6_default.toASCII(parsed.hostname);\n } catch (er) {\n }\n }\n }\n return encode_default(format(parsed));\n}\nfunction normalizeLinkText(url) {\n const parsed = parse_default(url, true);\n if (parsed.hostname) {\n if (!parsed.protocol || RECODE_HOSTNAME_FOR.indexOf(parsed.protocol) >= 0) {\n try {\n parsed.hostname = punycode_es6_default.toUnicode(parsed.hostname);\n } catch (er) {\n }\n }\n }\n return decode_default(format(parsed), decode_default.defaultChars + \"%\");\n}\nfunction MarkdownIt(presetName, options) {\n if (!(this instanceof MarkdownIt)) {\n return new MarkdownIt(presetName, options);\n }\n if (!options) {\n if (!isString(presetName)) {\n options = presetName || {};\n presetName = \"default\";\n }\n }\n this.inline = new parser_inline_default();\n this.block = new parser_block_default();\n this.core = new parser_core_default();\n this.renderer = new renderer_default();\n this.linkify = new linkify_it_default();\n this.validateLink = validateLink;\n this.normalizeLink = normalizeLink;\n this.normalizeLinkText = normalizeLinkText;\n this.utils = utils_exports;\n this.helpers = assign({}, helpers_exports);\n this.options = {};\n this.configure(presetName);\n if (options) {\n this.set(options);\n }\n}\nMarkdownIt.prototype.set = function(options) {\n assign(this.options, options);\n return this;\n};\nMarkdownIt.prototype.configure = function(presets) {\n const self = this;\n if (isString(presets)) {\n const presetName = presets;\n presets = config[presetName];\n if (!presets) {\n throw new Error('Wrong `markdown-it` preset \"' + presetName + '\", check name');\n }\n }\n if (!presets) {\n throw new Error(\"Wrong `markdown-it` preset, can't be empty\");\n }\n if (presets.options) {\n self.set(presets.options);\n }\n if (presets.components) {\n Object.keys(presets.components).forEach(function(name) {\n if (presets.components[name].rules) {\n self[name].ruler.enableOnly(presets.components[name].rules);\n }\n if (presets.components[name].rules2) {\n self[name].ruler2.enableOnly(presets.components[name].rules2);\n }\n });\n }\n return this;\n};\nMarkdownIt.prototype.enable = function(list2, ignoreInvalid) {\n let result = [];\n if (!Array.isArray(list2)) {\n list2 = [list2];\n }\n [\"core\", \"block\", \"inline\"].forEach(function(chain) {\n result = result.concat(this[chain].ruler.enable(list2, true));\n }, this);\n result = result.concat(this.inline.ruler2.enable(list2, true));\n const missed = list2.filter(function(name) {\n return result.indexOf(name) < 0;\n });\n if (missed.length && !ignoreInvalid) {\n throw new Error(\"MarkdownIt. Failed to enable unknown rule(s): \" + missed);\n }\n return this;\n};\nMarkdownIt.prototype.disable = function(list2, ignoreInvalid) {\n let result = [];\n if (!Array.isArray(list2)) {\n list2 = [list2];\n }\n [\"core\", \"block\", \"inline\"].forEach(function(chain) {\n result = result.concat(this[chain].ruler.disable(list2, true));\n }, this);\n result = result.concat(this.inline.ruler2.disable(list2, true));\n const missed = list2.filter(function(name) {\n return result.indexOf(name) < 0;\n });\n if (missed.length && !ignoreInvalid) {\n throw new Error(\"MarkdownIt. Failed to disable unknown rule(s): \" + missed);\n }\n return this;\n};\nMarkdownIt.prototype.use = function(plugin) {\n const args = [this].concat(Array.prototype.slice.call(arguments, 1));\n plugin.apply(plugin, args);\n return this;\n};\nMarkdownIt.prototype.parse = function(src, env) {\n if (typeof src !== \"string\") {\n throw new Error(\"Input data should be a String\");\n }\n const state = new this.core.State(src, this, env);\n this.core.process(state);\n return state.tokens;\n};\nMarkdownIt.prototype.render = function(src, env) {\n env = env || {};\n return this.renderer.render(this.parse(src, env), this.options, env);\n};\nMarkdownIt.prototype.parseInline = function(src, env) {\n const state = new this.core.State(src, this, env);\n state.inlineMode = true;\n this.core.process(state);\n return state.tokens;\n};\nMarkdownIt.prototype.renderInline = function(src, env) {\n env = env || {};\n return this.renderer.render(this.parseInline(src, env), this.options, env);\n};\nvar lib_default = MarkdownIt;\n\n// apps/ecosystem-certifier/fixtures/positive/markdown-it-entry.ts\nvar md = new lib_default({\n linkify: true\n});\nvar source = Host.v1.document.get(\"text/markdown-case\");\nvar tokens = md.parse(source, {});\nvar links = md.render(source).match(/
token.type),\n tokenCount: tokens.length,\n linkCount: links\n};\nexport {\n markdown_it_entry_default as default\n};\n", + "sourceMap": "{\"mappings\":\"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AQ,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,YAAY,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,aAAa,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,aAAa,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,IAAG,QAAQ,GAAE,CAAC,IAAG,SAAS,GAAE,CAAC,IAAG,UAAU,GAAE,CAAC,IAAG,SAAS,GAAE,CAAC,KAAI,QAAQ,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,IAAG,SAAS,GAAE,CAAC,GAAE,kBAAkB,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,oBAAoB,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,IAAG,aAAa,GAAE,CAAC,KAAI,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,WAAW,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,MAAM,GAAE,CAAC,GAAE,MAAM,GAAE,CAAC,GAAE,MAAM,GAAE,CAAC,GAAE,WAAW,GAAE,CAAC,GAAE,MAAM,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,WAAW,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,MAAM,GAAE,CAAC,GAAE,MAAM,GAAE,CAAC,GAAE,MAAM,GAAE,CAAC,GAAE,WAAW,GAAE,CAAC,GAAE,MAAM,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,YAAY,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,WAAW,GAAE,CAAC,IAAG,UAAU,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,eAAe,GAAE,CAAC,IAAG,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAA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AC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CA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\",\"names\":[\"fromCodePoint\",\"code\",\"regex_default\",\"regex_default\",\"regex_default\",\"regex_default\",\"regex_default\",\"regex_default\",\"_a\",\"CharCodes\",\"BinTrieFlags\",\"code\",\"EntityDecoderState\",\"DecodingMode\",\"errors\",\"base\",\"_a\",\"map\",\"escape\",\"match\",\"EntityLevel\",\"EncodingMode\",\"source\",\"fromCodePoint\",\"match\",\"code\",\"entity\",\"regex_default\",\"code\",\"code\",\"tokens\",\"list\",\"md\",\"tokens\",\"tokens\",\"text\",\"links\",\"match\",\"tokens\",\"text\",\"tokens\",\"md\",\"tokens\",\"code\",\"nextLine\",\"pos\",\"max\",\"_rules\",\"md\",\"md\",\"linkify\",\"match\",\"link\",\"escape\",\"postProcess\",\"code\",\"code\",\"tokens\",\"isLinkOpen\",\"isLinkClose\",\"match\",\"match\",\"code\",\"fromCodePoint\",\"tokens\",\"_rules\",\"linkify\",\"escape\",\"_rules2\",\"md\",\"regex_default\",\"assign\",\"source\",\"_class\",\"isString\",\"escapeRE\",\"text\",\"match\",\"tlds\",\"list\",\"normalize\",\"decode\",\"encode\",\"list\"],\"sources\":[\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/common/utils.mjs\",\"../node_modules/.pnpm/mdurl@2.0.0/node_modules/mdurl/index.mjs\",\"../node_modules/.pnpm/mdurl@2.0.0/node_modules/mdurl/lib/decode.mjs\",\"../node_modules/.pnpm/mdurl@2.0.0/node_modules/mdurl/lib/encode.mjs\",\"../node_modules/.pnpm/mdurl@2.0.0/node_modules/mdurl/lib/format.mjs\",\"../node_modules/.pnpm/mdurl@2.0.0/node_modules/mdurl/lib/parse.mjs\",\"../node_modules/.pnpm/uc.micro@2.1.0/node_modules/uc.micro/index.mjs\",\"../node_modules/.pnpm/uc.micro@2.1.0/node_modules/uc.micro/properties/Any/regex.mjs\",\"../node_modules/.pnpm/uc.micro@2.1.0/node_modules/uc.micro/categories/Cc/regex.mjs\",\"../node_modules/.pnpm/uc.micro@2.1.0/node_modules/uc.micro/categories/Cf/regex.mjs\",\"../node_modules/.pnpm/uc.micro@2.1.0/node_modules/uc.micro/categories/P/regex.mjs\",\"../node_modules/.pnpm/uc.micro@2.1.0/node_modules/uc.micro/categories/S/regex.mjs\",\"../node_modules/.pnpm/uc.micro@2.1.0/node_modules/uc.micro/categories/Z/regex.mjs\",\"https://raw.githubusercontent.com/fb55/entities/61afd4701eaa736978b13c7351cd3de9a96b04bc/src/generated/decode-data-html.ts\",\"https://raw.githubusercontent.com/fb55/entities/61afd4701eaa736978b13c7351cd3de9a96b04bc/src/generated/decode-data-xml.ts\",\"https://raw.githubusercontent.com/fb55/entities/61afd4701eaa736978b13c7351cd3de9a96b04bc/src/decode_codepoint.ts\",\"https://raw.githubusercontent.com/fb55/entities/61afd4701eaa736978b13c7351cd3de9a96b04bc/src/decode.ts\",\"https://raw.githubusercontent.com/fb55/entities/61afd4701eaa736978b13c7351cd3de9a96b04bc/src/generated/encode-html.ts\",\"https://raw.githubusercontent.com/fb55/entities/61afd4701eaa736978b13c7351cd3de9a96b04bc/src/escape.ts\",\"https://raw.githubusercontent.com/fb55/entities/61afd4701eaa736978b13c7351cd3de9a96b04bc/src/index.ts\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/helpers/index.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/helpers/parse_link_label.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/helpers/parse_link_destination.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/helpers/parse_link_title.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/renderer.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/ruler.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/token.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_core/state_core.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_core/normalize.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_core/block.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_core/inline.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_core/linkify.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_core/replacements.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_core/smartquotes.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_core/text_join.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/parser_core.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/state_block.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/table.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/code.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/fence.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/blockquote.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/hr.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/list.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/reference.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/common/html_blocks.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/common/html_re.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/html_block.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/heading.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/lheading.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/paragraph.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/parser_block.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/state_inline.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/text.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/linkify.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/newline.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/escape.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/backticks.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/strikethrough.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/emphasis.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/link.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/image.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/autolink.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/html_inline.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/entity.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/balance_pairs.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/fragments_join.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/parser_inline.mjs\",\"../node_modules/.pnpm/linkify-it@5.0.0/node_modules/linkify-it/lib/re.mjs\",\"../node_modules/.pnpm/linkify-it@5.0.0/node_modules/linkify-it/index.mjs\",\"../node_modules/.pnpm/punycode.js@2.3.1/node_modules/punycode.js/punycode.es6.js\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/presets/default.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/presets/zero.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/presets/commonmark.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/index.mjs\",\"../apps/ecosystem-certifier/fixtures/positive/markdown-it-entry.ts\"],\"sourcesContent\":[\"// Utilities\\n//\\n\\nimport * as mdurl from 'mdurl'\\nimport * as ucmicro from 'uc.micro'\\nimport { decodeHTML } from 'entities'\\n\\nfunction _class (obj) { return Object.prototype.toString.call(obj) }\\n\\nfunction isString (obj) { return _class(obj) === '[object String]' }\\n\\nconst _hasOwnProperty = Object.prototype.hasOwnProperty\\n\\nfunction has (object, key) {\\n return _hasOwnProperty.call(object, key)\\n}\\n\\n// Merge objects\\n//\\nfunction assign (obj /* from1, from2, from3, ... */) {\\n const sources = Array.prototype.slice.call(arguments, 1)\\n\\n sources.forEach(function (source) {\\n if (!source) { return }\\n\\n if (typeof source !== 'object') {\\n throw new TypeError(source + 'must be object')\\n }\\n\\n Object.keys(source).forEach(function (key) {\\n obj[key] = source[key]\\n })\\n })\\n\\n return obj\\n}\\n\\n// Remove element from array and put another array at those position.\\n// Useful for some operations with tokens\\nfunction arrayReplaceAt (src, pos, newElements) {\\n return [].concat(src.slice(0, pos), newElements, src.slice(pos + 1))\\n}\\n\\nfunction isValidEntityCode (c) {\\n /* eslint no-bitwise:0 */\\n // broken sequence\\n if (c >= 0xD800 && c <= 0xDFFF) { return false }\\n // never used\\n if (c >= 0xFDD0 && c <= 0xFDEF) { return false }\\n if ((c & 0xFFFF) === 0xFFFF || (c & 0xFFFF) === 0xFFFE) { return false }\\n // control codes\\n if (c >= 0x00 && c <= 0x08) { return false }\\n if (c === 0x0B) { return false }\\n if (c >= 0x0E && c <= 0x1F) { return false }\\n if (c >= 0x7F && c <= 0x9F) { return false }\\n // out of range\\n if (c > 0x10FFFF) { return false }\\n return true\\n}\\n\\nfunction fromCodePoint (c) {\\n /* eslint no-bitwise:0 */\\n if (c > 0xffff) {\\n c -= 0x10000\\n const surrogate1 = 0xd800 + (c >> 10)\\n const surrogate2 = 0xdc00 + (c & 0x3ff)\\n\\n return String.fromCharCode(surrogate1, surrogate2)\\n }\\n return String.fromCharCode(c)\\n}\\n\\nconst UNESCAPE_MD_RE = /\\\\\\\\([!\\\"#$%&'()*+,\\\\-./:;<=>?@[\\\\\\\\\\\\]^_`{|}~])/g\\nconst ENTITY_RE = /&([a-z#][a-z0-9]{1,31});/gi\\nconst UNESCAPE_ALL_RE = new RegExp(UNESCAPE_MD_RE.source + '|' + ENTITY_RE.source, 'gi')\\n\\nconst DIGITAL_ENTITY_TEST_RE = /^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))$/i\\n\\nfunction replaceEntityPattern (match, name) {\\n if (name.charCodeAt(0) === 0x23/* # */ && DIGITAL_ENTITY_TEST_RE.test(name)) {\\n const code = name[1].toLowerCase() === 'x'\\n ? parseInt(name.slice(2), 16)\\n : parseInt(name.slice(1), 10)\\n\\n if (isValidEntityCode(code)) {\\n return fromCodePoint(code)\\n }\\n\\n return match\\n }\\n\\n const decoded = decodeHTML(match)\\n if (decoded !== match) {\\n return decoded\\n }\\n\\n return match\\n}\\n\\n/* function replaceEntities(str) {\\n if (str.indexOf('&') < 0) { return str; }\\n\\n return str.replace(ENTITY_RE, replaceEntityPattern);\\n} */\\n\\nfunction unescapeMd (str) {\\n if (str.indexOf('\\\\\\\\') < 0) { return str }\\n return str.replace(UNESCAPE_MD_RE, '$1')\\n}\\n\\nfunction unescapeAll (str) {\\n if (str.indexOf('\\\\\\\\') < 0 && str.indexOf('&') < 0) { return str }\\n\\n return str.replace(UNESCAPE_ALL_RE, function (match, escaped, entity) {\\n if (escaped) { return escaped }\\n return replaceEntityPattern(match, entity)\\n })\\n}\\n\\nconst HTML_ESCAPE_TEST_RE = /[&<>\\\"]/\\nconst HTML_ESCAPE_REPLACE_RE = /[&<>\\\"]/g\\nconst HTML_REPLACEMENTS = {\\n '&': '&',\\n '<': '<',\\n '>': '>',\\n '\\\"': '"'\\n}\\n\\nfunction replaceUnsafeChar (ch) {\\n return HTML_REPLACEMENTS[ch]\\n}\\n\\nfunction escapeHtml (str) {\\n if (HTML_ESCAPE_TEST_RE.test(str)) {\\n return str.replace(HTML_ESCAPE_REPLACE_RE, replaceUnsafeChar)\\n }\\n return str\\n}\\n\\nconst REGEXP_ESCAPE_RE = /[.?*+^$[\\\\]\\\\\\\\(){}|-]/g\\n\\nfunction escapeRE (str) {\\n return str.replace(REGEXP_ESCAPE_RE, '\\\\\\\\$&')\\n}\\n\\nfunction isSpace (code) {\\n switch (code) {\\n case 0x09:\\n case 0x20:\\n return true\\n }\\n return false\\n}\\n\\n// Zs (unicode class) || [\\\\t\\\\f\\\\v\\\\r\\\\n]\\nfunction isWhiteSpace (code) {\\n if (code >= 0x2000 && code <= 0x200A) { return true }\\n switch (code) {\\n case 0x09: // \\\\t\\n case 0x0A: // \\\\n\\n case 0x0B: // \\\\v\\n case 0x0C: // \\\\f\\n case 0x0D: // \\\\r\\n case 0x20:\\n case 0xA0:\\n case 0x1680:\\n case 0x202F:\\n case 0x205F:\\n case 0x3000:\\n return true\\n }\\n return false\\n}\\n\\n/* eslint-disable max-len */\\n\\n// Currently without astral characters support.\\nfunction isPunctChar (ch) {\\n return ucmicro.P.test(ch) || ucmicro.S.test(ch)\\n}\\n\\n// Markdown ASCII punctuation characters.\\n//\\n// !, \\\", #, $, %, &, ', (, ), *, +, ,, -, ., /, :, ;, <, =, >, ?, @, [, \\\\, ], ^, _, `, {, |, }, or ~\\n// http://spec.commonmark.org/0.15/#ascii-punctuation-character\\n//\\n// Don't confuse with unicode punctuation !!! It lacks some chars in ascii range.\\n//\\nfunction isMdAsciiPunct (ch) {\\n switch (ch) {\\n case 0x21/* ! */:\\n case 0x22/* \\\" */:\\n case 0x23/* # */:\\n case 0x24/* $ */:\\n case 0x25/* % */:\\n case 0x26/* & */:\\n case 0x27/* ' */:\\n case 0x28/* ( */:\\n case 0x29/* ) */:\\n case 0x2A/* * */:\\n case 0x2B/* + */:\\n case 0x2C/* , */:\\n case 0x2D/* - */:\\n case 0x2E/* . */:\\n case 0x2F/* / */:\\n case 0x3A/* : */:\\n case 0x3B/* ; */:\\n case 0x3C/* < */:\\n case 0x3D/* = */:\\n case 0x3E/* > */:\\n case 0x3F/* ? */:\\n case 0x40/* @ */:\\n case 0x5B/* [ */:\\n case 0x5C/* \\\\ */:\\n case 0x5D/* ] */:\\n case 0x5E/* ^ */:\\n case 0x5F/* _ */:\\n case 0x60/* ` */:\\n case 0x7B/* { */:\\n case 0x7C/* | */:\\n case 0x7D/* } */:\\n case 0x7E/* ~ */:\\n return true\\n default:\\n return false\\n }\\n}\\n\\n// Hepler to unify [reference labels].\\n//\\nfunction normalizeReference (str) {\\n // Trim and collapse whitespace\\n //\\n str = str.trim().replace(/\\\\s+/g, ' ')\\n\\n // In node v10 'ẞ'.toLowerCase() === 'Ṿ', which is presumed to be a bug\\n // fixed in v12 (couldn't find any details).\\n //\\n // So treat this one as a special case\\n // (remove this when node v10 is no longer supported).\\n //\\n if ('ẞ'.toLowerCase() === 'Ṿ') {\\n str = str.replace(/ẞ/g, 'ß')\\n }\\n\\n // .toLowerCase().toUpperCase() should get rid of all differences\\n // between letter variants.\\n //\\n // Simple .toLowerCase() doesn't normalize 125 code points correctly,\\n // and .toUpperCase doesn't normalize 6 of them (list of exceptions:\\n // İ, ϴ, ẞ, Ω, K, Å - those are already uppercased, but have differently\\n // uppercased versions).\\n //\\n // Here's an example showing how it happens. Lets take greek letter omega:\\n // uppercase U+0398 (Θ), U+03f4 (ϴ) and lowercase U+03b8 (θ), U+03d1 (ϑ)\\n //\\n // Unicode entries:\\n // 0398;GREEK CAPITAL LETTER THETA;Lu;0;L;;;;;N;;;;03B8;\\n // 03B8;GREEK SMALL LETTER THETA;Ll;0;L;;;;;N;;;0398;;0398\\n // 03D1;GREEK THETA SYMBOL;Ll;0;L; 03B8;;;;N;GREEK SMALL LETTER SCRIPT THETA;;0398;;0398\\n // 03F4;GREEK CAPITAL THETA SYMBOL;Lu;0;L; 0398;;;;N;;;;03B8;\\n //\\n // Case-insensitive comparison should treat all of them as equivalent.\\n //\\n // But .toLowerCase() doesn't change ϑ (it's already lowercase),\\n // and .toUpperCase() doesn't change ϴ (already uppercase).\\n //\\n // Applying first lower then upper case normalizes any character:\\n // '\\\\u0398\\\\u03f4\\\\u03b8\\\\u03d1'.toLowerCase().toUpperCase() === '\\\\u0398\\\\u0398\\\\u0398\\\\u0398'\\n //\\n // Note: this is equivalent to unicode case folding; unicode normalization\\n // is a different step that is not required here.\\n //\\n // Final result should be uppercased, because it's later stored in an object\\n // (this avoid a conflict with Object.prototype members,\\n // most notably, `__proto__`)\\n //\\n return str.toLowerCase().toUpperCase()\\n}\\n\\n// Re-export libraries commonly used in both markdown-it and its plugins,\\n// so plugins won't have to depend on them explicitly, which reduces their\\n// bundled size (e.g. a browser build).\\n//\\nconst lib = { mdurl, ucmicro }\\n\\nexport {\\n lib,\\n assign,\\n isString,\\n has,\\n unescapeMd,\\n unescapeAll,\\n isValidEntityCode,\\n fromCodePoint,\\n escapeHtml,\\n arrayReplaceAt,\\n isSpace,\\n isWhiteSpace,\\n isMdAsciiPunct,\\n isPunctChar,\\n escapeRE,\\n normalizeReference\\n}\\n\",\"import decode from './lib/decode.mjs'\\nimport encode from './lib/encode.mjs'\\nimport format from './lib/format.mjs'\\nimport parse from './lib/parse.mjs'\\n\\nexport {\\n decode,\\n encode,\\n format,\\n parse\\n}\\n\",\"/* eslint-disable no-bitwise */\\n\\nconst decodeCache = {}\\n\\nfunction getDecodeCache (exclude) {\\n let cache = decodeCache[exclude]\\n if (cache) { return cache }\\n\\n cache = decodeCache[exclude] = []\\n\\n for (let i = 0; i < 128; i++) {\\n const ch = String.fromCharCode(i)\\n cache.push(ch)\\n }\\n\\n for (let i = 0; i < exclude.length; i++) {\\n const ch = exclude.charCodeAt(i)\\n cache[ch] = '%' + ('0' + ch.toString(16).toUpperCase()).slice(-2)\\n }\\n\\n return cache\\n}\\n\\n// Decode percent-encoded string.\\n//\\nfunction decode (string, exclude) {\\n if (typeof exclude !== 'string') {\\n exclude = decode.defaultChars\\n }\\n\\n const cache = getDecodeCache(exclude)\\n\\n return string.replace(/(%[a-f0-9]{2})+/gi, function (seq) {\\n let result = ''\\n\\n for (let i = 0, l = seq.length; i < l; i += 3) {\\n const b1 = parseInt(seq.slice(i + 1, i + 3), 16)\\n\\n if (b1 < 0x80) {\\n result += cache[b1]\\n continue\\n }\\n\\n if ((b1 & 0xE0) === 0xC0 && (i + 3 < l)) {\\n // 110xxxxx 10xxxxxx\\n const b2 = parseInt(seq.slice(i + 4, i + 6), 16)\\n\\n if ((b2 & 0xC0) === 0x80) {\\n const chr = ((b1 << 6) & 0x7C0) | (b2 & 0x3F)\\n\\n if (chr < 0x80) {\\n result += '\\\\ufffd\\\\ufffd'\\n } else {\\n result += String.fromCharCode(chr)\\n }\\n\\n i += 3\\n continue\\n }\\n }\\n\\n if ((b1 & 0xF0) === 0xE0 && (i + 6 < l)) {\\n // 1110xxxx 10xxxxxx 10xxxxxx\\n const b2 = parseInt(seq.slice(i + 4, i + 6), 16)\\n const b3 = parseInt(seq.slice(i + 7, i + 9), 16)\\n\\n if ((b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80) {\\n const chr = ((b1 << 12) & 0xF000) | ((b2 << 6) & 0xFC0) | (b3 & 0x3F)\\n\\n if (chr < 0x800 || (chr >= 0xD800 && chr <= 0xDFFF)) {\\n result += '\\\\ufffd\\\\ufffd\\\\ufffd'\\n } else {\\n result += String.fromCharCode(chr)\\n }\\n\\n i += 6\\n continue\\n }\\n }\\n\\n if ((b1 & 0xF8) === 0xF0 && (i + 9 < l)) {\\n // 111110xx 10xxxxxx 10xxxxxx 10xxxxxx\\n const b2 = parseInt(seq.slice(i + 4, i + 6), 16)\\n const b3 = parseInt(seq.slice(i + 7, i + 9), 16)\\n const b4 = parseInt(seq.slice(i + 10, i + 12), 16)\\n\\n if ((b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80 && (b4 & 0xC0) === 0x80) {\\n let chr = ((b1 << 18) & 0x1C0000) | ((b2 << 12) & 0x3F000) | ((b3 << 6) & 0xFC0) | (b4 & 0x3F)\\n\\n if (chr < 0x10000 || chr > 0x10FFFF) {\\n result += '\\\\ufffd\\\\ufffd\\\\ufffd\\\\ufffd'\\n } else {\\n chr -= 0x10000\\n result += String.fromCharCode(0xD800 + (chr >> 10), 0xDC00 + (chr & 0x3FF))\\n }\\n\\n i += 9\\n continue\\n }\\n }\\n\\n result += '\\\\ufffd'\\n }\\n\\n return result\\n })\\n}\\n\\ndecode.defaultChars = ';/?:@&=+$,#'\\ndecode.componentChars = ''\\n\\nexport default decode\\n\",\"const encodeCache = {}\\n\\n// Create a lookup array where anything but characters in `chars` string\\n// and alphanumeric chars is percent-encoded.\\n//\\nfunction getEncodeCache (exclude) {\\n let cache = encodeCache[exclude]\\n if (cache) { return cache }\\n\\n cache = encodeCache[exclude] = []\\n\\n for (let i = 0; i < 128; i++) {\\n const ch = String.fromCharCode(i)\\n\\n if (/^[0-9a-z]$/i.test(ch)) {\\n // always allow unencoded alphanumeric characters\\n cache.push(ch)\\n } else {\\n cache.push('%' + ('0' + i.toString(16).toUpperCase()).slice(-2))\\n }\\n }\\n\\n for (let i = 0; i < exclude.length; i++) {\\n cache[exclude.charCodeAt(i)] = exclude[i]\\n }\\n\\n return cache\\n}\\n\\n// Encode unsafe characters with percent-encoding, skipping already\\n// encoded sequences.\\n//\\n// - string - string to encode\\n// - exclude - list of characters to ignore (in addition to a-zA-Z0-9)\\n// - keepEscaped - don't encode '%' in a correct escape sequence (default: true)\\n//\\nfunction encode (string, exclude, keepEscaped) {\\n if (typeof exclude !== 'string') {\\n // encode(string, keepEscaped)\\n keepEscaped = exclude\\n exclude = encode.defaultChars\\n }\\n\\n if (typeof keepEscaped === 'undefined') {\\n keepEscaped = true\\n }\\n\\n const cache = getEncodeCache(exclude)\\n let result = ''\\n\\n for (let i = 0, l = string.length; i < l; i++) {\\n const code = string.charCodeAt(i)\\n\\n if (keepEscaped && code === 0x25 /* % */ && i + 2 < l) {\\n if (/^[0-9a-f]{2}$/i.test(string.slice(i + 1, i + 3))) {\\n result += string.slice(i, i + 3)\\n i += 2\\n continue\\n }\\n }\\n\\n if (code < 128) {\\n result += cache[code]\\n continue\\n }\\n\\n if (code >= 0xD800 && code <= 0xDFFF) {\\n if (code >= 0xD800 && code <= 0xDBFF && i + 1 < l) {\\n const nextCode = string.charCodeAt(i + 1)\\n if (nextCode >= 0xDC00 && nextCode <= 0xDFFF) {\\n result += encodeURIComponent(string[i] + string[i + 1])\\n i++\\n continue\\n }\\n }\\n result += '%EF%BF%BD'\\n continue\\n }\\n\\n result += encodeURIComponent(string[i])\\n }\\n\\n return result\\n}\\n\\nencode.defaultChars = \\\";/?:@&=+$,-_.!~*'()#\\\"\\nencode.componentChars = \\\"-_.!~*'()\\\"\\n\\nexport default encode\\n\",\"export default function format (url) {\\n let result = ''\\n\\n result += url.protocol || ''\\n result += url.slashes ? '//' : ''\\n result += url.auth ? url.auth + '@' : ''\\n\\n if (url.hostname && url.hostname.indexOf(':') !== -1) {\\n // ipv6 address\\n result += '[' + url.hostname + ']'\\n } else {\\n result += url.hostname || ''\\n }\\n\\n result += url.port ? ':' + url.port : ''\\n result += url.pathname || ''\\n result += url.search || ''\\n result += url.hash || ''\\n\\n return result\\n};\\n\",\"// Copyright Joyent, Inc. and other Node contributors.\\n//\\n// Permission is hereby granted, free of charge, to any person obtaining a\\n// copy of this software and associated documentation files (the\\n// \\\"Software\\\"), to deal in the Software without restriction, including\\n// without limitation the rights to use, copy, modify, merge, publish,\\n// distribute, sublicense, and/or sell copies of the Software, and to permit\\n// persons to whom the Software is furnished to do so, subject to the\\n// following conditions:\\n//\\n// The above copyright notice and this permission notice shall be included\\n// in all copies or substantial portions of the Software.\\n//\\n// THE SOFTWARE IS PROVIDED \\\"AS IS\\\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\\n\\n//\\n// Changes from joyent/node:\\n//\\n// 1. No leading slash in paths,\\n// e.g. in `url.parse('http://foo?bar')` pathname is ``, not `/`\\n//\\n// 2. Backslashes are not replaced with slashes,\\n// so `http:\\\\\\\\example.org\\\\` is treated like a relative path\\n//\\n// 3. Trailing colon is treated like a part of the path,\\n// i.e. in `http://example.org:foo` pathname is `:foo`\\n//\\n// 4. Nothing is URL-encoded in the resulting object,\\n// (in joyent/node some chars in auth and paths are encoded)\\n//\\n// 5. `url.parse()` does not have `parseQueryString` argument\\n//\\n// 6. Removed extraneous result properties: `host`, `path`, `query`, etc.,\\n// which can be constructed using other parts of the url.\\n//\\n\\nfunction Url () {\\n this.protocol = null\\n this.slashes = null\\n this.auth = null\\n this.port = null\\n this.hostname = null\\n this.hash = null\\n this.search = null\\n this.pathname = null\\n}\\n\\n// Reference: RFC 3986, RFC 1808, RFC 2396\\n\\n// define these here so at least they only have to be\\n// compiled once on the first module load.\\nconst protocolPattern = /^([a-z0-9.+-]+:)/i\\nconst portPattern = /:[0-9]*$/\\n\\n// Special case for a simple path URL\\n/* eslint-disable-next-line no-useless-escape */\\nconst simplePathPattern = /^(\\\\/\\\\/?(?!\\\\/)[^\\\\?\\\\s]*)(\\\\?[^\\\\s]*)?$/\\n\\n// RFC 2396: characters reserved for delimiting URLs.\\n// We actually just auto-escape these.\\nconst delims = ['<', '>', '\\\"', '`', ' ', '\\\\r', '\\\\n', '\\\\t']\\n\\n// RFC 2396: characters not allowed for various reasons.\\nconst unwise = ['{', '}', '|', '\\\\\\\\', '^', '`'].concat(delims)\\n\\n// Allowed by RFCs, but cause of XSS attacks. Always escape these.\\nconst autoEscape = ['\\\\''].concat(unwise)\\n// Characters that are never ever allowed in a hostname.\\n// Note that any invalid chars are also handled, but these\\n// are the ones that are *expected* to be seen, so we fast-path\\n// them.\\nconst nonHostChars = ['%', '/', '?', ';', '#'].concat(autoEscape)\\nconst hostEndingChars = ['/', '?', '#']\\nconst hostnameMaxLen = 255\\nconst hostnamePartPattern = /^[+a-z0-9A-Z_-]{0,63}$/\\nconst hostnamePartStart = /^([+a-z0-9A-Z_-]{0,63})(.*)$/\\n// protocols that can allow \\\"unsafe\\\" and \\\"unwise\\\" chars.\\n// protocols that never have a hostname.\\nconst hostlessProtocol = {\\n javascript: true,\\n 'javascript:': true\\n}\\n// protocols that always contain a // bit.\\nconst slashedProtocol = {\\n http: true,\\n https: true,\\n ftp: true,\\n gopher: true,\\n file: true,\\n 'http:': true,\\n 'https:': true,\\n 'ftp:': true,\\n 'gopher:': true,\\n 'file:': true\\n}\\n\\nfunction urlParse (url, slashesDenoteHost) {\\n if (url && url instanceof Url) return url\\n\\n const u = new Url()\\n u.parse(url, slashesDenoteHost)\\n return u\\n}\\n\\nUrl.prototype.parse = function (url, slashesDenoteHost) {\\n let lowerProto, hec, slashes\\n let rest = url\\n\\n // trim before proceeding.\\n // This is to support parse stuff like \\\" http://foo.com \\\\n\\\"\\n rest = rest.trim()\\n\\n if (!slashesDenoteHost && url.split('#').length === 1) {\\n // Try fast path regexp\\n const simplePath = simplePathPattern.exec(rest)\\n if (simplePath) {\\n this.pathname = simplePath[1]\\n if (simplePath[2]) {\\n this.search = simplePath[2]\\n }\\n return this\\n }\\n }\\n\\n let proto = protocolPattern.exec(rest)\\n if (proto) {\\n proto = proto[0]\\n lowerProto = proto.toLowerCase()\\n this.protocol = proto\\n rest = rest.substr(proto.length)\\n }\\n\\n // figure out if it's got a host\\n // user@server is *always* interpreted as a hostname, and url\\n // resolution will treat //foo/bar as host=foo,path=bar because that's\\n // how the browser resolves relative URLs.\\n /* eslint-disable-next-line no-useless-escape */\\n if (slashesDenoteHost || proto || rest.match(/^\\\\/\\\\/[^@\\\\/]+@[^@\\\\/]+/)) {\\n slashes = rest.substr(0, 2) === '//'\\n if (slashes && !(proto && hostlessProtocol[proto])) {\\n rest = rest.substr(2)\\n this.slashes = true\\n }\\n }\\n\\n if (!hostlessProtocol[proto] &&\\n (slashes || (proto && !slashedProtocol[proto]))) {\\n // there's a hostname.\\n // the first instance of /, ?, ;, or # ends the host.\\n //\\n // If there is an @ in the hostname, then non-host chars *are* allowed\\n // to the left of the last @ sign, unless some host-ending character\\n // comes *before* the @-sign.\\n // URLs are obnoxious.\\n //\\n // ex:\\n // http://a@b@c/ => user:a@b host:c\\n // http://a@b?@c => user:a host:c path:/?@c\\n\\n // v0.12 TODO(isaacs): This is not quite how Chrome does things.\\n // Review our test case against browsers more comprehensively.\\n\\n // find the first instance of any hostEndingChars\\n let hostEnd = -1\\n for (let i = 0; i < hostEndingChars.length; i++) {\\n hec = rest.indexOf(hostEndingChars[i])\\n if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) {\\n hostEnd = hec\\n }\\n }\\n\\n // at this point, either we have an explicit point where the\\n // auth portion cannot go past, or the last @ char is the decider.\\n let auth, atSign\\n if (hostEnd === -1) {\\n // atSign can be anywhere.\\n atSign = rest.lastIndexOf('@')\\n } else {\\n // atSign must be in auth portion.\\n // http://a@b/c@d => host:b auth:a path:/c@d\\n atSign = rest.lastIndexOf('@', hostEnd)\\n }\\n\\n // Now we have a portion which is definitely the auth.\\n // Pull that off.\\n if (atSign !== -1) {\\n auth = rest.slice(0, atSign)\\n rest = rest.slice(atSign + 1)\\n this.auth = auth\\n }\\n\\n // the host is the remaining to the left of the first non-host char\\n hostEnd = -1\\n for (let i = 0; i < nonHostChars.length; i++) {\\n hec = rest.indexOf(nonHostChars[i])\\n if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) {\\n hostEnd = hec\\n }\\n }\\n // if we still have not hit it, then the entire thing is a host.\\n if (hostEnd === -1) {\\n hostEnd = rest.length\\n }\\n\\n if (rest[hostEnd - 1] === ':') { hostEnd-- }\\n const host = rest.slice(0, hostEnd)\\n rest = rest.slice(hostEnd)\\n\\n // pull out port.\\n this.parseHost(host)\\n\\n // we've indicated that there is a hostname,\\n // so even if it's empty, it has to be present.\\n this.hostname = this.hostname || ''\\n\\n // if hostname begins with [ and ends with ]\\n // assume that it's an IPv6 address.\\n const ipv6Hostname = this.hostname[0] === '[' &&\\n this.hostname[this.hostname.length - 1] === ']'\\n\\n // validate a little.\\n if (!ipv6Hostname) {\\n const hostparts = this.hostname.split(/\\\\./)\\n for (let i = 0, l = hostparts.length; i < l; i++) {\\n const part = hostparts[i]\\n if (!part) { continue }\\n if (!part.match(hostnamePartPattern)) {\\n let newpart = ''\\n for (let j = 0, k = part.length; j < k; j++) {\\n if (part.charCodeAt(j) > 127) {\\n // we replace non-ASCII char with a temporary placeholder\\n // we need this to make sure size of hostname is not\\n // broken by replacing non-ASCII by nothing\\n newpart += 'x'\\n } else {\\n newpart += part[j]\\n }\\n }\\n // we test again with ASCII char only\\n if (!newpart.match(hostnamePartPattern)) {\\n const validParts = hostparts.slice(0, i)\\n const notHost = hostparts.slice(i + 1)\\n const bit = part.match(hostnamePartStart)\\n if (bit) {\\n validParts.push(bit[1])\\n notHost.unshift(bit[2])\\n }\\n if (notHost.length) {\\n rest = notHost.join('.') + rest\\n }\\n this.hostname = validParts.join('.')\\n break\\n }\\n }\\n }\\n }\\n\\n if (this.hostname.length > hostnameMaxLen) {\\n this.hostname = ''\\n }\\n\\n // strip [ and ] from the hostname\\n // the host field still retains them, though\\n if (ipv6Hostname) {\\n this.hostname = this.hostname.substr(1, this.hostname.length - 2)\\n }\\n }\\n\\n // chop off from the tail first.\\n const hash = rest.indexOf('#')\\n if (hash !== -1) {\\n // got a fragment string.\\n this.hash = rest.substr(hash)\\n rest = rest.slice(0, hash)\\n }\\n const qm = rest.indexOf('?')\\n if (qm !== -1) {\\n this.search = rest.substr(qm)\\n rest = rest.slice(0, qm)\\n }\\n if (rest) { this.pathname = rest }\\n if (slashedProtocol[lowerProto] &&\\n this.hostname && !this.pathname) {\\n this.pathname = ''\\n }\\n\\n return this\\n}\\n\\nUrl.prototype.parseHost = function (host) {\\n let port = portPattern.exec(host)\\n if (port) {\\n port = port[0]\\n if (port !== ':') {\\n this.port = port.substr(1)\\n }\\n host = host.substr(0, host.length - port.length)\\n }\\n if (host) { this.hostname = host }\\n}\\n\\nexport default urlParse\\n\",\"import Any from './properties/Any/regex.mjs';\\nimport Cc from './categories/Cc/regex.mjs';\\nimport Cf from './categories/Cf/regex.mjs';\\nimport P from './categories/P/regex.mjs';\\nimport S from './categories/S/regex.mjs';\\nimport Z from './categories/Z/regex.mjs';\\n\\nexport { Any, Cc, Cf, P, S, Z };\\n\",\"export default /[\\\\0-\\\\uD7FF\\\\uE000-\\\\uFFFF]|[\\\\uD800-\\\\uDBFF][\\\\uDC00-\\\\uDFFF]|[\\\\uD800-\\\\uDBFF](?![\\\\uDC00-\\\\uDFFF])|(?:[^\\\\uD800-\\\\uDBFF]|^)[\\\\uDC00-\\\\uDFFF]/\",\"export default /[\\\\0-\\\\x1F\\\\x7F-\\\\x9F]/\",\"export default /[\\\\xAD\\\\u0600-\\\\u0605\\\\u061C\\\\u06DD\\\\u070F\\\\u0890\\\\u0891\\\\u08E2\\\\u180E\\\\u200B-\\\\u200F\\\\u202A-\\\\u202E\\\\u2060-\\\\u2064\\\\u2066-\\\\u206F\\\\uFEFF\\\\uFFF9-\\\\uFFFB]|\\\\uD804[\\\\uDCBD\\\\uDCCD]|\\\\uD80D[\\\\uDC30-\\\\uDC3F]|\\\\uD82F[\\\\uDCA0-\\\\uDCA3]|\\\\uD834[\\\\uDD73-\\\\uDD7A]|\\\\uDB40[\\\\uDC01\\\\uDC20-\\\\uDC7F]/\",\"export default /[!-#%-\\\\*,-\\\\/:;\\\\?@\\\\[-\\\\]_\\\\{\\\\}\\\\xA1\\\\xA7\\\\xAB\\\\xB6\\\\xB7\\\\xBB\\\\xBF\\\\u037E\\\\u0387\\\\u055A-\\\\u055F\\\\u0589\\\\u058A\\\\u05BE\\\\u05C0\\\\u05C3\\\\u05C6\\\\u05F3\\\\u05F4\\\\u0609\\\\u060A\\\\u060C\\\\u060D\\\\u061B\\\\u061D-\\\\u061F\\\\u066A-\\\\u066D\\\\u06D4\\\\u0700-\\\\u070D\\\\u07F7-\\\\u07F9\\\\u0830-\\\\u083E\\\\u085E\\\\u0964\\\\u0965\\\\u0970\\\\u09FD\\\\u0A76\\\\u0AF0\\\\u0C77\\\\u0C84\\\\u0DF4\\\\u0E4F\\\\u0E5A\\\\u0E5B\\\\u0F04-\\\\u0F12\\\\u0F14\\\\u0F3A-\\\\u0F3D\\\\u0F85\\\\u0FD0-\\\\u0FD4\\\\u0FD9\\\\u0FDA\\\\u104A-\\\\u104F\\\\u10FB\\\\u1360-\\\\u1368\\\\u1400\\\\u166E\\\\u169B\\\\u169C\\\\u16EB-\\\\u16ED\\\\u1735\\\\u1736\\\\u17D4-\\\\u17D6\\\\u17D8-\\\\u17DA\\\\u1800-\\\\u180A\\\\u1944\\\\u1945\\\\u1A1E\\\\u1A1F\\\\u1AA0-\\\\u1AA6\\\\u1AA8-\\\\u1AAD\\\\u1B5A-\\\\u1B60\\\\u1B7D\\\\u1B7E\\\\u1BFC-\\\\u1BFF\\\\u1C3B-\\\\u1C3F\\\\u1C7E\\\\u1C7F\\\\u1CC0-\\\\u1CC7\\\\u1CD3\\\\u2010-\\\\u2027\\\\u2030-\\\\u2043\\\\u2045-\\\\u2051\\\\u2053-\\\\u205E\\\\u207D\\\\u207E\\\\u208D\\\\u208E\\\\u2308-\\\\u230B\\\\u2329\\\\u232A\\\\u2768-\\\\u2775\\\\u27C5\\\\u27C6\\\\u27E6-\\\\u27EF\\\\u2983-\\\\u2998\\\\u29D8-\\\\u29DB\\\\u29FC\\\\u29FD\\\\u2CF9-\\\\u2CFC\\\\u2CFE\\\\u2CFF\\\\u2D70\\\\u2E00-\\\\u2E2E\\\\u2E30-\\\\u2E4F\\\\u2E52-\\\\u2E5D\\\\u3001-\\\\u3003\\\\u3008-\\\\u3011\\\\u3014-\\\\u301F\\\\u3030\\\\u303D\\\\u30A0\\\\u30FB\\\\uA4FE\\\\uA4FF\\\\uA60D-\\\\uA60F\\\\uA673\\\\uA67E\\\\uA6F2-\\\\uA6F7\\\\uA874-\\\\uA877\\\\uA8CE\\\\uA8CF\\\\uA8F8-\\\\uA8FA\\\\uA8FC\\\\uA92E\\\\uA92F\\\\uA95F\\\\uA9C1-\\\\uA9CD\\\\uA9DE\\\\uA9DF\\\\uAA5C-\\\\uAA5F\\\\uAADE\\\\uAADF\\\\uAAF0\\\\uAAF1\\\\uABEB\\\\uFD3E\\\\uFD3F\\\\uFE10-\\\\uFE19\\\\uFE30-\\\\uFE52\\\\uFE54-\\\\uFE61\\\\uFE63\\\\uFE68\\\\uFE6A\\\\uFE6B\\\\uFF01-\\\\uFF03\\\\uFF05-\\\\uFF0A\\\\uFF0C-\\\\uFF0F\\\\uFF1A\\\\uFF1B\\\\uFF1F\\\\uFF20\\\\uFF3B-\\\\uFF3D\\\\uFF3F\\\\uFF5B\\\\uFF5D\\\\uFF5F-\\\\uFF65]|\\\\uD800[\\\\uDD00-\\\\uDD02\\\\uDF9F\\\\uDFD0]|\\\\uD801\\\\uDD6F|\\\\uD802[\\\\uDC57\\\\uDD1F\\\\uDD3F\\\\uDE50-\\\\uDE58\\\\uDE7F\\\\uDEF0-\\\\uDEF6\\\\uDF39-\\\\uDF3F\\\\uDF99-\\\\uDF9C]|\\\\uD803[\\\\uDEAD\\\\uDF55-\\\\uDF59\\\\uDF86-\\\\uDF89]|\\\\uD804[\\\\uDC47-\\\\uDC4D\\\\uDCBB\\\\uDCBC\\\\uDCBE-\\\\uDCC1\\\\uDD40-\\\\uDD43\\\\uDD74\\\\uDD75\\\\uDDC5-\\\\uDDC8\\\\uDDCD\\\\uDDDB\\\\uDDDD-\\\\uDDDF\\\\uDE38-\\\\uDE3D\\\\uDEA9]|\\\\uD805[\\\\uDC4B-\\\\uDC4F\\\\uDC5A\\\\uDC5B\\\\uDC5D\\\\uDCC6\\\\uDDC1-\\\\uDDD7\\\\uDE41-\\\\uDE43\\\\uDE60-\\\\uDE6C\\\\uDEB9\\\\uDF3C-\\\\uDF3E]|\\\\uD806[\\\\uDC3B\\\\uDD44-\\\\uDD46\\\\uDDE2\\\\uDE3F-\\\\uDE46\\\\uDE9A-\\\\uDE9C\\\\uDE9E-\\\\uDEA2\\\\uDF00-\\\\uDF09]|\\\\uD807[\\\\uDC41-\\\\uDC45\\\\uDC70\\\\uDC71\\\\uDEF7\\\\uDEF8\\\\uDF43-\\\\uDF4F\\\\uDFFF]|\\\\uD809[\\\\uDC70-\\\\uDC74]|\\\\uD80B[\\\\uDFF1\\\\uDFF2]|\\\\uD81A[\\\\uDE6E\\\\uDE6F\\\\uDEF5\\\\uDF37-\\\\uDF3B\\\\uDF44]|\\\\uD81B[\\\\uDE97-\\\\uDE9A\\\\uDFE2]|\\\\uD82F\\\\uDC9F|\\\\uD836[\\\\uDE87-\\\\uDE8B]|\\\\uD83A[\\\\uDD5E\\\\uDD5F]/\",\"export default /[\\\\$\\\\+<->\\\\^`\\\\|~\\\\xA2-\\\\xA6\\\\xA8\\\\xA9\\\\xAC\\\\xAE-\\\\xB1\\\\xB4\\\\xB8\\\\xD7\\\\xF7\\\\u02C2-\\\\u02C5\\\\u02D2-\\\\u02DF\\\\u02E5-\\\\u02EB\\\\u02ED\\\\u02EF-\\\\u02FF\\\\u0375\\\\u0384\\\\u0385\\\\u03F6\\\\u0482\\\\u058D-\\\\u058F\\\\u0606-\\\\u0608\\\\u060B\\\\u060E\\\\u060F\\\\u06DE\\\\u06E9\\\\u06FD\\\\u06FE\\\\u07F6\\\\u07FE\\\\u07FF\\\\u0888\\\\u09F2\\\\u09F3\\\\u09FA\\\\u09FB\\\\u0AF1\\\\u0B70\\\\u0BF3-\\\\u0BFA\\\\u0C7F\\\\u0D4F\\\\u0D79\\\\u0E3F\\\\u0F01-\\\\u0F03\\\\u0F13\\\\u0F15-\\\\u0F17\\\\u0F1A-\\\\u0F1F\\\\u0F34\\\\u0F36\\\\u0F38\\\\u0FBE-\\\\u0FC5\\\\u0FC7-\\\\u0FCC\\\\u0FCE\\\\u0FCF\\\\u0FD5-\\\\u0FD8\\\\u109E\\\\u109F\\\\u1390-\\\\u1399\\\\u166D\\\\u17DB\\\\u1940\\\\u19DE-\\\\u19FF\\\\u1B61-\\\\u1B6A\\\\u1B74-\\\\u1B7C\\\\u1FBD\\\\u1FBF-\\\\u1FC1\\\\u1FCD-\\\\u1FCF\\\\u1FDD-\\\\u1FDF\\\\u1FED-\\\\u1FEF\\\\u1FFD\\\\u1FFE\\\\u2044\\\\u2052\\\\u207A-\\\\u207C\\\\u208A-\\\\u208C\\\\u20A0-\\\\u20C0\\\\u2100\\\\u2101\\\\u2103-\\\\u2106\\\\u2108\\\\u2109\\\\u2114\\\\u2116-\\\\u2118\\\\u211E-\\\\u2123\\\\u2125\\\\u2127\\\\u2129\\\\u212E\\\\u213A\\\\u213B\\\\u2140-\\\\u2144\\\\u214A-\\\\u214D\\\\u214F\\\\u218A\\\\u218B\\\\u2190-\\\\u2307\\\\u230C-\\\\u2328\\\\u232B-\\\\u2426\\\\u2440-\\\\u244A\\\\u249C-\\\\u24E9\\\\u2500-\\\\u2767\\\\u2794-\\\\u27C4\\\\u27C7-\\\\u27E5\\\\u27F0-\\\\u2982\\\\u2999-\\\\u29D7\\\\u29DC-\\\\u29FB\\\\u29FE-\\\\u2B73\\\\u2B76-\\\\u2B95\\\\u2B97-\\\\u2BFF\\\\u2CE5-\\\\u2CEA\\\\u2E50\\\\u2E51\\\\u2E80-\\\\u2E99\\\\u2E9B-\\\\u2EF3\\\\u2F00-\\\\u2FD5\\\\u2FF0-\\\\u2FFF\\\\u3004\\\\u3012\\\\u3013\\\\u3020\\\\u3036\\\\u3037\\\\u303E\\\\u303F\\\\u309B\\\\u309C\\\\u3190\\\\u3191\\\\u3196-\\\\u319F\\\\u31C0-\\\\u31E3\\\\u31EF\\\\u3200-\\\\u321E\\\\u322A-\\\\u3247\\\\u3250\\\\u3260-\\\\u327F\\\\u328A-\\\\u32B0\\\\u32C0-\\\\u33FF\\\\u4DC0-\\\\u4DFF\\\\uA490-\\\\uA4C6\\\\uA700-\\\\uA716\\\\uA720\\\\uA721\\\\uA789\\\\uA78A\\\\uA828-\\\\uA82B\\\\uA836-\\\\uA839\\\\uAA77-\\\\uAA79\\\\uAB5B\\\\uAB6A\\\\uAB6B\\\\uFB29\\\\uFBB2-\\\\uFBC2\\\\uFD40-\\\\uFD4F\\\\uFDCF\\\\uFDFC-\\\\uFDFF\\\\uFE62\\\\uFE64-\\\\uFE66\\\\uFE69\\\\uFF04\\\\uFF0B\\\\uFF1C-\\\\uFF1E\\\\uFF3E\\\\uFF40\\\\uFF5C\\\\uFF5E\\\\uFFE0-\\\\uFFE6\\\\uFFE8-\\\\uFFEE\\\\uFFFC\\\\uFFFD]|\\\\uD800[\\\\uDD37-\\\\uDD3F\\\\uDD79-\\\\uDD89\\\\uDD8C-\\\\uDD8E\\\\uDD90-\\\\uDD9C\\\\uDDA0\\\\uDDD0-\\\\uDDFC]|\\\\uD802[\\\\uDC77\\\\uDC78\\\\uDEC8]|\\\\uD805\\\\uDF3F|\\\\uD807[\\\\uDFD5-\\\\uDFF1]|\\\\uD81A[\\\\uDF3C-\\\\uDF3F\\\\uDF45]|\\\\uD82F\\\\uDC9C|\\\\uD833[\\\\uDF50-\\\\uDFC3]|\\\\uD834[\\\\uDC00-\\\\uDCF5\\\\uDD00-\\\\uDD26\\\\uDD29-\\\\uDD64\\\\uDD6A-\\\\uDD6C\\\\uDD83\\\\uDD84\\\\uDD8C-\\\\uDDA9\\\\uDDAE-\\\\uDDEA\\\\uDE00-\\\\uDE41\\\\uDE45\\\\uDF00-\\\\uDF56]|\\\\uD835[\\\\uDEC1\\\\uDEDB\\\\uDEFB\\\\uDF15\\\\uDF35\\\\uDF4F\\\\uDF6F\\\\uDF89\\\\uDFA9\\\\uDFC3]|\\\\uD836[\\\\uDC00-\\\\uDDFF\\\\uDE37-\\\\uDE3A\\\\uDE6D-\\\\uDE74\\\\uDE76-\\\\uDE83\\\\uDE85\\\\uDE86]|\\\\uD838[\\\\uDD4F\\\\uDEFF]|\\\\uD83B[\\\\uDCAC\\\\uDCB0\\\\uDD2E\\\\uDEF0\\\\uDEF1]|\\\\uD83C[\\\\uDC00-\\\\uDC2B\\\\uDC30-\\\\uDC93\\\\uDCA0-\\\\uDCAE\\\\uDCB1-\\\\uDCBF\\\\uDCC1-\\\\uDCCF\\\\uDCD1-\\\\uDCF5\\\\uDD0D-\\\\uDDAD\\\\uDDE6-\\\\uDE02\\\\uDE10-\\\\uDE3B\\\\uDE40-\\\\uDE48\\\\uDE50\\\\uDE51\\\\uDE60-\\\\uDE65\\\\uDF00-\\\\uDFFF]|\\\\uD83D[\\\\uDC00-\\\\uDED7\\\\uDEDC-\\\\uDEEC\\\\uDEF0-\\\\uDEFC\\\\uDF00-\\\\uDF76\\\\uDF7B-\\\\uDFD9\\\\uDFE0-\\\\uDFEB\\\\uDFF0]|\\\\uD83E[\\\\uDC00-\\\\uDC0B\\\\uDC10-\\\\uDC47\\\\uDC50-\\\\uDC59\\\\uDC60-\\\\uDC87\\\\uDC90-\\\\uDCAD\\\\uDCB0\\\\uDCB1\\\\uDD00-\\\\uDE53\\\\uDE60-\\\\uDE6D\\\\uDE70-\\\\uDE7C\\\\uDE80-\\\\uDE88\\\\uDE90-\\\\uDEBD\\\\uDEBF-\\\\uDEC5\\\\uDECE-\\\\uDEDB\\\\uDEE0-\\\\uDEE8\\\\uDEF0-\\\\uDEF8\\\\uDF00-\\\\uDF92\\\\uDF94-\\\\uDFCA]/\",\"export default /[ \\\\xA0\\\\u1680\\\\u2000-\\\\u200A\\\\u2028\\\\u2029\\\\u202F\\\\u205F\\\\u3000]/\",null,null,null,null,null,null,null,\"// Just a shortcut for bulk export\\n\\nimport parseLinkLabel from './parse_link_label.mjs'\\nimport parseLinkDestination from './parse_link_destination.mjs'\\nimport parseLinkTitle from './parse_link_title.mjs'\\n\\nexport {\\n parseLinkLabel,\\n parseLinkDestination,\\n parseLinkTitle\\n}\\n\",\"// Parse link label\\n//\\n// this function assumes that first character (\\\"[\\\") already matches;\\n// returns the end of the label\\n//\\n\\nexport default function parseLinkLabel (state, start, disableNested) {\\n let level, found, marker, prevPos\\n\\n const max = state.posMax\\n const oldPos = state.pos\\n\\n state.pos = start + 1\\n level = 1\\n\\n while (state.pos < max) {\\n marker = state.src.charCodeAt(state.pos)\\n if (marker === 0x5D /* ] */) {\\n level--\\n if (level === 0) {\\n found = true\\n break\\n }\\n }\\n\\n prevPos = state.pos\\n state.md.inline.skipToken(state)\\n if (marker === 0x5B /* [ */) {\\n if (prevPos === state.pos - 1) {\\n // increase level if we find text `[`, which is not a part of any token\\n level++\\n } else if (disableNested) {\\n state.pos = oldPos\\n return -1\\n }\\n }\\n }\\n\\n let labelEnd = -1\\n\\n if (found) {\\n labelEnd = state.pos\\n }\\n\\n // restore old state\\n state.pos = oldPos\\n\\n return labelEnd\\n}\\n\",\"// Parse link destination\\n//\\n\\nimport { unescapeAll } from '../common/utils.mjs'\\n\\nexport default function parseLinkDestination (str, start, max) {\\n let code\\n let pos = start\\n\\n const result = {\\n ok: false,\\n pos: 0,\\n str: ''\\n }\\n\\n if (str.charCodeAt(pos) === 0x3C /* < */) {\\n pos++\\n while (pos < max) {\\n code = str.charCodeAt(pos)\\n if (code === 0x0A /* \\\\n */) { return result }\\n if (code === 0x3C /* < */) { return result }\\n if (code === 0x3E /* > */) {\\n result.pos = pos + 1\\n result.str = unescapeAll(str.slice(start + 1, pos))\\n result.ok = true\\n return result\\n }\\n if (code === 0x5C /* \\\\ */ && pos + 1 < max) {\\n pos += 2\\n continue\\n }\\n\\n pos++\\n }\\n\\n // no closing '>'\\n return result\\n }\\n\\n // this should be ... } else { ... branch\\n\\n let level = 0\\n while (pos < max) {\\n code = str.charCodeAt(pos)\\n\\n if (code === 0x20) { break }\\n\\n // ascii control characters\\n if (code < 0x20 || code === 0x7F) { break }\\n\\n if (code === 0x5C /* \\\\ */ && pos + 1 < max) {\\n if (str.charCodeAt(pos + 1) === 0x20) { break }\\n pos += 2\\n continue\\n }\\n\\n if (code === 0x28 /* ( */) {\\n level++\\n if (level > 32) { return result }\\n }\\n\\n if (code === 0x29 /* ) */) {\\n if (level === 0) { break }\\n level--\\n }\\n\\n pos++\\n }\\n\\n if (start === pos) { return result }\\n if (level !== 0) { return result }\\n\\n result.str = unescapeAll(str.slice(start, pos))\\n result.pos = pos\\n result.ok = true\\n return result\\n}\\n\",\"// Parse link title\\n//\\n\\nimport { unescapeAll } from '../common/utils.mjs'\\n\\n// Parse link title within `str` in [start, max] range,\\n// or continue previous parsing if `prev_state` is defined (equal to result of last execution).\\n//\\nexport default function parseLinkTitle (str, start, max, prev_state) {\\n let code\\n let pos = start\\n\\n const state = {\\n // if `true`, this is a valid link title\\n ok: false,\\n // if `true`, this link can be continued on the next line\\n can_continue: false,\\n // if `ok`, it's the position of the first character after the closing marker\\n pos: 0,\\n // if `ok`, it's the unescaped title\\n str: '',\\n // expected closing marker character code\\n marker: 0\\n }\\n\\n if (prev_state) {\\n // this is a continuation of a previous parseLinkTitle call on the next line,\\n // used in reference links only\\n state.str = prev_state.str\\n state.marker = prev_state.marker\\n } else {\\n if (pos >= max) { return state }\\n\\n let marker = str.charCodeAt(pos)\\n if (marker !== 0x22 /* \\\" */ && marker !== 0x27 /* ' */ && marker !== 0x28 /* ( */) { return state }\\n\\n start++\\n pos++\\n\\n // if opening marker is \\\"(\\\", switch it to closing marker \\\")\\\"\\n if (marker === 0x28) { marker = 0x29 }\\n\\n state.marker = marker\\n }\\n\\n while (pos < max) {\\n code = str.charCodeAt(pos)\\n if (code === state.marker) {\\n state.pos = pos + 1\\n state.str += unescapeAll(str.slice(start, pos))\\n state.ok = true\\n return state\\n } else if (code === 0x28 /* ( */ && state.marker === 0x29 /* ) */) {\\n return state\\n } else if (code === 0x5C /* \\\\ */ && pos + 1 < max) {\\n pos++\\n }\\n\\n pos++\\n }\\n\\n // no closing marker found, but this link title may continue on the next line (for references)\\n state.can_continue = true\\n state.str += unescapeAll(str.slice(start, pos))\\n return state\\n}\\n\",\"/**\\n * class Renderer\\n *\\n * Generates HTML from parsed token stream. Each instance has independent\\n * copy of rules. Those can be rewritten with ease. Also, you can add new\\n * rules if you create plugin and adds new token types.\\n **/\\n\\nimport { assign, unescapeAll, escapeHtml } from './common/utils.mjs'\\n\\nconst default_rules = {}\\n\\ndefault_rules.code_inline = function (tokens, idx, options, env, slf) {\\n const token = tokens[idx]\\n\\n return '' +\\n escapeHtml(token.content) +\\n ''\\n}\\n\\ndefault_rules.code_block = function (tokens, idx, options, env, slf) {\\n const token = tokens[idx]\\n\\n return '' +\\n escapeHtml(tokens[idx].content) +\\n '\\\\n'\\n}\\n\\ndefault_rules.fence = function (tokens, idx, options, env, slf) {\\n const token = tokens[idx]\\n const info = token.info ? unescapeAll(token.info).trim() : ''\\n let langName = ''\\n let langAttrs = ''\\n\\n if (info) {\\n const arr = info.split(/(\\\\s+)/g)\\n langName = arr[0]\\n langAttrs = arr.slice(2).join('')\\n }\\n\\n let highlighted\\n if (options.highlight) {\\n highlighted = options.highlight(token.content, langName, langAttrs) || escapeHtml(token.content)\\n } else {\\n highlighted = escapeHtml(token.content)\\n }\\n\\n if (highlighted.indexOf('${highlighted}\\\\n`\\n }\\n\\n return `
${highlighted}
\\\\n`\\n}\\n\\ndefault_rules.image = function (tokens, idx, options, env, slf) {\\n const token = tokens[idx]\\n\\n // \\\"alt\\\" attr MUST be set, even if empty. Because it's mandatory and\\n // should be placed on proper position for tests.\\n //\\n // Replace content with actual value\\n\\n token.attrs[token.attrIndex('alt')][1] =\\n slf.renderInlineAsText(token.children, options, env)\\n\\n return slf.renderToken(tokens, idx, options)\\n}\\n\\ndefault_rules.hardbreak = function (tokens, idx, options /*, env */) {\\n return options.xhtmlOut ? '
\\\\n' : '
\\\\n'\\n}\\ndefault_rules.softbreak = function (tokens, idx, options /*, env */) {\\n return options.breaks ? (options.xhtmlOut ? '
\\\\n' : '
\\\\n') : '\\\\n'\\n}\\n\\ndefault_rules.text = function (tokens, idx /*, options, env */) {\\n return escapeHtml(tokens[idx].content)\\n}\\n\\ndefault_rules.html_block = function (tokens, idx /*, options, env */) {\\n return tokens[idx].content\\n}\\ndefault_rules.html_inline = function (tokens, idx /*, options, env */) {\\n return tokens[idx].content\\n}\\n\\n/**\\n * new Renderer()\\n *\\n * Creates new [[Renderer]] instance and fill [[Renderer#rules]] with defaults.\\n **/\\nfunction Renderer () {\\n /**\\n * Renderer#rules -> Object\\n *\\n * Contains render rules for tokens. Can be updated and extended.\\n *\\n * ##### Example\\n *\\n * ```javascript\\n * var md = require('markdown-it')();\\n *\\n * md.renderer.rules.strong_open = function () { return ''; };\\n * md.renderer.rules.strong_close = function () { return ''; };\\n *\\n * var result = md.renderInline(...);\\n * ```\\n *\\n * Each rule is called as independent static function with fixed signature:\\n *\\n * ```javascript\\n * function my_token_render(tokens, idx, options, env, renderer) {\\n * // ...\\n * return renderedHTML;\\n * }\\n * ```\\n *\\n * See [source code](https://github.com/markdown-it/markdown-it/blob/master/lib/renderer.mjs)\\n * for more details and examples.\\n **/\\n this.rules = assign({}, default_rules)\\n}\\n\\n/**\\n * Renderer.renderAttrs(token) -> String\\n *\\n * Render token attributes to string.\\n **/\\nRenderer.prototype.renderAttrs = function renderAttrs (token) {\\n let i, l, result\\n\\n if (!token.attrs) { return '' }\\n\\n result = ''\\n\\n for (i = 0, l = token.attrs.length; i < l; i++) {\\n result += ' ' + escapeHtml(token.attrs[i][0]) + '=\\\"' + escapeHtml(token.attrs[i][1]) + '\\\"'\\n }\\n\\n return result\\n}\\n\\n/**\\n * Renderer.renderToken(tokens, idx, options) -> String\\n * - tokens (Array): list of tokens\\n * - idx (Numbed): token index to render\\n * - options (Object): params of parser instance\\n *\\n * Default token renderer. Can be overriden by custom function\\n * in [[Renderer#rules]].\\n **/\\nRenderer.prototype.renderToken = function renderToken (tokens, idx, options) {\\n const token = tokens[idx]\\n let result = ''\\n\\n // Tight list paragraphs\\n if (token.hidden) {\\n return ''\\n }\\n\\n // Insert a newline between hidden paragraph and subsequent opening\\n // block-level tag.\\n //\\n // For example, here we should insert a newline before blockquote:\\n // - a\\n // >\\n //\\n if (token.block && token.nesting !== -1 && idx && tokens[idx - 1].hidden) {\\n result += '\\\\n'\\n }\\n\\n // Add token name, e.g. ``.\\n //\\n needLf = false\\n }\\n }\\n }\\n }\\n\\n result += needLf ? '>\\\\n' : '>'\\n\\n return result\\n}\\n\\n/**\\n * Renderer.renderInline(tokens, options, env) -> String\\n * - tokens (Array): list on block tokens to render\\n * - options (Object): params of parser instance\\n * - env (Object): additional data from parsed input (references, for example)\\n *\\n * The same as [[Renderer.render]], but for single token of `inline` type.\\n **/\\nRenderer.prototype.renderInline = function (tokens, options, env) {\\n let result = ''\\n const rules = this.rules\\n\\n for (let i = 0, len = tokens.length; i < len; i++) {\\n const type = tokens[i].type\\n\\n if (typeof rules[type] !== 'undefined') {\\n result += rules[type](tokens, i, options, env, this)\\n } else {\\n result += this.renderToken(tokens, i, options)\\n }\\n }\\n\\n return result\\n}\\n\\n/** internal\\n * Renderer.renderInlineAsText(tokens, options, env) -> String\\n * - tokens (Array): list on block tokens to render\\n * - options (Object): params of parser instance\\n * - env (Object): additional data from parsed input (references, for example)\\n *\\n * Special kludge for image `alt` attributes to conform CommonMark spec.\\n * Don't try to use it! Spec requires to show `alt` content with stripped markup,\\n * instead of simple escaping.\\n **/\\nRenderer.prototype.renderInlineAsText = function (tokens, options, env) {\\n let result = ''\\n\\n for (let i = 0, len = tokens.length; i < len; i++) {\\n switch (tokens[i].type) {\\n case 'text':\\n result += tokens[i].content\\n break\\n case 'image':\\n result += this.renderInlineAsText(tokens[i].children, options, env)\\n break\\n case 'html_inline':\\n case 'html_block':\\n result += tokens[i].content\\n break\\n case 'softbreak':\\n case 'hardbreak':\\n result += '\\\\n'\\n break\\n default:\\n // all other tokens are skipped\\n }\\n }\\n\\n return result\\n}\\n\\n/**\\n * Renderer.render(tokens, options, env) -> String\\n * - tokens (Array): list on block tokens to render\\n * - options (Object): params of parser instance\\n * - env (Object): additional data from parsed input (references, for example)\\n *\\n * Takes token stream and generates HTML. Probably, you will never need to call\\n * this method directly.\\n **/\\nRenderer.prototype.render = function (tokens, options, env) {\\n let result = ''\\n const rules = this.rules\\n\\n for (let i = 0, len = tokens.length; i < len; i++) {\\n const type = tokens[i].type\\n\\n if (type === 'inline') {\\n result += this.renderInline(tokens[i].children, options, env)\\n } else if (typeof rules[type] !== 'undefined') {\\n result += rules[type](tokens, i, options, env, this)\\n } else {\\n result += this.renderToken(tokens, i, options, env)\\n }\\n }\\n\\n return result\\n}\\n\\nexport default Renderer\\n\",\"/**\\n * class Ruler\\n *\\n * Helper class, used by [[MarkdownIt#core]], [[MarkdownIt#block]] and\\n * [[MarkdownIt#inline]] to manage sequences of functions (rules):\\n *\\n * - keep rules in defined order\\n * - assign the name to each rule\\n * - enable/disable rules\\n * - add/replace rules\\n * - allow assign rules to additional named chains (in the same)\\n * - cacheing lists of active rules\\n *\\n * You will not need use this class directly until write plugins. For simple\\n * rules control use [[MarkdownIt.disable]], [[MarkdownIt.enable]] and\\n * [[MarkdownIt.use]].\\n **/\\n\\n/**\\n * new Ruler()\\n **/\\nfunction Ruler () {\\n // List of added rules. Each element is:\\n //\\n // {\\n // name: XXX,\\n // enabled: Boolean,\\n // fn: Function(),\\n // alt: [ name2, name3 ]\\n // }\\n //\\n this.__rules__ = []\\n\\n // Cached rule chains.\\n //\\n // First level - chain name, '' for default.\\n // Second level - diginal anchor for fast filtering by charcodes.\\n //\\n this.__cache__ = null\\n}\\n\\n// Helper methods, should not be used directly\\n\\n// Find rule index by name\\n//\\nRuler.prototype.__find__ = function (name) {\\n for (let i = 0; i < this.__rules__.length; i++) {\\n if (this.__rules__[i].name === name) {\\n return i\\n }\\n }\\n return -1\\n}\\n\\n// Build rules lookup cache\\n//\\nRuler.prototype.__compile__ = function () {\\n const self = this\\n const chains = ['']\\n\\n // collect unique names\\n self.__rules__.forEach(function (rule) {\\n if (!rule.enabled) { return }\\n\\n rule.alt.forEach(function (altName) {\\n if (chains.indexOf(altName) < 0) {\\n chains.push(altName)\\n }\\n })\\n })\\n\\n self.__cache__ = {}\\n\\n chains.forEach(function (chain) {\\n self.__cache__[chain] = []\\n self.__rules__.forEach(function (rule) {\\n if (!rule.enabled) { return }\\n\\n if (chain && rule.alt.indexOf(chain) < 0) { return }\\n\\n self.__cache__[chain].push(rule.fn)\\n })\\n })\\n}\\n\\n/**\\n * Ruler.at(name, fn [, options])\\n * - name (String): rule name to replace.\\n * - fn (Function): new rule function.\\n * - options (Object): new rule options (not mandatory).\\n *\\n * Replace rule by name with new function & options. Throws error if name not\\n * found.\\n *\\n * ##### Options:\\n *\\n * - __alt__ - array with names of \\\"alternate\\\" chains.\\n *\\n * ##### Example\\n *\\n * Replace existing typographer replacement rule with new one:\\n *\\n * ```javascript\\n * var md = require('markdown-it')();\\n *\\n * md.core.ruler.at('replacements', function replace(state) {\\n * //...\\n * });\\n * ```\\n **/\\nRuler.prototype.at = function (name, fn, options) {\\n const index = this.__find__(name)\\n const opt = options || {}\\n\\n if (index === -1) { throw new Error('Parser rule not found: ' + name) }\\n\\n this.__rules__[index].fn = fn\\n this.__rules__[index].alt = opt.alt || []\\n this.__cache__ = null\\n}\\n\\n/**\\n * Ruler.before(beforeName, ruleName, fn [, options])\\n * - beforeName (String): new rule will be added before this one.\\n * - ruleName (String): name of added rule.\\n * - fn (Function): rule function.\\n * - options (Object): rule options (not mandatory).\\n *\\n * Add new rule to chain before one with given name. See also\\n * [[Ruler.after]], [[Ruler.push]].\\n *\\n * ##### Options:\\n *\\n * - __alt__ - array with names of \\\"alternate\\\" chains.\\n *\\n * ##### Example\\n *\\n * ```javascript\\n * var md = require('markdown-it')();\\n *\\n * md.block.ruler.before('paragraph', 'my_rule', function replace(state) {\\n * //...\\n * });\\n * ```\\n **/\\nRuler.prototype.before = function (beforeName, ruleName, fn, options) {\\n const index = this.__find__(beforeName)\\n const opt = options || {}\\n\\n if (index === -1) { throw new Error('Parser rule not found: ' + beforeName) }\\n\\n this.__rules__.splice(index, 0, {\\n name: ruleName,\\n enabled: true,\\n fn,\\n alt: opt.alt || []\\n })\\n\\n this.__cache__ = null\\n}\\n\\n/**\\n * Ruler.after(afterName, ruleName, fn [, options])\\n * - afterName (String): new rule will be added after this one.\\n * - ruleName (String): name of added rule.\\n * - fn (Function): rule function.\\n * - options (Object): rule options (not mandatory).\\n *\\n * Add new rule to chain after one with given name. See also\\n * [[Ruler.before]], [[Ruler.push]].\\n *\\n * ##### Options:\\n *\\n * - __alt__ - array with names of \\\"alternate\\\" chains.\\n *\\n * ##### Example\\n *\\n * ```javascript\\n * var md = require('markdown-it')();\\n *\\n * md.inline.ruler.after('text', 'my_rule', function replace(state) {\\n * //...\\n * });\\n * ```\\n **/\\nRuler.prototype.after = function (afterName, ruleName, fn, options) {\\n const index = this.__find__(afterName)\\n const opt = options || {}\\n\\n if (index === -1) { throw new Error('Parser rule not found: ' + afterName) }\\n\\n this.__rules__.splice(index + 1, 0, {\\n name: ruleName,\\n enabled: true,\\n fn,\\n alt: opt.alt || []\\n })\\n\\n this.__cache__ = null\\n}\\n\\n/**\\n * Ruler.push(ruleName, fn [, options])\\n * - ruleName (String): name of added rule.\\n * - fn (Function): rule function.\\n * - options (Object): rule options (not mandatory).\\n *\\n * Push new rule to the end of chain. See also\\n * [[Ruler.before]], [[Ruler.after]].\\n *\\n * ##### Options:\\n *\\n * - __alt__ - array with names of \\\"alternate\\\" chains.\\n *\\n * ##### Example\\n *\\n * ```javascript\\n * var md = require('markdown-it')();\\n *\\n * md.core.ruler.push('my_rule', function replace(state) {\\n * //...\\n * });\\n * ```\\n **/\\nRuler.prototype.push = function (ruleName, fn, options) {\\n const opt = options || {}\\n\\n this.__rules__.push({\\n name: ruleName,\\n enabled: true,\\n fn,\\n alt: opt.alt || []\\n })\\n\\n this.__cache__ = null\\n}\\n\\n/**\\n * Ruler.enable(list [, ignoreInvalid]) -> Array\\n * - list (String|Array): list of rule names to enable.\\n * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.\\n *\\n * Enable rules with given names. If any rule name not found - throw Error.\\n * Errors can be disabled by second param.\\n *\\n * Returns list of found rule names (if no exception happened).\\n *\\n * See also [[Ruler.disable]], [[Ruler.enableOnly]].\\n **/\\nRuler.prototype.enable = function (list, ignoreInvalid) {\\n if (!Array.isArray(list)) { list = [list] }\\n\\n const result = []\\n\\n // Search by name and enable\\n list.forEach(function (name) {\\n const idx = this.__find__(name)\\n\\n if (idx < 0) {\\n if (ignoreInvalid) { return }\\n throw new Error('Rules manager: invalid rule name ' + name)\\n }\\n this.__rules__[idx].enabled = true\\n result.push(name)\\n }, this)\\n\\n this.__cache__ = null\\n return result\\n}\\n\\n/**\\n * Ruler.enableOnly(list [, ignoreInvalid])\\n * - list (String|Array): list of rule names to enable (whitelist).\\n * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.\\n *\\n * Enable rules with given names, and disable everything else. If any rule name\\n * not found - throw Error. Errors can be disabled by second param.\\n *\\n * See also [[Ruler.disable]], [[Ruler.enable]].\\n **/\\nRuler.prototype.enableOnly = function (list, ignoreInvalid) {\\n if (!Array.isArray(list)) { list = [list] }\\n\\n this.__rules__.forEach(function (rule) { rule.enabled = false })\\n\\n this.enable(list, ignoreInvalid)\\n}\\n\\n/**\\n * Ruler.disable(list [, ignoreInvalid]) -> Array\\n * - list (String|Array): list of rule names to disable.\\n * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.\\n *\\n * Disable rules with given names. If any rule name not found - throw Error.\\n * Errors can be disabled by second param.\\n *\\n * Returns list of found rule names (if no exception happened).\\n *\\n * See also [[Ruler.enable]], [[Ruler.enableOnly]].\\n **/\\nRuler.prototype.disable = function (list, ignoreInvalid) {\\n if (!Array.isArray(list)) { list = [list] }\\n\\n const result = []\\n\\n // Search by name and disable\\n list.forEach(function (name) {\\n const idx = this.__find__(name)\\n\\n if (idx < 0) {\\n if (ignoreInvalid) { return }\\n throw new Error('Rules manager: invalid rule name ' + name)\\n }\\n this.__rules__[idx].enabled = false\\n result.push(name)\\n }, this)\\n\\n this.__cache__ = null\\n return result\\n}\\n\\n/**\\n * Ruler.getRules(chainName) -> Array\\n *\\n * Return array of active functions (rules) for given chain name. It analyzes\\n * rules configuration, compiles caches if not exists and returns result.\\n *\\n * Default chain name is `''` (empty string). It can't be skipped. That's\\n * done intentionally, to keep signature monomorphic for high speed.\\n **/\\nRuler.prototype.getRules = function (chainName) {\\n if (this.__cache__ === null) {\\n this.__compile__()\\n }\\n\\n // Chain can be empty, if rules disabled. But we still have to return Array.\\n return this.__cache__[chainName] || []\\n}\\n\\nexport default Ruler\\n\",\"// Token class\\n\\n/**\\n * class Token\\n **/\\n\\n/**\\n * new Token(type, tag, nesting)\\n *\\n * Create new token and fill passed properties.\\n **/\\nfunction Token (type, tag, nesting) {\\n /**\\n * Token#type -> String\\n *\\n * Type of the token (string, e.g. \\\"paragraph_open\\\")\\n **/\\n this.type = type\\n\\n /**\\n * Token#tag -> String\\n *\\n * html tag name, e.g. \\\"p\\\"\\n **/\\n this.tag = tag\\n\\n /**\\n * Token#attrs -> Array\\n *\\n * Html attributes. Format: `[ [ name1, value1 ], [ name2, value2 ] ]`\\n **/\\n this.attrs = null\\n\\n /**\\n * Token#map -> Array\\n *\\n * Source map info. Format: `[ line_begin, line_end ]`\\n **/\\n this.map = null\\n\\n /**\\n * Token#nesting -> Number\\n *\\n * Level change (number in {-1, 0, 1} set), where:\\n *\\n * - `1` means the tag is opening\\n * - `0` means the tag is self-closing\\n * - `-1` means the tag is closing\\n **/\\n this.nesting = nesting\\n\\n /**\\n * Token#level -> Number\\n *\\n * nesting level, the same as `state.level`\\n **/\\n this.level = 0\\n\\n /**\\n * Token#children -> Array\\n *\\n * An array of child nodes (inline and img tokens)\\n **/\\n this.children = null\\n\\n /**\\n * Token#content -> String\\n *\\n * In a case of self-closing tag (code, html, fence, etc.),\\n * it has contents of this tag.\\n **/\\n this.content = ''\\n\\n /**\\n * Token#markup -> String\\n *\\n * '*' or '_' for emphasis, fence string for fence, etc.\\n **/\\n this.markup = ''\\n\\n /**\\n * Token#info -> String\\n *\\n * Additional information:\\n *\\n * - Info string for \\\"fence\\\" tokens\\n * - The value \\\"auto\\\" for autolink \\\"link_open\\\" and \\\"link_close\\\" tokens\\n * - The string value of the item marker for ordered-list \\\"list_item_open\\\" tokens\\n **/\\n this.info = ''\\n\\n /**\\n * Token#meta -> Object\\n *\\n * A place for plugins to store an arbitrary data\\n **/\\n this.meta = null\\n\\n /**\\n * Token#block -> Boolean\\n *\\n * True for block-level tokens, false for inline tokens.\\n * Used in renderer to calculate line breaks\\n **/\\n this.block = false\\n\\n /**\\n * Token#hidden -> Boolean\\n *\\n * If it's true, ignore this element when rendering. Used for tight lists\\n * to hide paragraphs.\\n **/\\n this.hidden = false\\n}\\n\\n/**\\n * Token.attrIndex(name) -> Number\\n *\\n * Search attribute index by name.\\n **/\\nToken.prototype.attrIndex = function attrIndex (name) {\\n if (!this.attrs) { return -1 }\\n\\n const attrs = this.attrs\\n\\n for (let i = 0, len = attrs.length; i < len; i++) {\\n if (attrs[i][0] === name) { return i }\\n }\\n return -1\\n}\\n\\n/**\\n * Token.attrPush(attrData)\\n *\\n * Add `[ name, value ]` attribute to list. Init attrs if necessary\\n **/\\nToken.prototype.attrPush = function attrPush (attrData) {\\n if (this.attrs) {\\n this.attrs.push(attrData)\\n } else {\\n this.attrs = [attrData]\\n }\\n}\\n\\n/**\\n * Token.attrSet(name, value)\\n *\\n * Set `name` attribute to `value`. Override old value if exists.\\n **/\\nToken.prototype.attrSet = function attrSet (name, value) {\\n const idx = this.attrIndex(name)\\n const attrData = [name, value]\\n\\n if (idx < 0) {\\n this.attrPush(attrData)\\n } else {\\n this.attrs[idx] = attrData\\n }\\n}\\n\\n/**\\n * Token.attrGet(name)\\n *\\n * Get the value of attribute `name`, or null if it does not exist.\\n **/\\nToken.prototype.attrGet = function attrGet (name) {\\n const idx = this.attrIndex(name)\\n let value = null\\n if (idx >= 0) {\\n value = this.attrs[idx][1]\\n }\\n return value\\n}\\n\\n/**\\n * Token.attrJoin(name, value)\\n *\\n * Join value to existing attribute via space. Or create new attribute if not\\n * exists. Useful to operate with token classes.\\n **/\\nToken.prototype.attrJoin = function attrJoin (name, value) {\\n const idx = this.attrIndex(name)\\n\\n if (idx < 0) {\\n this.attrPush([name, value])\\n } else {\\n this.attrs[idx][1] = this.attrs[idx][1] + ' ' + value\\n }\\n}\\n\\nexport default Token\\n\",\"// Core state object\\n//\\n\\nimport Token from '../token.mjs'\\n\\nfunction StateCore (src, md, env) {\\n this.src = src\\n this.env = env\\n this.tokens = []\\n this.inlineMode = false\\n this.md = md // link to parser instance\\n}\\n\\n// re-export Token class to use in core rules\\nStateCore.prototype.Token = Token\\n\\nexport default StateCore\\n\",\"// Normalize input string\\n\\n// https://spec.commonmark.org/0.29/#line-ending\\nconst NEWLINES_RE = /\\\\r\\\\n?|\\\\n/g\\nconst NULL_RE = /\\\\0/g\\n\\nexport default function normalize (state) {\\n let str\\n\\n // Normalize newlines\\n str = state.src.replace(NEWLINES_RE, '\\\\n')\\n\\n // Replace NULL characters\\n str = str.replace(NULL_RE, '\\\\uFFFD')\\n\\n state.src = str\\n}\\n\",\"export default function block (state) {\\n let token\\n\\n if (state.inlineMode) {\\n token = new state.Token('inline', '', 0)\\n token.content = state.src\\n token.map = [0, 1]\\n token.children = []\\n state.tokens.push(token)\\n } else {\\n state.md.block.parse(state.src, state.md, state.env, state.tokens)\\n }\\n}\\n\",\"export default function inline (state) {\\n const tokens = state.tokens\\n\\n // Parse inlines\\n for (let i = 0, l = tokens.length; i < l; i++) {\\n const tok = tokens[i]\\n if (tok.type === 'inline') {\\n state.md.inline.parse(tok.content, state.md, state.env, tok.children)\\n }\\n }\\n}\\n\",\"// Replace link-like texts with link nodes.\\n//\\n// Currently restricted by `md.validateLink()` to http/https/ftp\\n//\\n\\nimport { arrayReplaceAt } from '../common/utils.mjs'\\n\\nfunction isLinkOpen (str) {\\n return /^\\\\s]/i.test(str)\\n}\\nfunction isLinkClose (str) {\\n return /^<\\\\/a\\\\s*>/i.test(str)\\n}\\n\\nexport default function linkify (state) {\\n const blockTokens = state.tokens\\n\\n if (!state.md.options.linkify) { return }\\n\\n for (let j = 0, l = blockTokens.length; j < l; j++) {\\n if (blockTokens[j].type !== 'inline' ||\\n !state.md.linkify.pretest(blockTokens[j].content)) {\\n continue\\n }\\n\\n let tokens = blockTokens[j].children\\n\\n let htmlLinkLevel = 0\\n\\n // We scan from the end, to keep position when new tags added.\\n // Use reversed logic in links start/end match\\n for (let i = tokens.length - 1; i >= 0; i--) {\\n const currentToken = tokens[i]\\n\\n // Skip content of markdown links\\n if (currentToken.type === 'link_close') {\\n i--\\n while (tokens[i].level !== currentToken.level && tokens[i].type !== 'link_open') {\\n i--\\n }\\n continue\\n }\\n\\n // Skip content of html tag links\\n if (currentToken.type === 'html_inline') {\\n if (isLinkOpen(currentToken.content) && htmlLinkLevel > 0) {\\n htmlLinkLevel--\\n }\\n if (isLinkClose(currentToken.content)) {\\n htmlLinkLevel++\\n }\\n }\\n if (htmlLinkLevel > 0) { continue }\\n\\n if (currentToken.type === 'text' && state.md.linkify.test(currentToken.content)) {\\n const text = currentToken.content\\n let links = state.md.linkify.match(text)\\n\\n // Now split string to nodes\\n const nodes = []\\n let level = currentToken.level\\n let lastPos = 0\\n\\n // forbid escape sequence at the start of the string,\\n // this avoids http\\\\://example.com/ from being linkified as\\n // http:
//example.com/\\n if (links.length > 0 &&\\n links[0].index === 0 &&\\n i > 0 &&\\n tokens[i - 1].type === 'text_special') {\\n links = links.slice(1)\\n }\\n\\n for (let ln = 0; ln < links.length; ln++) {\\n const url = links[ln].url\\n const fullUrl = state.md.normalizeLink(url)\\n if (!state.md.validateLink(fullUrl)) { continue }\\n\\n let urlText = links[ln].text\\n\\n // Linkifier might send raw hostnames like \\\"example.com\\\", where url\\n // starts with domain name. So we prepend http:// in those cases,\\n // and remove it afterwards.\\n //\\n if (!links[ln].schema) {\\n urlText = state.md.normalizeLinkText('http://' + urlText).replace(/^http:\\\\/\\\\//, '')\\n } else if (links[ln].schema === 'mailto:' && !/^mailto:/i.test(urlText)) {\\n urlText = state.md.normalizeLinkText('mailto:' + urlText).replace(/^mailto:/, '')\\n } else {\\n urlText = state.md.normalizeLinkText(urlText)\\n }\\n\\n const pos = links[ln].index\\n\\n if (pos > lastPos) {\\n const token = new state.Token('text', '', 0)\\n token.content = text.slice(lastPos, pos)\\n token.level = level\\n nodes.push(token)\\n }\\n\\n const token_o = new state.Token('link_open', 'a', 1)\\n token_o.attrs = [['href', fullUrl]]\\n token_o.level = level++\\n token_o.markup = 'linkify'\\n token_o.info = 'auto'\\n nodes.push(token_o)\\n\\n const token_t = new state.Token('text', '', 0)\\n token_t.content = urlText\\n token_t.level = level\\n nodes.push(token_t)\\n\\n const token_c = new state.Token('link_close', 'a', -1)\\n token_c.level = --level\\n token_c.markup = 'linkify'\\n token_c.info = 'auto'\\n nodes.push(token_c)\\n\\n lastPos = links[ln].lastIndex\\n }\\n if (lastPos < text.length) {\\n const token = new state.Token('text', '', 0)\\n token.content = text.slice(lastPos)\\n token.level = level\\n nodes.push(token)\\n }\\n\\n // replace current node\\n blockTokens[j].children = tokens = arrayReplaceAt(tokens, i, nodes)\\n }\\n }\\n }\\n}\\n\",\"// Simple typographic replacements\\n//\\n// (c) (C) → ©\\n// (tm) (TM) → ™\\n// (r) (R) → ®\\n// +- → ±\\n// ... → … (also ?.... → ?.., !.... → !..)\\n// ???????? → ???, !!!!! → !!!, `,,` → `,`\\n// -- → –, --- → —\\n//\\n\\n// TODO:\\n// - fractionals 1/2, 1/4, 3/4 -> ½, ¼, ¾\\n// - multiplications 2 x 4 -> 2 × 4\\n\\nconst RARE_RE = /\\\\+-|\\\\.\\\\.|\\\\?\\\\?\\\\?\\\\?|!!!!|,,|--/\\n\\n// Workaround for phantomjs - need regex without /g flag,\\n// or root check will fail every second time\\nconst SCOPED_ABBR_TEST_RE = /\\\\((c|tm|r)\\\\)/i\\n\\nconst SCOPED_ABBR_RE = /\\\\((c|tm|r)\\\\)/ig\\nconst SCOPED_ABBR = {\\n c: '©',\\n r: '®',\\n tm: '™'\\n}\\n\\nfunction replaceFn (match, name) {\\n return SCOPED_ABBR[name.toLowerCase()]\\n}\\n\\nfunction replace_scoped (inlineTokens) {\\n let inside_autolink = 0\\n\\n for (let i = inlineTokens.length - 1; i >= 0; i--) {\\n const token = inlineTokens[i]\\n\\n if (token.type === 'text' && !inside_autolink) {\\n token.content = token.content.replace(SCOPED_ABBR_RE, replaceFn)\\n }\\n\\n if (token.type === 'link_open' && token.info === 'auto') {\\n inside_autolink--\\n }\\n\\n if (token.type === 'link_close' && token.info === 'auto') {\\n inside_autolink++\\n }\\n }\\n}\\n\\nfunction replace_rare (inlineTokens) {\\n let inside_autolink = 0\\n\\n for (let i = inlineTokens.length - 1; i >= 0; i--) {\\n const token = inlineTokens[i]\\n\\n if (token.type === 'text' && !inside_autolink) {\\n if (RARE_RE.test(token.content)) {\\n token.content = token.content\\n .replace(/\\\\+-/g, '±')\\n // .., ..., ....... -> …\\n // but ?..... & !..... -> ?.. & !..\\n .replace(/\\\\.{2,}/g, '…').replace(/([?!])…/g, '$1..')\\n .replace(/([?!]){4,}/g, '$1$1$1').replace(/,{2,}/g, ',')\\n // em-dash\\n .replace(/(^|[^-])---(?=[^-]|$)/mg, '$1\\\\u2014')\\n // en-dash\\n .replace(/(^|\\\\s)--(?=\\\\s|$)/mg, '$1\\\\u2013')\\n .replace(/(^|[^-\\\\s])--(?=[^-\\\\s]|$)/mg, '$1\\\\u2013')\\n }\\n }\\n\\n if (token.type === 'link_open' && token.info === 'auto') {\\n inside_autolink--\\n }\\n\\n if (token.type === 'link_close' && token.info === 'auto') {\\n inside_autolink++\\n }\\n }\\n}\\n\\nexport default function replace (state) {\\n let blkIdx\\n\\n if (!state.md.options.typographer) { return }\\n\\n for (blkIdx = state.tokens.length - 1; blkIdx >= 0; blkIdx--) {\\n if (state.tokens[blkIdx].type !== 'inline') { continue }\\n\\n if (SCOPED_ABBR_TEST_RE.test(state.tokens[blkIdx].content)) {\\n replace_scoped(state.tokens[blkIdx].children)\\n }\\n\\n if (RARE_RE.test(state.tokens[blkIdx].content)) {\\n replace_rare(state.tokens[blkIdx].children)\\n }\\n }\\n}\\n\",\"// Convert straight quotation marks to typographic ones\\n//\\n\\nimport { isWhiteSpace, isPunctChar, isMdAsciiPunct } from '../common/utils.mjs'\\n\\nconst QUOTE_TEST_RE = /['\\\"]/\\nconst QUOTE_RE = /['\\\"]/g\\nconst APOSTROPHE = '\\\\u2019' /* ’ */\\n\\nfunction replaceAt (str, index, ch) {\\n return str.slice(0, index) + ch + str.slice(index + 1)\\n}\\n\\nfunction process_inlines (tokens, state) {\\n let j\\n\\n const stack = []\\n\\n for (let i = 0; i < tokens.length; i++) {\\n const token = tokens[i]\\n\\n const thisLevel = tokens[i].level\\n\\n for (j = stack.length - 1; j >= 0; j--) {\\n if (stack[j].level <= thisLevel) { break }\\n }\\n stack.length = j + 1\\n\\n if (token.type !== 'text') { continue }\\n\\n let text = token.content\\n let pos = 0\\n let max = text.length\\n\\n /* eslint no-labels:0,block-scoped-var:0 */\\n OUTER:\\n while (pos < max) {\\n QUOTE_RE.lastIndex = pos\\n const t = QUOTE_RE.exec(text)\\n if (!t) { break }\\n\\n let canOpen = true\\n let canClose = true\\n pos = t.index + 1\\n const isSingle = (t[0] === \\\"'\\\")\\n\\n // Find previous character,\\n // default to space if it's the beginning of the line\\n //\\n let lastChar = 0x20\\n\\n if (t.index - 1 >= 0) {\\n lastChar = text.charCodeAt(t.index - 1)\\n } else {\\n for (j = i - 1; j >= 0; j--) {\\n if (tokens[j].type === 'softbreak' || tokens[j].type === 'hardbreak') break // lastChar defaults to 0x20\\n if (!tokens[j].content) continue // should skip all tokens except 'text', 'html_inline' or 'code_inline'\\n\\n lastChar = tokens[j].content.charCodeAt(tokens[j].content.length - 1)\\n break\\n }\\n }\\n\\n // Find next character,\\n // default to space if it's the end of the line\\n //\\n let nextChar = 0x20\\n\\n if (pos < max) {\\n nextChar = text.charCodeAt(pos)\\n } else {\\n for (j = i + 1; j < tokens.length; j++) {\\n if (tokens[j].type === 'softbreak' || tokens[j].type === 'hardbreak') break // nextChar defaults to 0x20\\n if (!tokens[j].content) continue // should skip all tokens except 'text', 'html_inline' or 'code_inline'\\n\\n nextChar = tokens[j].content.charCodeAt(0)\\n break\\n }\\n }\\n\\n const isLastPunctChar = isMdAsciiPunct(lastChar) || isPunctChar(String.fromCharCode(lastChar))\\n const isNextPunctChar = isMdAsciiPunct(nextChar) || isPunctChar(String.fromCharCode(nextChar))\\n\\n const isLastWhiteSpace = isWhiteSpace(lastChar)\\n const isNextWhiteSpace = isWhiteSpace(nextChar)\\n\\n if (isNextWhiteSpace) {\\n canOpen = false\\n } else if (isNextPunctChar) {\\n if (!(isLastWhiteSpace || isLastPunctChar)) {\\n canOpen = false\\n }\\n }\\n\\n if (isLastWhiteSpace) {\\n canClose = false\\n } else if (isLastPunctChar) {\\n if (!(isNextWhiteSpace || isNextPunctChar)) {\\n canClose = false\\n }\\n }\\n\\n if (nextChar === 0x22 /* \\\" */ && t[0] === '\\\"') {\\n if (lastChar >= 0x30 /* 0 */ && lastChar <= 0x39 /* 9 */) {\\n // special case: 1\\\"\\\" - count first quote as an inch\\n canClose = canOpen = false\\n }\\n }\\n\\n if (canOpen && canClose) {\\n // Replace quotes in the middle of punctuation sequence, but not\\n // in the middle of the words, i.e.:\\n //\\n // 1. foo \\\" bar \\\" baz - not replaced\\n // 2. foo-\\\"-bar-\\\"-baz - replaced\\n // 3. foo\\\"bar\\\"baz - not replaced\\n //\\n canOpen = isLastPunctChar\\n canClose = isNextPunctChar\\n }\\n\\n if (!canOpen && !canClose) {\\n // middle of word\\n if (isSingle) {\\n token.content = replaceAt(token.content, t.index, APOSTROPHE)\\n }\\n continue\\n }\\n\\n if (canClose) {\\n // this could be a closing quote, rewind the stack to get a match\\n for (j = stack.length - 1; j >= 0; j--) {\\n let item = stack[j]\\n if (stack[j].level < thisLevel) { break }\\n if (item.single === isSingle && stack[j].level === thisLevel) {\\n item = stack[j]\\n\\n let openQuote\\n let closeQuote\\n if (isSingle) {\\n openQuote = state.md.options.quotes[2]\\n closeQuote = state.md.options.quotes[3]\\n } else {\\n openQuote = state.md.options.quotes[0]\\n closeQuote = state.md.options.quotes[1]\\n }\\n\\n // replace token.content *before* tokens[item.token].content,\\n // because, if they are pointing at the same token, replaceAt\\n // could mess up indices when quote length != 1\\n token.content = replaceAt(token.content, t.index, closeQuote)\\n tokens[item.token].content = replaceAt(\\n tokens[item.token].content, item.pos, openQuote)\\n\\n pos += closeQuote.length - 1\\n if (item.token === i) { pos += openQuote.length - 1 }\\n\\n text = token.content\\n max = text.length\\n\\n stack.length = j\\n continue OUTER\\n }\\n }\\n }\\n\\n if (canOpen) {\\n stack.push({\\n token: i,\\n pos: t.index,\\n single: isSingle,\\n level: thisLevel\\n })\\n } else if (canClose && isSingle) {\\n token.content = replaceAt(token.content, t.index, APOSTROPHE)\\n }\\n }\\n }\\n}\\n\\nexport default function smartquotes (state) {\\n /* eslint max-depth:0 */\\n if (!state.md.options.typographer) { return }\\n\\n for (let blkIdx = state.tokens.length - 1; blkIdx >= 0; blkIdx--) {\\n if (state.tokens[blkIdx].type !== 'inline' ||\\n !QUOTE_TEST_RE.test(state.tokens[blkIdx].content)) {\\n continue\\n }\\n\\n process_inlines(state.tokens[blkIdx].children, state)\\n }\\n}\\n\",\"// Join raw text tokens with the rest of the text\\n//\\n// This is set as a separate rule to provide an opportunity for plugins\\n// to run text replacements after text join, but before escape join.\\n//\\n// For example, `\\\\:)` shouldn't be replaced with an emoji.\\n//\\n\\nexport default function text_join (state) {\\n let curr, last\\n const blockTokens = state.tokens\\n const l = blockTokens.length\\n\\n for (let j = 0; j < l; j++) {\\n if (blockTokens[j].type !== 'inline') continue\\n\\n const tokens = blockTokens[j].children\\n const max = tokens.length\\n\\n for (curr = 0; curr < max; curr++) {\\n if (tokens[curr].type === 'text_special') {\\n tokens[curr].type = 'text'\\n }\\n }\\n\\n for (curr = last = 0; curr < max; curr++) {\\n if (tokens[curr].type === 'text' &&\\n curr + 1 < max &&\\n tokens[curr + 1].type === 'text') {\\n // collapse two adjacent text nodes\\n tokens[curr + 1].content = tokens[curr].content + tokens[curr + 1].content\\n } else {\\n if (curr !== last) { tokens[last] = tokens[curr] }\\n\\n last++\\n }\\n }\\n\\n if (curr !== last) {\\n tokens.length = last\\n }\\n }\\n}\\n\",\"/** internal\\n * class Core\\n *\\n * Top-level rules executor. Glues block/inline parsers and does intermediate\\n * transformations.\\n **/\\n\\nimport Ruler from './ruler.mjs'\\nimport StateCore from './rules_core/state_core.mjs'\\n\\nimport r_normalize from './rules_core/normalize.mjs'\\nimport r_block from './rules_core/block.mjs'\\nimport r_inline from './rules_core/inline.mjs'\\nimport r_linkify from './rules_core/linkify.mjs'\\nimport r_replacements from './rules_core/replacements.mjs'\\nimport r_smartquotes from './rules_core/smartquotes.mjs'\\nimport r_text_join from './rules_core/text_join.mjs'\\n\\nconst _rules = [\\n ['normalize', r_normalize],\\n ['block', r_block],\\n ['inline', r_inline],\\n ['linkify', r_linkify],\\n ['replacements', r_replacements],\\n ['smartquotes', r_smartquotes],\\n // `text_join` finds `text_special` tokens (for escape sequences)\\n // and joins them with the rest of the text\\n ['text_join', r_text_join]\\n]\\n\\n/**\\n * new Core()\\n **/\\nfunction Core () {\\n /**\\n * Core#ruler -> Ruler\\n *\\n * [[Ruler]] instance. Keep configuration of core rules.\\n **/\\n this.ruler = new Ruler()\\n\\n for (let i = 0; i < _rules.length; i++) {\\n this.ruler.push(_rules[i][0], _rules[i][1])\\n }\\n}\\n\\n/**\\n * Core.process(state)\\n *\\n * Executes core chain rules.\\n **/\\nCore.prototype.process = function (state) {\\n const rules = this.ruler.getRules('')\\n\\n for (let i = 0, l = rules.length; i < l; i++) {\\n rules[i](state)\\n }\\n}\\n\\nCore.prototype.State = StateCore\\n\\nexport default Core\\n\",\"// Parser state class\\n\\nimport Token from '../token.mjs'\\nimport { isSpace } from '../common/utils.mjs'\\n\\nfunction StateBlock (src, md, env, tokens) {\\n this.src = src\\n\\n // link to parser instance\\n this.md = md\\n\\n this.env = env\\n\\n //\\n // Internal state vartiables\\n //\\n\\n this.tokens = tokens\\n\\n this.bMarks = [] // line begin offsets for fast jumps\\n this.eMarks = [] // line end offsets for fast jumps\\n this.tShift = [] // offsets of the first non-space characters (tabs not expanded)\\n this.sCount = [] // indents for each line (tabs expanded)\\n\\n // An amount of virtual spaces (tabs expanded) between beginning\\n // of each line (bMarks) and real beginning of that line.\\n //\\n // It exists only as a hack because blockquotes override bMarks\\n // losing information in the process.\\n //\\n // It's used only when expanding tabs, you can think about it as\\n // an initial tab length, e.g. bsCount=21 applied to string `\\\\t123`\\n // means first tab should be expanded to 4-21%4 === 3 spaces.\\n //\\n this.bsCount = []\\n\\n // block parser variables\\n\\n // required block content indent (for example, if we are\\n // inside a list, it would be positioned after list marker)\\n this.blkIndent = 0\\n this.line = 0 // line index in src\\n this.lineMax = 0 // lines count\\n this.tight = false // loose/tight mode for lists\\n this.ddIndent = -1 // indent of the current dd block (-1 if there isn't any)\\n this.listIndent = -1 // indent of the current list block (-1 if there isn't any)\\n\\n // can be 'blockquote', 'list', 'root', 'paragraph' or 'reference'\\n // used in lists to determine if they interrupt a paragraph\\n this.parentType = 'root'\\n\\n this.level = 0\\n\\n // Create caches\\n // Generate markers.\\n const s = this.src\\n\\n for (let start = 0, pos = 0, indent = 0, offset = 0, len = s.length, indent_found = false; pos < len; pos++) {\\n const ch = s.charCodeAt(pos)\\n\\n if (!indent_found) {\\n if (isSpace(ch)) {\\n indent++\\n\\n if (ch === 0x09) {\\n offset += 4 - offset % 4\\n } else {\\n offset++\\n }\\n continue\\n } else {\\n indent_found = true\\n }\\n }\\n\\n if (ch === 0x0A || pos === len - 1) {\\n if (ch !== 0x0A) { pos++ }\\n this.bMarks.push(start)\\n this.eMarks.push(pos)\\n this.tShift.push(indent)\\n this.sCount.push(offset)\\n this.bsCount.push(0)\\n\\n indent_found = false\\n indent = 0\\n offset = 0\\n start = pos + 1\\n }\\n }\\n\\n // Push fake entry to simplify cache bounds checks\\n this.bMarks.push(s.length)\\n this.eMarks.push(s.length)\\n this.tShift.push(0)\\n this.sCount.push(0)\\n this.bsCount.push(0)\\n\\n this.lineMax = this.bMarks.length - 1 // don't count last fake line\\n}\\n\\n// Push new token to \\\"stream\\\".\\n//\\nStateBlock.prototype.push = function (type, tag, nesting) {\\n const token = new Token(type, tag, nesting)\\n token.block = true\\n\\n if (nesting < 0) this.level-- // closing tag\\n token.level = this.level\\n if (nesting > 0) this.level++ // opening tag\\n\\n this.tokens.push(token)\\n return token\\n}\\n\\nStateBlock.prototype.isEmpty = function isEmpty (line) {\\n return this.bMarks[line] + this.tShift[line] >= this.eMarks[line]\\n}\\n\\nStateBlock.prototype.skipEmptyLines = function skipEmptyLines (from) {\\n for (let max = this.lineMax; from < max; from++) {\\n if (this.bMarks[from] + this.tShift[from] < this.eMarks[from]) {\\n break\\n }\\n }\\n return from\\n}\\n\\n// Skip spaces from given position.\\nStateBlock.prototype.skipSpaces = function skipSpaces (pos) {\\n for (let max = this.src.length; pos < max; pos++) {\\n const ch = this.src.charCodeAt(pos)\\n if (!isSpace(ch)) { break }\\n }\\n return pos\\n}\\n\\n// Skip spaces from given position in reverse.\\nStateBlock.prototype.skipSpacesBack = function skipSpacesBack (pos, min) {\\n if (pos <= min) { return pos }\\n\\n while (pos > min) {\\n if (!isSpace(this.src.charCodeAt(--pos))) { return pos + 1 }\\n }\\n return pos\\n}\\n\\n// Skip char codes from given position\\nStateBlock.prototype.skipChars = function skipChars (pos, code) {\\n for (let max = this.src.length; pos < max; pos++) {\\n if (this.src.charCodeAt(pos) !== code) { break }\\n }\\n return pos\\n}\\n\\n// Skip char codes reverse from given position - 1\\nStateBlock.prototype.skipCharsBack = function skipCharsBack (pos, code, min) {\\n if (pos <= min) { return pos }\\n\\n while (pos > min) {\\n if (code !== this.src.charCodeAt(--pos)) { return pos + 1 }\\n }\\n return pos\\n}\\n\\n// cut lines range from source.\\nStateBlock.prototype.getLines = function getLines (begin, end, indent, keepLastLF) {\\n if (begin >= end) {\\n return ''\\n }\\n\\n const queue = new Array(end - begin)\\n\\n for (let i = 0, line = begin; line < end; line++, i++) {\\n let lineIndent = 0\\n const lineStart = this.bMarks[line]\\n let first = lineStart\\n let last\\n\\n if (line + 1 < end || keepLastLF) {\\n // No need for bounds check because we have fake entry on tail.\\n last = this.eMarks[line] + 1\\n } else {\\n last = this.eMarks[line]\\n }\\n\\n while (first < last && lineIndent < indent) {\\n const ch = this.src.charCodeAt(first)\\n\\n if (isSpace(ch)) {\\n if (ch === 0x09) {\\n lineIndent += 4 - (lineIndent + this.bsCount[line]) % 4\\n } else {\\n lineIndent++\\n }\\n } else if (first - lineStart < this.tShift[line]) {\\n // patched tShift masked characters to look like spaces (blockquotes, list markers)\\n lineIndent++\\n } else {\\n break\\n }\\n\\n first++\\n }\\n\\n if (lineIndent > indent) {\\n // partially expanding tabs in code blocks, e.g '\\\\t\\\\tfoobar'\\n // with indent=2 becomes ' \\\\tfoobar'\\n queue[i] = new Array(lineIndent - indent + 1).join(' ') + this.src.slice(first, last)\\n } else {\\n queue[i] = this.src.slice(first, last)\\n }\\n }\\n\\n return queue.join('')\\n}\\n\\n// re-export Token class to use in block rules\\nStateBlock.prototype.Token = Token\\n\\nexport default StateBlock\\n\",\"// GFM table, https://github.github.com/gfm/#tables-extension-\\n\\nimport { isSpace } from '../common/utils.mjs'\\n\\n// Limit the amount of empty autocompleted cells in a table,\\n// see https://github.com/markdown-it/markdown-it/issues/1000,\\n//\\n// Both pulldown-cmark and commonmark-hs limit the number of cells this way to ~200k.\\n// We set it to 65k, which can expand user input by a factor of x370\\n// (256x256 square is 1.8kB expanded into 650kB).\\nconst MAX_AUTOCOMPLETED_CELLS = 0x10000\\n\\nfunction getLine (state, line) {\\n const pos = state.bMarks[line] + state.tShift[line]\\n const max = state.eMarks[line]\\n\\n return state.src.slice(pos, max)\\n}\\n\\nfunction escapedSplit (str) {\\n const result = []\\n const max = str.length\\n\\n let pos = 0\\n let ch = str.charCodeAt(pos)\\n let isEscaped = false\\n let lastPos = 0\\n let current = ''\\n\\n while (pos < max) {\\n if (ch === 0x7c/* | */) {\\n if (!isEscaped) {\\n // pipe separating cells, '|'\\n result.push(current + str.substring(lastPos, pos))\\n current = ''\\n lastPos = pos + 1\\n } else {\\n // escaped pipe, '\\\\|'\\n current += str.substring(lastPos, pos - 1)\\n lastPos = pos\\n }\\n }\\n\\n isEscaped = (ch === 0x5c/* \\\\ */)\\n pos++\\n\\n ch = str.charCodeAt(pos)\\n }\\n\\n result.push(current + str.substring(lastPos))\\n\\n return result\\n}\\n\\nexport default function table (state, startLine, endLine, silent) {\\n // should have at least two lines\\n if (startLine + 2 > endLine) { return false }\\n\\n let nextLine = startLine + 1\\n\\n if (state.sCount[nextLine] < state.blkIndent) { return false }\\n\\n // if it's indented more than 3 spaces, it should be a code block\\n if (state.sCount[nextLine] - state.blkIndent >= 4) { return false }\\n\\n // first character of the second line should be '|', '-', ':',\\n // and no other characters are allowed but spaces;\\n // basically, this is the equivalent of /^[-:|][-:|\\\\s]*$/ regexp\\n\\n let pos = state.bMarks[nextLine] + state.tShift[nextLine]\\n if (pos >= state.eMarks[nextLine]) { return false }\\n\\n const firstCh = state.src.charCodeAt(pos++)\\n if (firstCh !== 0x7C/* | */ && firstCh !== 0x2D/* - */ && firstCh !== 0x3A/* : */) { return false }\\n\\n if (pos >= state.eMarks[nextLine]) { return false }\\n\\n const secondCh = state.src.charCodeAt(pos++)\\n if (secondCh !== 0x7C/* | */ && secondCh !== 0x2D/* - */ && secondCh !== 0x3A/* : */ && !isSpace(secondCh)) {\\n return false\\n }\\n\\n // if first character is '-', then second character must not be a space\\n // (due to parsing ambiguity with list)\\n if (firstCh === 0x2D/* - */ && isSpace(secondCh)) { return false }\\n\\n while (pos < state.eMarks[nextLine]) {\\n const ch = state.src.charCodeAt(pos)\\n\\n if (ch !== 0x7C/* | */ && ch !== 0x2D/* - */ && ch !== 0x3A/* : */ && !isSpace(ch)) { return false }\\n\\n pos++\\n }\\n\\n let lineText = getLine(state, startLine + 1)\\n let columns = lineText.split('|')\\n const aligns = []\\n for (let i = 0; i < columns.length; i++) {\\n const t = columns[i].trim()\\n if (!t) {\\n // allow empty columns before and after table, but not in between columns;\\n // e.g. allow ` |---| `, disallow ` ---||--- `\\n if (i === 0 || i === columns.length - 1) {\\n continue\\n } else {\\n return false\\n }\\n }\\n\\n if (!/^:?-+:?$/.test(t)) { return false }\\n if (t.charCodeAt(t.length - 1) === 0x3A/* : */) {\\n aligns.push(t.charCodeAt(0) === 0x3A/* : */ ? 'center' : 'right')\\n } else if (t.charCodeAt(0) === 0x3A/* : */) {\\n aligns.push('left')\\n } else {\\n aligns.push('')\\n }\\n }\\n\\n lineText = getLine(state, startLine).trim()\\n if (lineText.indexOf('|') === -1) { return false }\\n if (state.sCount[startLine] - state.blkIndent >= 4) { return false }\\n columns = escapedSplit(lineText)\\n if (columns.length && columns[0] === '') columns.shift()\\n if (columns.length && columns[columns.length - 1] === '') columns.pop()\\n\\n // header row will define an amount of columns in the entire table,\\n // and align row should be exactly the same (the rest of the rows can differ)\\n const columnCount = columns.length\\n if (columnCount === 0 || columnCount !== aligns.length) { return false }\\n\\n if (silent) { return true }\\n\\n const oldParentType = state.parentType\\n state.parentType = 'table'\\n\\n // use 'blockquote' lists for termination because it's\\n // the most similar to tables\\n const terminatorRules = state.md.block.ruler.getRules('blockquote')\\n\\n const token_to = state.push('table_open', 'table', 1)\\n const tableLines = [startLine, 0]\\n token_to.map = tableLines\\n\\n const token_tho = state.push('thead_open', 'thead', 1)\\n token_tho.map = [startLine, startLine + 1]\\n\\n const token_htro = state.push('tr_open', 'tr', 1)\\n token_htro.map = [startLine, startLine + 1]\\n\\n for (let i = 0; i < columns.length; i++) {\\n const token_ho = state.push('th_open', 'th', 1)\\n if (aligns[i]) {\\n token_ho.attrs = [['style', 'text-align:' + aligns[i]]]\\n }\\n\\n const token_il = state.push('inline', '', 0)\\n token_il.content = columns[i].trim()\\n token_il.children = []\\n\\n state.push('th_close', 'th', -1)\\n }\\n\\n state.push('tr_close', 'tr', -1)\\n state.push('thead_close', 'thead', -1)\\n\\n let tbodyLines\\n let autocompletedCells = 0\\n\\n for (nextLine = startLine + 2; nextLine < endLine; nextLine++) {\\n if (state.sCount[nextLine] < state.blkIndent) { break }\\n\\n let terminate = false\\n for (let i = 0, l = terminatorRules.length; i < l; i++) {\\n if (terminatorRules[i](state, nextLine, endLine, true)) {\\n terminate = true\\n break\\n }\\n }\\n\\n if (terminate) { break }\\n lineText = getLine(state, nextLine).trim()\\n if (!lineText) { break }\\n if (state.sCount[nextLine] - state.blkIndent >= 4) { break }\\n columns = escapedSplit(lineText)\\n if (columns.length && columns[0] === '') columns.shift()\\n if (columns.length && columns[columns.length - 1] === '') columns.pop()\\n\\n // note: autocomplete count can be negative if user specifies more columns than header,\\n // but that does not affect intended use (which is limiting expansion)\\n autocompletedCells += columnCount - columns.length\\n if (autocompletedCells > MAX_AUTOCOMPLETED_CELLS) { break }\\n\\n if (nextLine === startLine + 2) {\\n const token_tbo = state.push('tbody_open', 'tbody', 1)\\n token_tbo.map = tbodyLines = [startLine + 2, 0]\\n }\\n\\n const token_tro = state.push('tr_open', 'tr', 1)\\n token_tro.map = [nextLine, nextLine + 1]\\n\\n for (let i = 0; i < columnCount; i++) {\\n const token_tdo = state.push('td_open', 'td', 1)\\n if (aligns[i]) {\\n token_tdo.attrs = [['style', 'text-align:' + aligns[i]]]\\n }\\n\\n const token_il = state.push('inline', '', 0)\\n token_il.content = columns[i] ? columns[i].trim() : ''\\n token_il.children = []\\n\\n state.push('td_close', 'td', -1)\\n }\\n state.push('tr_close', 'tr', -1)\\n }\\n\\n if (tbodyLines) {\\n state.push('tbody_close', 'tbody', -1)\\n tbodyLines[1] = nextLine\\n }\\n\\n state.push('table_close', 'table', -1)\\n tableLines[1] = nextLine\\n\\n state.parentType = oldParentType\\n state.line = nextLine\\n return true\\n}\\n\",\"// Code block (4 spaces padded)\\n\\nexport default function code (state, startLine, endLine/*, silent */) {\\n if (state.sCount[startLine] - state.blkIndent < 4) { return false }\\n\\n let nextLine = startLine + 1\\n let last = nextLine\\n\\n while (nextLine < endLine) {\\n if (state.isEmpty(nextLine)) {\\n nextLine++\\n continue\\n }\\n\\n if (state.sCount[nextLine] - state.blkIndent >= 4) {\\n nextLine++\\n last = nextLine\\n continue\\n }\\n break\\n }\\n\\n state.line = last\\n\\n const token = state.push('code_block', 'code', 0)\\n token.content = state.getLines(startLine, last, 4 + state.blkIndent, false) + '\\\\n'\\n token.map = [startLine, state.line]\\n\\n return true\\n}\\n\",\"// fences (``` lang, ~~~ lang)\\n\\nexport default function fence (state, startLine, endLine, silent) {\\n let pos = state.bMarks[startLine] + state.tShift[startLine]\\n let max = state.eMarks[startLine]\\n\\n // if it's indented more than 3 spaces, it should be a code block\\n if (state.sCount[startLine] - state.blkIndent >= 4) { return false }\\n\\n if (pos + 3 > max) { return false }\\n\\n const marker = state.src.charCodeAt(pos)\\n\\n if (marker !== 0x7E/* ~ */ && marker !== 0x60 /* ` */) {\\n return false\\n }\\n\\n // scan marker length\\n let mem = pos\\n pos = state.skipChars(pos, marker)\\n\\n let len = pos - mem\\n\\n if (len < 3) { return false }\\n\\n const markup = state.src.slice(mem, pos)\\n const params = state.src.slice(pos, max)\\n\\n if (marker === 0x60 /* ` */) {\\n if (params.indexOf(String.fromCharCode(marker)) >= 0) {\\n return false\\n }\\n }\\n\\n // Since start is found, we can report success here in validation mode\\n if (silent) { return true }\\n\\n // search end of block\\n let nextLine = startLine\\n let haveEndMarker = false\\n\\n for (;;) {\\n nextLine++\\n if (nextLine >= endLine) {\\n // unclosed block should be autoclosed by end of document.\\n // also block seems to be autoclosed by end of parent\\n break\\n }\\n\\n pos = mem = state.bMarks[nextLine] + state.tShift[nextLine]\\n max = state.eMarks[nextLine]\\n\\n if (pos < max && state.sCount[nextLine] < state.blkIndent) {\\n // non-empty line with negative indent should stop the list:\\n // - ```\\n // test\\n break\\n }\\n\\n if (state.src.charCodeAt(pos) !== marker) { continue }\\n\\n if (state.sCount[nextLine] - state.blkIndent >= 4) {\\n // closing fence should be indented less than 4 spaces\\n continue\\n }\\n\\n pos = state.skipChars(pos, marker)\\n\\n // closing code fence must be at least as long as the opening one\\n if (pos - mem < len) { continue }\\n\\n // make sure tail has spaces only\\n pos = state.skipSpaces(pos)\\n\\n if (pos < max) { continue }\\n\\n haveEndMarker = true\\n // found!\\n break\\n }\\n\\n // If a fence has heading spaces, they should be removed from its inner block\\n len = state.sCount[startLine]\\n\\n state.line = nextLine + (haveEndMarker ? 1 : 0)\\n\\n const token = state.push('fence', 'code', 0)\\n token.info = params\\n token.content = state.getLines(startLine + 1, nextLine, len, true)\\n token.markup = markup\\n token.map = [startLine, state.line]\\n\\n return true\\n}\\n\",\"// Block quotes\\n\\nimport { isSpace } from '../common/utils.mjs'\\n\\nexport default function blockquote (state, startLine, endLine, silent) {\\n let pos = state.bMarks[startLine] + state.tShift[startLine]\\n let max = state.eMarks[startLine]\\n\\n const oldLineMax = state.lineMax\\n\\n // if it's indented more than 3 spaces, it should be a code block\\n if (state.sCount[startLine] - state.blkIndent >= 4) { return false }\\n\\n // check the block quote marker\\n if (state.src.charCodeAt(pos) !== 0x3E/* > */) { return false }\\n\\n // we know that it's going to be a valid blockquote,\\n // so no point trying to find the end of it in silent mode\\n if (silent) { return true }\\n\\n const oldBMarks = []\\n const oldBSCount = []\\n const oldSCount = []\\n const oldTShift = []\\n\\n const terminatorRules = state.md.block.ruler.getRules('blockquote')\\n\\n const oldParentType = state.parentType\\n state.parentType = 'blockquote'\\n let lastLineEmpty = false\\n let nextLine\\n\\n // Search the end of the block\\n //\\n // Block ends with either:\\n // 1. an empty line outside:\\n // ```\\n // > test\\n //\\n // ```\\n // 2. an empty line inside:\\n // ```\\n // >\\n // test\\n // ```\\n // 3. another tag:\\n // ```\\n // > test\\n // - - -\\n // ```\\n for (nextLine = startLine; nextLine < endLine; nextLine++) {\\n // check if it's outdented, i.e. it's inside list item and indented\\n // less than said list item:\\n //\\n // ```\\n // 1. anything\\n // > current blockquote\\n // 2. checking this line\\n // ```\\n const isOutdented = state.sCount[nextLine] < state.blkIndent\\n\\n pos = state.bMarks[nextLine] + state.tShift[nextLine]\\n max = state.eMarks[nextLine]\\n\\n if (pos >= max) {\\n // Case 1: line is not inside the blockquote, and this line is empty.\\n break\\n }\\n\\n if (state.src.charCodeAt(pos++) === 0x3E/* > */ && !isOutdented) {\\n // This line is inside the blockquote.\\n\\n // set offset past spaces and \\\">\\\"\\n let initial = state.sCount[nextLine] + 1\\n let spaceAfterMarker\\n let adjustTab\\n\\n // skip one optional space after '>'\\n if (state.src.charCodeAt(pos) === 0x20 /* space */) {\\n // ' > test '\\n // ^ -- position start of line here:\\n pos++\\n initial++\\n adjustTab = false\\n spaceAfterMarker = true\\n } else if (state.src.charCodeAt(pos) === 0x09 /* tab */) {\\n spaceAfterMarker = true\\n\\n if ((state.bsCount[nextLine] + initial) % 4 === 3) {\\n // ' >\\\\t test '\\n // ^ -- position start of line here (tab has width===1)\\n pos++\\n initial++\\n adjustTab = false\\n } else {\\n // ' >\\\\t test '\\n // ^ -- position start of line here + shift bsCount slightly\\n // to make extra space appear\\n adjustTab = true\\n }\\n } else {\\n spaceAfterMarker = false\\n }\\n\\n let offset = initial\\n oldBMarks.push(state.bMarks[nextLine])\\n state.bMarks[nextLine] = pos\\n\\n while (pos < max) {\\n const ch = state.src.charCodeAt(pos)\\n\\n if (isSpace(ch)) {\\n if (ch === 0x09) {\\n offset += 4 - (offset + state.bsCount[nextLine] + (adjustTab ? 1 : 0)) % 4\\n } else {\\n offset++\\n }\\n } else {\\n break\\n }\\n\\n pos++\\n }\\n\\n lastLineEmpty = pos >= max\\n\\n oldBSCount.push(state.bsCount[nextLine])\\n state.bsCount[nextLine] = state.sCount[nextLine] + 1 + (spaceAfterMarker ? 1 : 0)\\n\\n oldSCount.push(state.sCount[nextLine])\\n state.sCount[nextLine] = offset - initial\\n\\n oldTShift.push(state.tShift[nextLine])\\n state.tShift[nextLine] = pos - state.bMarks[nextLine]\\n continue\\n }\\n\\n // Case 2: line is not inside the blockquote, and the last line was empty.\\n if (lastLineEmpty) { break }\\n\\n // Case 3: another tag found.\\n let terminate = false\\n for (let i = 0, l = terminatorRules.length; i < l; i++) {\\n if (terminatorRules[i](state, nextLine, endLine, true)) {\\n terminate = true\\n break\\n }\\n }\\n\\n if (terminate) {\\n // Quirk to enforce \\\"hard termination mode\\\" for paragraphs;\\n // normally if you call `tokenize(state, startLine, nextLine)`,\\n // paragraphs will look below nextLine for paragraph continuation,\\n // but if blockquote is terminated by another tag, they shouldn't\\n state.lineMax = nextLine\\n\\n if (state.blkIndent !== 0) {\\n // state.blkIndent was non-zero, we now set it to zero,\\n // so we need to re-calculate all offsets to appear as\\n // if indent wasn't changed\\n oldBMarks.push(state.bMarks[nextLine])\\n oldBSCount.push(state.bsCount[nextLine])\\n oldTShift.push(state.tShift[nextLine])\\n oldSCount.push(state.sCount[nextLine])\\n state.sCount[nextLine] -= state.blkIndent\\n }\\n\\n break\\n }\\n\\n oldBMarks.push(state.bMarks[nextLine])\\n oldBSCount.push(state.bsCount[nextLine])\\n oldTShift.push(state.tShift[nextLine])\\n oldSCount.push(state.sCount[nextLine])\\n\\n // A negative indentation means that this is a paragraph continuation\\n //\\n state.sCount[nextLine] = -1\\n }\\n\\n const oldIndent = state.blkIndent\\n state.blkIndent = 0\\n\\n const token_o = state.push('blockquote_open', 'blockquote', 1)\\n token_o.markup = '>'\\n const lines = [startLine, 0]\\n token_o.map = lines\\n\\n state.md.block.tokenize(state, startLine, nextLine)\\n\\n const token_c = state.push('blockquote_close', 'blockquote', -1)\\n token_c.markup = '>'\\n\\n state.lineMax = oldLineMax\\n state.parentType = oldParentType\\n lines[1] = state.line\\n\\n // Restore original tShift; this might not be necessary since the parser\\n // has already been here, but just to make sure we can do that.\\n for (let i = 0; i < oldTShift.length; i++) {\\n state.bMarks[i + startLine] = oldBMarks[i]\\n state.tShift[i + startLine] = oldTShift[i]\\n state.sCount[i + startLine] = oldSCount[i]\\n state.bsCount[i + startLine] = oldBSCount[i]\\n }\\n state.blkIndent = oldIndent\\n\\n return true\\n}\\n\",\"// Horizontal rule\\n\\nimport { isSpace } from '../common/utils.mjs'\\n\\nexport default function hr (state, startLine, endLine, silent) {\\n const max = state.eMarks[startLine]\\n // if it's indented more than 3 spaces, it should be a code block\\n if (state.sCount[startLine] - state.blkIndent >= 4) { return false }\\n\\n let pos = state.bMarks[startLine] + state.tShift[startLine]\\n const marker = state.src.charCodeAt(pos++)\\n\\n // Check hr marker\\n if (marker !== 0x2A/* * */ &&\\n marker !== 0x2D/* - */ &&\\n marker !== 0x5F/* _ */) {\\n return false\\n }\\n\\n // markers can be mixed with spaces, but there should be at least 3 of them\\n\\n let cnt = 1\\n while (pos < max) {\\n const ch = state.src.charCodeAt(pos++)\\n if (ch !== marker && !isSpace(ch)) { return false }\\n if (ch === marker) { cnt++ }\\n }\\n\\n if (cnt < 3) { return false }\\n\\n if (silent) { return true }\\n\\n state.line = startLine + 1\\n\\n const token = state.push('hr', 'hr', 0)\\n token.map = [startLine, state.line]\\n token.markup = Array(cnt + 1).join(String.fromCharCode(marker))\\n\\n return true\\n}\\n\",\"// Lists\\n\\nimport { isSpace } from '../common/utils.mjs'\\n\\n// Search `[-+*][\\\\n ]`, returns next pos after marker on success\\n// or -1 on fail.\\nfunction skipBulletListMarker (state, startLine) {\\n const max = state.eMarks[startLine]\\n let pos = state.bMarks[startLine] + state.tShift[startLine]\\n\\n const marker = state.src.charCodeAt(pos++)\\n // Check bullet\\n if (marker !== 0x2A/* * */ &&\\n marker !== 0x2D/* - */ &&\\n marker !== 0x2B/* + */) {\\n return -1\\n }\\n\\n if (pos < max) {\\n const ch = state.src.charCodeAt(pos)\\n\\n if (!isSpace(ch)) {\\n // \\\" -test \\\" - is not a list item\\n return -1\\n }\\n }\\n\\n return pos\\n}\\n\\n// Search `\\\\d+[.)][\\\\n ]`, returns next pos after marker on success\\n// or -1 on fail.\\nfunction skipOrderedListMarker (state, startLine) {\\n const start = state.bMarks[startLine] + state.tShift[startLine]\\n const max = state.eMarks[startLine]\\n let pos = start\\n\\n // List marker should have at least 2 chars (digit + dot)\\n if (pos + 1 >= max) { return -1 }\\n\\n let ch = state.src.charCodeAt(pos++)\\n\\n if (ch < 0x30/* 0 */ || ch > 0x39/* 9 */) { return -1 }\\n\\n for (;;) {\\n // EOL -> fail\\n if (pos >= max) { return -1 }\\n\\n ch = state.src.charCodeAt(pos++)\\n\\n if (ch >= 0x30/* 0 */ && ch <= 0x39/* 9 */) {\\n // List marker should have no more than 9 digits\\n // (prevents integer overflow in browsers)\\n if (pos - start >= 10) { return -1 }\\n\\n continue\\n }\\n\\n // found valid marker\\n if (ch === 0x29/* ) */ || ch === 0x2e/* . */) {\\n break\\n }\\n\\n return -1\\n }\\n\\n if (pos < max) {\\n ch = state.src.charCodeAt(pos)\\n\\n if (!isSpace(ch)) {\\n // \\\" 1.test \\\" - is not a list item\\n return -1\\n }\\n }\\n return pos\\n}\\n\\nfunction markTightParagraphs (state, idx) {\\n const level = state.level + 2\\n\\n for (let i = idx + 2, l = state.tokens.length - 2; i < l; i++) {\\n if (state.tokens[i].level === level && state.tokens[i].type === 'paragraph_open') {\\n state.tokens[i + 2].hidden = true\\n state.tokens[i].hidden = true\\n i += 2\\n }\\n }\\n}\\n\\nexport default function list (state, startLine, endLine, silent) {\\n let max, pos, start, token\\n let nextLine = startLine\\n let tight = true\\n\\n // if it's indented more than 3 spaces, it should be a code block\\n if (state.sCount[nextLine] - state.blkIndent >= 4) { return false }\\n\\n // Special case:\\n // - item 1\\n // - item 2\\n // - item 3\\n // - item 4\\n // - this one is a paragraph continuation\\n if (state.listIndent >= 0 &&\\n state.sCount[nextLine] - state.listIndent >= 4 &&\\n state.sCount[nextLine] < state.blkIndent) {\\n return false\\n }\\n\\n let isTerminatingParagraph = false\\n\\n // limit conditions when list can interrupt\\n // a paragraph (validation mode only)\\n if (silent && state.parentType === 'paragraph') {\\n // Next list item should still terminate previous list item;\\n //\\n // This code can fail if plugins use blkIndent as well as lists,\\n // but I hope the spec gets fixed long before that happens.\\n //\\n if (state.sCount[nextLine] >= state.blkIndent) {\\n isTerminatingParagraph = true\\n }\\n }\\n\\n // Detect list type and position after marker\\n let isOrdered\\n let markerValue\\n let posAfterMarker\\n if ((posAfterMarker = skipOrderedListMarker(state, nextLine)) >= 0) {\\n isOrdered = true\\n start = state.bMarks[nextLine] + state.tShift[nextLine]\\n markerValue = Number(state.src.slice(start, posAfterMarker - 1))\\n\\n // If we're starting a new ordered list right after\\n // a paragraph, it should start with 1.\\n if (isTerminatingParagraph && markerValue !== 1) return false\\n } else if ((posAfterMarker = skipBulletListMarker(state, nextLine)) >= 0) {\\n isOrdered = false\\n } else {\\n return false\\n }\\n\\n // If we're starting a new unordered list right after\\n // a paragraph, first line should not be empty.\\n if (isTerminatingParagraph) {\\n if (state.skipSpaces(posAfterMarker) >= state.eMarks[nextLine]) return false\\n }\\n\\n // For validation mode we can terminate immediately\\n if (silent) { return true }\\n\\n // We should terminate list on style change. Remember first one to compare.\\n const markerCharCode = state.src.charCodeAt(posAfterMarker - 1)\\n\\n // Start list\\n const listTokIdx = state.tokens.length\\n\\n if (isOrdered) {\\n token = state.push('ordered_list_open', 'ol', 1)\\n if (markerValue !== 1) {\\n token.attrs = [['start', markerValue]]\\n }\\n } else {\\n token = state.push('bullet_list_open', 'ul', 1)\\n }\\n\\n const listLines = [nextLine, 0]\\n token.map = listLines\\n token.markup = String.fromCharCode(markerCharCode)\\n\\n //\\n // Iterate list items\\n //\\n\\n let prevEmptyEnd = false\\n const terminatorRules = state.md.block.ruler.getRules('list')\\n\\n const oldParentType = state.parentType\\n state.parentType = 'list'\\n\\n while (nextLine < endLine) {\\n pos = posAfterMarker\\n max = state.eMarks[nextLine]\\n\\n const initial = state.sCount[nextLine] + posAfterMarker - (state.bMarks[nextLine] + state.tShift[nextLine])\\n let offset = initial\\n\\n while (pos < max) {\\n const ch = state.src.charCodeAt(pos)\\n\\n if (ch === 0x09) {\\n offset += 4 - (offset + state.bsCount[nextLine]) % 4\\n } else if (ch === 0x20) {\\n offset++\\n } else {\\n break\\n }\\n\\n pos++\\n }\\n\\n const contentStart = pos\\n let indentAfterMarker\\n\\n if (contentStart >= max) {\\n // trimming space in \\\"- \\\\n 3\\\" case, indent is 1 here\\n indentAfterMarker = 1\\n } else {\\n indentAfterMarker = offset - initial\\n }\\n\\n // If we have more than 4 spaces, the indent is 1\\n // (the rest is just indented code block)\\n if (indentAfterMarker > 4) { indentAfterMarker = 1 }\\n\\n // \\\" - test\\\"\\n // ^^^^^ - calculating total length of this thing\\n const indent = initial + indentAfterMarker\\n\\n // Run subparser & write tokens\\n token = state.push('list_item_open', 'li', 1)\\n token.markup = String.fromCharCode(markerCharCode)\\n const itemLines = [nextLine, 0]\\n token.map = itemLines\\n if (isOrdered) {\\n token.info = state.src.slice(start, posAfterMarker - 1)\\n }\\n\\n // change current state, then restore it after parser subcall\\n const oldTight = state.tight\\n const oldTShift = state.tShift[nextLine]\\n const oldSCount = state.sCount[nextLine]\\n\\n // - example list\\n // ^ listIndent position will be here\\n // ^ blkIndent position will be here\\n //\\n const oldListIndent = state.listIndent\\n state.listIndent = state.blkIndent\\n state.blkIndent = indent\\n\\n state.tight = true\\n state.tShift[nextLine] = contentStart - state.bMarks[nextLine]\\n state.sCount[nextLine] = offset\\n\\n if (contentStart >= max && state.isEmpty(nextLine + 1)) {\\n // workaround for this case\\n // (list item is empty, list terminates before \\\"foo\\\"):\\n // ~~~~~~~~\\n // -\\n //\\n // foo\\n // ~~~~~~~~\\n state.line = Math.min(state.line + 2, endLine)\\n } else {\\n state.md.block.tokenize(state, nextLine, endLine, true)\\n }\\n\\n // If any of list item is tight, mark list as tight\\n if (!state.tight || prevEmptyEnd) {\\n tight = false\\n }\\n // Item become loose if finish with empty line,\\n // but we should filter last element, because it means list finish\\n prevEmptyEnd = (state.line - nextLine) > 1 && state.isEmpty(state.line - 1)\\n\\n state.blkIndent = state.listIndent\\n state.listIndent = oldListIndent\\n state.tShift[nextLine] = oldTShift\\n state.sCount[nextLine] = oldSCount\\n state.tight = oldTight\\n\\n token = state.push('list_item_close', 'li', -1)\\n token.markup = String.fromCharCode(markerCharCode)\\n\\n nextLine = state.line\\n itemLines[1] = nextLine\\n\\n if (nextLine >= endLine) { break }\\n\\n //\\n // Try to check if list is terminated or continued.\\n //\\n if (state.sCount[nextLine] < state.blkIndent) { break }\\n\\n // if it's indented more than 3 spaces, it should be a code block\\n if (state.sCount[nextLine] - state.blkIndent >= 4) { break }\\n\\n // fail if terminating block found\\n let terminate = false\\n for (let i = 0, l = terminatorRules.length; i < l; i++) {\\n if (terminatorRules[i](state, nextLine, endLine, true)) {\\n terminate = true\\n break\\n }\\n }\\n if (terminate) { break }\\n\\n // fail if list has another type\\n if (isOrdered) {\\n posAfterMarker = skipOrderedListMarker(state, nextLine)\\n if (posAfterMarker < 0) { break }\\n start = state.bMarks[nextLine] + state.tShift[nextLine]\\n } else {\\n posAfterMarker = skipBulletListMarker(state, nextLine)\\n if (posAfterMarker < 0) { break }\\n }\\n\\n if (markerCharCode !== state.src.charCodeAt(posAfterMarker - 1)) { break }\\n }\\n\\n // Finalize list\\n if (isOrdered) {\\n token = state.push('ordered_list_close', 'ol', -1)\\n } else {\\n token = state.push('bullet_list_close', 'ul', -1)\\n }\\n token.markup = String.fromCharCode(markerCharCode)\\n\\n listLines[1] = nextLine\\n state.line = nextLine\\n\\n state.parentType = oldParentType\\n\\n // mark paragraphs tight if needed\\n if (tight) {\\n markTightParagraphs(state, listTokIdx)\\n }\\n\\n return true\\n}\\n\",\"import { isSpace, normalizeReference } from '../common/utils.mjs'\\n\\nexport default function reference (state, startLine, _endLine, silent) {\\n let pos = state.bMarks[startLine] + state.tShift[startLine]\\n let max = state.eMarks[startLine]\\n let nextLine = startLine + 1\\n\\n // if it's indented more than 3 spaces, it should be a code block\\n if (state.sCount[startLine] - state.blkIndent >= 4) { return false }\\n\\n if (state.src.charCodeAt(pos) !== 0x5B/* [ */) { return false }\\n\\n function getNextLine (nextLine) {\\n const endLine = state.lineMax\\n\\n if (nextLine >= endLine || state.isEmpty(nextLine)) {\\n // empty line or end of input\\n return null\\n }\\n\\n let isContinuation = false\\n\\n // this would be a code block normally, but after paragraph\\n // it's considered a lazy continuation regardless of what's there\\n if (state.sCount[nextLine] - state.blkIndent > 3) { isContinuation = true }\\n\\n // quirk for blockquotes, this line should already be checked by that rule\\n if (state.sCount[nextLine] < 0) { isContinuation = true }\\n\\n if (!isContinuation) {\\n const terminatorRules = state.md.block.ruler.getRules('reference')\\n const oldParentType = state.parentType\\n state.parentType = 'reference'\\n\\n // Some tags can terminate paragraph without empty line.\\n let terminate = false\\n for (let i = 0, l = terminatorRules.length; i < l; i++) {\\n if (terminatorRules[i](state, nextLine, endLine, true)) {\\n terminate = true\\n break\\n }\\n }\\n\\n state.parentType = oldParentType\\n if (terminate) {\\n // terminated by another block\\n return null\\n }\\n }\\n\\n const pos = state.bMarks[nextLine] + state.tShift[nextLine]\\n const max = state.eMarks[nextLine]\\n\\n // max + 1 explicitly includes the newline\\n return state.src.slice(pos, max + 1)\\n }\\n\\n let str = state.src.slice(pos, max + 1)\\n\\n max = str.length\\n let labelEnd = -1\\n\\n for (pos = 1; pos < max; pos++) {\\n const ch = str.charCodeAt(pos)\\n if (ch === 0x5B /* [ */) {\\n return false\\n } else if (ch === 0x5D /* ] */) {\\n labelEnd = pos\\n break\\n } else if (ch === 0x0A /* \\\\n */) {\\n const lineContent = getNextLine(nextLine)\\n if (lineContent !== null) {\\n str += lineContent\\n max = str.length\\n nextLine++\\n }\\n } else if (ch === 0x5C /* \\\\ */) {\\n pos++\\n if (pos < max && str.charCodeAt(pos) === 0x0A) {\\n const lineContent = getNextLine(nextLine)\\n if (lineContent !== null) {\\n str += lineContent\\n max = str.length\\n nextLine++\\n }\\n }\\n }\\n }\\n\\n if (labelEnd < 0 || str.charCodeAt(labelEnd + 1) !== 0x3A/* : */) { return false }\\n\\n // [label]: destination 'title'\\n // ^^^ skip optional whitespace here\\n for (pos = labelEnd + 2; pos < max; pos++) {\\n const ch = str.charCodeAt(pos)\\n if (ch === 0x0A) {\\n const lineContent = getNextLine(nextLine)\\n if (lineContent !== null) {\\n str += lineContent\\n max = str.length\\n nextLine++\\n }\\n } else if (isSpace(ch)) {\\n /* eslint no-empty:0 */\\n } else {\\n break\\n }\\n }\\n\\n // [label]: destination 'title'\\n // ^^^^^^^^^^^ parse this\\n const destRes = state.md.helpers.parseLinkDestination(str, pos, max)\\n if (!destRes.ok) { return false }\\n\\n const href = state.md.normalizeLink(destRes.str)\\n if (!state.md.validateLink(href)) { return false }\\n\\n pos = destRes.pos\\n\\n // save cursor state, we could require to rollback later\\n const destEndPos = pos\\n const destEndLineNo = nextLine\\n\\n // [label]: destination 'title'\\n // ^^^ skipping those spaces\\n const start = pos\\n for (; pos < max; pos++) {\\n const ch = str.charCodeAt(pos)\\n if (ch === 0x0A) {\\n const lineContent = getNextLine(nextLine)\\n if (lineContent !== null) {\\n str += lineContent\\n max = str.length\\n nextLine++\\n }\\n } else if (isSpace(ch)) {\\n /* eslint no-empty:0 */\\n } else {\\n break\\n }\\n }\\n\\n // [label]: destination 'title'\\n // ^^^^^^^ parse this\\n let titleRes = state.md.helpers.parseLinkTitle(str, pos, max)\\n while (titleRes.can_continue) {\\n const lineContent = getNextLine(nextLine)\\n if (lineContent === null) break\\n str += lineContent\\n pos = max\\n max = str.length\\n nextLine++\\n titleRes = state.md.helpers.parseLinkTitle(str, pos, max, titleRes)\\n }\\n let title\\n\\n if (pos < max && start !== pos && titleRes.ok) {\\n title = titleRes.str\\n pos = titleRes.pos\\n } else {\\n title = ''\\n pos = destEndPos\\n nextLine = destEndLineNo\\n }\\n\\n // skip trailing spaces until the rest of the line\\n while (pos < max) {\\n const ch = str.charCodeAt(pos)\\n if (!isSpace(ch)) { break }\\n pos++\\n }\\n\\n if (pos < max && str.charCodeAt(pos) !== 0x0A) {\\n if (title) {\\n // garbage at the end of the line after title,\\n // but it could still be a valid reference if we roll back\\n title = ''\\n pos = destEndPos\\n nextLine = destEndLineNo\\n while (pos < max) {\\n const ch = str.charCodeAt(pos)\\n if (!isSpace(ch)) { break }\\n pos++\\n }\\n }\\n }\\n\\n if (pos < max && str.charCodeAt(pos) !== 0x0A) {\\n // garbage at the end of the line\\n return false\\n }\\n\\n const label = normalizeReference(str.slice(1, labelEnd))\\n if (!label) {\\n // CommonMark 0.20 disallows empty labels\\n return false\\n }\\n\\n // Reference can not terminate anything. This check is for safety only.\\n /* istanbul ignore if */\\n if (silent) { return true }\\n\\n if (typeof state.env.references === 'undefined') {\\n state.env.references = {}\\n }\\n if (typeof state.env.references[label] === 'undefined') {\\n state.env.references[label] = { title, href }\\n }\\n\\n state.line = nextLine\\n return true\\n}\\n\",\"// List of valid html blocks names, according to commonmark spec\\n// https://spec.commonmark.org/0.30/#html-blocks\\n\\nexport default [\\n 'address',\\n 'article',\\n 'aside',\\n 'base',\\n 'basefont',\\n 'blockquote',\\n 'body',\\n 'caption',\\n 'center',\\n 'col',\\n 'colgroup',\\n 'dd',\\n 'details',\\n 'dialog',\\n 'dir',\\n 'div',\\n 'dl',\\n 'dt',\\n 'fieldset',\\n 'figcaption',\\n 'figure',\\n 'footer',\\n 'form',\\n 'frame',\\n 'frameset',\\n 'h1',\\n 'h2',\\n 'h3',\\n 'h4',\\n 'h5',\\n 'h6',\\n 'head',\\n 'header',\\n 'hr',\\n 'html',\\n 'iframe',\\n 'legend',\\n 'li',\\n 'link',\\n 'main',\\n 'menu',\\n 'menuitem',\\n 'nav',\\n 'noframes',\\n 'ol',\\n 'optgroup',\\n 'option',\\n 'p',\\n 'param',\\n 'search',\\n 'section',\\n 'summary',\\n 'table',\\n 'tbody',\\n 'td',\\n 'tfoot',\\n 'th',\\n 'thead',\\n 'title',\\n 'tr',\\n 'track',\\n 'ul'\\n]\\n\",\"// Regexps to match html elements\\n\\nconst attr_name = '[a-zA-Z_:][a-zA-Z0-9:._-]*'\\n\\nconst unquoted = '[^\\\"\\\\'=<>`\\\\\\\\x00-\\\\\\\\x20]+'\\nconst single_quoted = \\\"'[^']*'\\\"\\nconst double_quoted = '\\\"[^\\\"]*\\\"'\\n\\nconst attr_value = '(?:' + unquoted + '|' + single_quoted + '|' + double_quoted + ')'\\n\\nconst attribute = '(?:\\\\\\\\s+' + attr_name + '(?:\\\\\\\\s*=\\\\\\\\s*' + attr_value + ')?)'\\n\\nconst open_tag = '<[A-Za-z][A-Za-z0-9\\\\\\\\-]*' + attribute + '*\\\\\\\\s*\\\\\\\\/?>'\\n\\nconst close_tag = '<\\\\\\\\/[A-Za-z][A-Za-z0-9\\\\\\\\-]*\\\\\\\\s*>'\\nconst comment = ''\\nconst processing = '<[?][\\\\\\\\s\\\\\\\\S]*?[?]>'\\nconst declaration = ']*>'\\nconst cdata = ''\\n\\nconst HTML_TAG_RE = new RegExp('^(?:' + open_tag + '|' + close_tag + '|' + comment +\\n '|' + processing + '|' + declaration + '|' + cdata + ')')\\nconst HTML_OPEN_CLOSE_TAG_RE = new RegExp('^(?:' + open_tag + '|' + close_tag + ')')\\n\\nexport { HTML_TAG_RE, HTML_OPEN_CLOSE_TAG_RE }\\n\",\"// HTML block\\n\\nimport block_names from '../common/html_blocks.mjs'\\nimport { HTML_OPEN_CLOSE_TAG_RE } from '../common/html_re.mjs'\\n\\n// An array of opening and corresponding closing sequences for html tags,\\n// last argument defines whether it can terminate a paragraph or not\\n//\\nconst HTML_SEQUENCES = [\\n [/^<(script|pre|style|textarea)(?=(\\\\s|>|$))/i, /<\\\\/(script|pre|style|textarea)>/i, true],\\n [/^/, true],\\n [/^<\\\\?/, /\\\\?>/, true],\\n [/^/, true],\\n [/^/, true],\\n [new RegExp('^|$))', 'i'), /^$/, true],\\n [new RegExp(HTML_OPEN_CLOSE_TAG_RE.source + '\\\\\\\\s*$'), /^$/, false]\\n]\\n\\nexport default function html_block (state, startLine, endLine, silent) {\\n let pos = state.bMarks[startLine] + state.tShift[startLine]\\n let max = state.eMarks[startLine]\\n\\n // if it's indented more than 3 spaces, it should be a code block\\n if (state.sCount[startLine] - state.blkIndent >= 4) { return false }\\n\\n if (!state.md.options.html) { return false }\\n\\n if (state.src.charCodeAt(pos) !== 0x3C/* < */) { return false }\\n\\n let lineText = state.src.slice(pos, max)\\n\\n let i = 0\\n for (; i < HTML_SEQUENCES.length; i++) {\\n if (HTML_SEQUENCES[i][0].test(lineText)) { break }\\n }\\n if (i === HTML_SEQUENCES.length) { return false }\\n\\n if (silent) {\\n // true if this sequence can be a terminator, false otherwise\\n return HTML_SEQUENCES[i][2]\\n }\\n\\n let nextLine = startLine + 1\\n\\n // If we are here - we detected HTML block.\\n // Let's roll down till block end.\\n if (!HTML_SEQUENCES[i][1].test(lineText)) {\\n for (; nextLine < endLine; nextLine++) {\\n if (state.sCount[nextLine] < state.blkIndent) { break }\\n\\n pos = state.bMarks[nextLine] + state.tShift[nextLine]\\n max = state.eMarks[nextLine]\\n lineText = state.src.slice(pos, max)\\n\\n if (HTML_SEQUENCES[i][1].test(lineText)) {\\n if (lineText.length !== 0) { nextLine++ }\\n break\\n }\\n }\\n }\\n\\n state.line = nextLine\\n\\n const token = state.push('html_block', '', 0)\\n token.map = [startLine, nextLine]\\n token.content = state.getLines(startLine, nextLine, state.blkIndent, true)\\n\\n return true\\n}\\n\",\"// heading (#, ##, ...)\\n\\nimport { isSpace } from '../common/utils.mjs'\\n\\nexport default function heading (state, startLine, endLine, silent) {\\n let pos = state.bMarks[startLine] + state.tShift[startLine]\\n let max = state.eMarks[startLine]\\n\\n // if it's indented more than 3 spaces, it should be a code block\\n if (state.sCount[startLine] - state.blkIndent >= 4) { return false }\\n\\n let ch = state.src.charCodeAt(pos)\\n\\n if (ch !== 0x23/* # */ || pos >= max) { return false }\\n\\n // count heading level\\n let level = 1\\n ch = state.src.charCodeAt(++pos)\\n while (ch === 0x23/* # */ && pos < max && level <= 6) {\\n level++\\n ch = state.src.charCodeAt(++pos)\\n }\\n\\n if (level > 6 || (pos < max && !isSpace(ch))) { return false }\\n\\n if (silent) { return true }\\n\\n // Let's cut tails like ' ### ' from the end of string\\n\\n max = state.skipSpacesBack(max, pos)\\n const tmp = state.skipCharsBack(max, 0x23, pos) // #\\n if (tmp > pos && isSpace(state.src.charCodeAt(tmp - 1))) {\\n max = tmp\\n }\\n\\n state.line = startLine + 1\\n\\n const token_o = state.push('heading_open', 'h' + String(level), 1)\\n token_o.markup = '########'.slice(0, level)\\n token_o.map = [startLine, state.line]\\n\\n const token_i = state.push('inline', '', 0)\\n token_i.content = state.src.slice(pos, max).trim()\\n token_i.map = [startLine, state.line]\\n token_i.children = []\\n\\n const token_c = state.push('heading_close', 'h' + String(level), -1)\\n token_c.markup = '########'.slice(0, level)\\n\\n return true\\n}\\n\",\"// lheading (---, ===)\\n\\nexport default function lheading (state, startLine, endLine/*, silent */) {\\n const terminatorRules = state.md.block.ruler.getRules('paragraph')\\n\\n // if it's indented more than 3 spaces, it should be a code block\\n if (state.sCount[startLine] - state.blkIndent >= 4) { return false }\\n\\n const oldParentType = state.parentType\\n state.parentType = 'paragraph' // use paragraph to match terminatorRules\\n\\n // jump line-by-line until empty one or EOF\\n let level = 0\\n let marker\\n let nextLine = startLine + 1\\n\\n for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) {\\n // this would be a code block normally, but after paragraph\\n // it's considered a lazy continuation regardless of what's there\\n if (state.sCount[nextLine] - state.blkIndent > 3) { continue }\\n\\n //\\n // Check for underline in setext header\\n //\\n if (state.sCount[nextLine] >= state.blkIndent) {\\n let pos = state.bMarks[nextLine] + state.tShift[nextLine]\\n const max = state.eMarks[nextLine]\\n\\n if (pos < max) {\\n marker = state.src.charCodeAt(pos)\\n\\n if (marker === 0x2D/* - */ || marker === 0x3D/* = */) {\\n pos = state.skipChars(pos, marker)\\n pos = state.skipSpaces(pos)\\n\\n if (pos >= max) {\\n level = (marker === 0x3D/* = */ ? 1 : 2)\\n break\\n }\\n }\\n }\\n }\\n\\n // quirk for blockquotes, this line should already be checked by that rule\\n if (state.sCount[nextLine] < 0) { continue }\\n\\n // Some tags can terminate paragraph without empty line.\\n let terminate = false\\n for (let i = 0, l = terminatorRules.length; i < l; i++) {\\n if (terminatorRules[i](state, nextLine, endLine, true)) {\\n terminate = true\\n break\\n }\\n }\\n if (terminate) { break }\\n }\\n\\n if (!level) {\\n // Didn't find valid underline\\n return false\\n }\\n\\n const content = state.getLines(startLine, nextLine, state.blkIndent, false).trim()\\n\\n state.line = nextLine + 1\\n\\n const token_o = state.push('heading_open', 'h' + String(level), 1)\\n token_o.markup = String.fromCharCode(marker)\\n token_o.map = [startLine, state.line]\\n\\n const token_i = state.push('inline', '', 0)\\n token_i.content = content\\n token_i.map = [startLine, state.line - 1]\\n token_i.children = []\\n\\n const token_c = state.push('heading_close', 'h' + String(level), -1)\\n token_c.markup = String.fromCharCode(marker)\\n\\n state.parentType = oldParentType\\n\\n return true\\n}\\n\",\"// Paragraph\\n\\nexport default function paragraph (state, startLine, endLine) {\\n const terminatorRules = state.md.block.ruler.getRules('paragraph')\\n const oldParentType = state.parentType\\n let nextLine = startLine + 1\\n state.parentType = 'paragraph'\\n\\n // jump line-by-line until empty one or EOF\\n for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) {\\n // this would be a code block normally, but after paragraph\\n // it's considered a lazy continuation regardless of what's there\\n if (state.sCount[nextLine] - state.blkIndent > 3) { continue }\\n\\n // quirk for blockquotes, this line should already be checked by that rule\\n if (state.sCount[nextLine] < 0) { continue }\\n\\n // Some tags can terminate paragraph without empty line.\\n let terminate = false\\n for (let i = 0, l = terminatorRules.length; i < l; i++) {\\n if (terminatorRules[i](state, nextLine, endLine, true)) {\\n terminate = true\\n break\\n }\\n }\\n if (terminate) { break }\\n }\\n\\n const content = state.getLines(startLine, nextLine, state.blkIndent, false).trim()\\n\\n state.line = nextLine\\n\\n const token_o = state.push('paragraph_open', 'p', 1)\\n token_o.map = [startLine, state.line]\\n\\n const token_i = state.push('inline', '', 0)\\n token_i.content = content\\n token_i.map = [startLine, state.line]\\n token_i.children = []\\n\\n state.push('paragraph_close', 'p', -1)\\n\\n state.parentType = oldParentType\\n\\n return true\\n}\\n\",\"/** internal\\n * class ParserBlock\\n *\\n * Block-level tokenizer.\\n **/\\n\\nimport Ruler from './ruler.mjs'\\nimport StateBlock from './rules_block/state_block.mjs'\\n\\nimport r_table from './rules_block/table.mjs'\\nimport r_code from './rules_block/code.mjs'\\nimport r_fence from './rules_block/fence.mjs'\\nimport r_blockquote from './rules_block/blockquote.mjs'\\nimport r_hr from './rules_block/hr.mjs'\\nimport r_list from './rules_block/list.mjs'\\nimport r_reference from './rules_block/reference.mjs'\\nimport r_html_block from './rules_block/html_block.mjs'\\nimport r_heading from './rules_block/heading.mjs'\\nimport r_lheading from './rules_block/lheading.mjs'\\nimport r_paragraph from './rules_block/paragraph.mjs'\\n\\nconst _rules = [\\n // First 2 params - rule name & source. Secondary array - list of rules,\\n // which can be terminated by this one.\\n ['table', r_table, ['paragraph', 'reference']],\\n ['code', r_code],\\n ['fence', r_fence, ['paragraph', 'reference', 'blockquote', 'list']],\\n ['blockquote', r_blockquote, ['paragraph', 'reference', 'blockquote', 'list']],\\n ['hr', r_hr, ['paragraph', 'reference', 'blockquote', 'list']],\\n ['list', r_list, ['paragraph', 'reference', 'blockquote']],\\n ['reference', r_reference],\\n ['html_block', r_html_block, ['paragraph', 'reference', 'blockquote']],\\n ['heading', r_heading, ['paragraph', 'reference', 'blockquote']],\\n ['lheading', r_lheading],\\n ['paragraph', r_paragraph]\\n]\\n\\n/**\\n * new ParserBlock()\\n **/\\nfunction ParserBlock () {\\n /**\\n * ParserBlock#ruler -> Ruler\\n *\\n * [[Ruler]] instance. Keep configuration of block rules.\\n **/\\n this.ruler = new Ruler()\\n\\n for (let i = 0; i < _rules.length; i++) {\\n this.ruler.push(_rules[i][0], _rules[i][1], { alt: (_rules[i][2] || []).slice() })\\n }\\n}\\n\\n// Generate tokens for input range\\n//\\nParserBlock.prototype.tokenize = function (state, startLine, endLine) {\\n const rules = this.ruler.getRules('')\\n const len = rules.length\\n const maxNesting = state.md.options.maxNesting\\n let line = startLine\\n let hasEmptyLines = false\\n\\n while (line < endLine) {\\n state.line = line = state.skipEmptyLines(line)\\n if (line >= endLine) { break }\\n\\n // Termination condition for nested calls.\\n // Nested calls currently used for blockquotes & lists\\n if (state.sCount[line] < state.blkIndent) { break }\\n\\n // If nesting level exceeded - skip tail to the end. That's not ordinary\\n // situation and we should not care about content.\\n if (state.level >= maxNesting) {\\n state.line = endLine\\n break\\n }\\n\\n // Try all possible rules.\\n // On success, rule should:\\n //\\n // - update `state.line`\\n // - update `state.tokens`\\n // - return true\\n const prevLine = state.line\\n let ok = false\\n\\n for (let i = 0; i < len; i++) {\\n ok = rules[i](state, line, endLine, false)\\n if (ok) {\\n if (prevLine >= state.line) {\\n throw new Error(\\\"block rule didn't increment state.line\\\")\\n }\\n break\\n }\\n }\\n\\n // this can only happen if user disables paragraph rule\\n if (!ok) throw new Error('none of the block rules matched')\\n\\n // set state.tight if we had an empty line before current tag\\n // i.e. latest empty line should not count\\n state.tight = !hasEmptyLines\\n\\n // paragraph might \\\"eat\\\" one newline after it in nested lists\\n if (state.isEmpty(state.line - 1)) {\\n hasEmptyLines = true\\n }\\n\\n line = state.line\\n\\n if (line < endLine && state.isEmpty(line)) {\\n hasEmptyLines = true\\n line++\\n state.line = line\\n }\\n }\\n}\\n\\n/**\\n * ParserBlock.parse(str, md, env, outTokens)\\n *\\n * Process input string and push block tokens into `outTokens`\\n **/\\nParserBlock.prototype.parse = function (src, md, env, outTokens) {\\n if (!src) { return }\\n\\n const state = new this.State(src, md, env, outTokens)\\n\\n this.tokenize(state, state.line, state.lineMax)\\n}\\n\\nParserBlock.prototype.State = StateBlock\\n\\nexport default ParserBlock\\n\",\"// Inline parser state\\n\\nimport Token from '../token.mjs'\\nimport { isWhiteSpace, isPunctChar, isMdAsciiPunct } from '../common/utils.mjs'\\n\\nfunction StateInline (src, md, env, outTokens) {\\n this.src = src\\n this.env = env\\n this.md = md\\n this.tokens = outTokens\\n this.tokens_meta = Array(outTokens.length)\\n\\n this.pos = 0\\n this.posMax = this.src.length\\n this.level = 0\\n this.pending = ''\\n this.pendingLevel = 0\\n\\n // Stores { start: end } pairs. Useful for backtrack\\n // optimization of pairs parse (emphasis, strikes).\\n this.cache = {}\\n\\n // List of emphasis-like delimiters for current tag\\n this.delimiters = []\\n\\n // Stack of delimiter lists for upper level tags\\n this._prev_delimiters = []\\n\\n // backtick length => last seen position\\n this.backticks = {}\\n this.backticksScanned = false\\n\\n // Counter used to disable inline linkify-it execution\\n // inside and markdown links\\n this.linkLevel = 0\\n}\\n\\n// Flush pending text\\n//\\nStateInline.prototype.pushPending = function () {\\n const token = new Token('text', '', 0)\\n token.content = this.pending\\n token.level = this.pendingLevel\\n this.tokens.push(token)\\n this.pending = ''\\n return token\\n}\\n\\n// Push new token to \\\"stream\\\".\\n// If pending text exists - flush it as text token\\n//\\nStateInline.prototype.push = function (type, tag, nesting) {\\n if (this.pending) {\\n this.pushPending()\\n }\\n\\n const token = new Token(type, tag, nesting)\\n let token_meta = null\\n\\n if (nesting < 0) {\\n // closing tag\\n this.level--\\n this.delimiters = this._prev_delimiters.pop()\\n }\\n\\n token.level = this.level\\n\\n if (nesting > 0) {\\n // opening tag\\n this.level++\\n this._prev_delimiters.push(this.delimiters)\\n this.delimiters = []\\n token_meta = { delimiters: this.delimiters }\\n }\\n\\n this.pendingLevel = this.level\\n this.tokens.push(token)\\n this.tokens_meta.push(token_meta)\\n return token\\n}\\n\\n// Scan a sequence of emphasis-like markers, and determine whether\\n// it can start an emphasis sequence or end an emphasis sequence.\\n//\\n// - start - position to scan from (it should point at a valid marker);\\n// - canSplitWord - determine if these markers can be found inside a word\\n//\\nStateInline.prototype.scanDelims = function (start, canSplitWord) {\\n const max = this.posMax\\n const marker = this.src.charCodeAt(start)\\n\\n // treat beginning of the line as a whitespace\\n const lastChar = start > 0 ? this.src.charCodeAt(start - 1) : 0x20\\n\\n let pos = start\\n while (pos < max && this.src.charCodeAt(pos) === marker) { pos++ }\\n\\n const count = pos - start\\n\\n // treat end of the line as a whitespace\\n const nextChar = pos < max ? this.src.charCodeAt(pos) : 0x20\\n\\n const isLastPunctChar = isMdAsciiPunct(lastChar) || isPunctChar(String.fromCharCode(lastChar))\\n const isNextPunctChar = isMdAsciiPunct(nextChar) || isPunctChar(String.fromCharCode(nextChar))\\n\\n const isLastWhiteSpace = isWhiteSpace(lastChar)\\n const isNextWhiteSpace = isWhiteSpace(nextChar)\\n\\n const left_flanking =\\n !isNextWhiteSpace && (!isNextPunctChar || isLastWhiteSpace || isLastPunctChar)\\n const right_flanking =\\n !isLastWhiteSpace && (!isLastPunctChar || isNextWhiteSpace || isNextPunctChar)\\n\\n const can_open = left_flanking && (canSplitWord || !right_flanking || isLastPunctChar)\\n const can_close = right_flanking && (canSplitWord || !left_flanking || isNextPunctChar)\\n\\n return { can_open, can_close, length: count }\\n}\\n\\n// re-export Token class to use in block rules\\nStateInline.prototype.Token = Token\\n\\nexport default StateInline\\n\",\"// Skip text characters for text token, place those to pending buffer\\n// and increment current pos\\n\\n// Rule to skip pure text\\n// '{}$%@~+=:' reserved for extentions\\n\\n// !, \\\", #, $, %, &, ', (, ), *, +, ,, -, ., /, :, ;, <, =, >, ?, @, [, \\\\, ], ^, _, `, {, |, }, or ~\\n\\n// !!!! Don't confuse with \\\"Markdown ASCII Punctuation\\\" chars\\n// http://spec.commonmark.org/0.15/#ascii-punctuation-character\\nfunction isTerminatorChar (ch) {\\n switch (ch) {\\n case 0x0A/* \\\\n */:\\n case 0x21/* ! */:\\n case 0x23/* # */:\\n case 0x24/* $ */:\\n case 0x25/* % */:\\n case 0x26/* & */:\\n case 0x2A/* * */:\\n case 0x2B/* + */:\\n case 0x2D/* - */:\\n case 0x3A/* : */:\\n case 0x3C/* < */:\\n case 0x3D/* = */:\\n case 0x3E/* > */:\\n case 0x40/* @ */:\\n case 0x5B/* [ */:\\n case 0x5C/* \\\\ */:\\n case 0x5D/* ] */:\\n case 0x5E/* ^ */:\\n case 0x5F/* _ */:\\n case 0x60/* ` */:\\n case 0x7B/* { */:\\n case 0x7D/* } */:\\n case 0x7E/* ~ */:\\n return true\\n default:\\n return false\\n }\\n}\\n\\nexport default function text (state, silent) {\\n let pos = state.pos\\n\\n while (pos < state.posMax && !isTerminatorChar(state.src.charCodeAt(pos))) {\\n pos++\\n }\\n\\n if (pos === state.pos) { return false }\\n\\n if (!silent) { state.pending += state.src.slice(state.pos, pos) }\\n\\n state.pos = pos\\n\\n return true\\n}\\n\\n// Alternative implementation, for memory.\\n//\\n// It costs 10% of performance, but allows extend terminators list, if place it\\n// to `ParserInline` property. Probably, will switch to it sometime, such\\n// flexibility required.\\n\\n/*\\nvar TERMINATOR_RE = /[\\\\n!#$%&*+\\\\-:<=>@[\\\\\\\\\\\\]^_`{}~]/;\\n\\nmodule.exports = function text(state, silent) {\\n var pos = state.pos,\\n idx = state.src.slice(pos).search(TERMINATOR_RE);\\n\\n // first char is terminator -> empty text\\n if (idx === 0) { return false; }\\n\\n // no terminator -> text till end of string\\n if (idx < 0) {\\n if (!silent) { state.pending += state.src.slice(pos); }\\n state.pos = state.src.length;\\n return true;\\n }\\n\\n if (!silent) { state.pending += state.src.slice(pos, pos + idx); }\\n\\n state.pos += idx;\\n\\n return true;\\n}; */\\n\",\"// Process links like https://example.org/\\n\\n// RFC3986: scheme = ALPHA *( ALPHA / DIGIT / \\\"+\\\" / \\\"-\\\" / \\\".\\\" )\\nconst SCHEME_RE = /(?:^|[^a-z0-9.+-])([a-z][a-z0-9.+-]*)$/i\\n\\nexport default function linkify (state, silent) {\\n if (!state.md.options.linkify) return false\\n if (state.linkLevel > 0) return false\\n\\n const pos = state.pos\\n const max = state.posMax\\n\\n if (pos + 3 > max) return false\\n if (state.src.charCodeAt(pos) !== 0x3A/* : */) return false\\n if (state.src.charCodeAt(pos + 1) !== 0x2F/* / */) return false\\n if (state.src.charCodeAt(pos + 2) !== 0x2F/* / */) return false\\n\\n const match = state.pending.match(SCHEME_RE)\\n if (!match) return false\\n\\n const proto = match[1]\\n\\n const link = state.md.linkify.matchAtStart(state.src.slice(pos - proto.length))\\n if (!link) return false\\n\\n let url = link.url\\n\\n // invalid link, but still detected by linkify somehow;\\n // need to check to prevent infinite loop below\\n if (url.length <= proto.length) return false\\n\\n // disallow '*' at the end of the link (conflicts with emphasis)\\n // do manual backsearch to avoid perf issues with regex /\\\\*+$/ on \\\"****...****a\\\".\\n let urlEnd = url.length\\n while (urlEnd > 0 && url.charCodeAt(urlEnd - 1) === 0x2A/* * */) {\\n urlEnd--\\n }\\n if (urlEnd !== url.length) {\\n url = url.slice(0, urlEnd)\\n }\\n\\n const fullUrl = state.md.normalizeLink(url)\\n if (!state.md.validateLink(fullUrl)) return false\\n\\n if (!silent) {\\n state.pending = state.pending.slice(0, -proto.length)\\n\\n const token_o = state.push('link_open', 'a', 1)\\n token_o.attrs = [['href', fullUrl]]\\n token_o.markup = 'linkify'\\n token_o.info = 'auto'\\n\\n const token_t = state.push('text', '', 0)\\n token_t.content = state.md.normalizeLinkText(url)\\n\\n const token_c = state.push('link_close', 'a', -1)\\n token_c.markup = 'linkify'\\n token_c.info = 'auto'\\n }\\n\\n state.pos += url.length - proto.length\\n return true\\n}\\n\",\"// Proceess '\\\\n'\\n\\nimport { isSpace } from '../common/utils.mjs'\\n\\nexport default function newline (state, silent) {\\n let pos = state.pos\\n\\n if (state.src.charCodeAt(pos) !== 0x0A/* \\\\n */) { return false }\\n\\n const pmax = state.pending.length - 1\\n const max = state.posMax\\n\\n // ' \\\\n' -> hardbreak\\n // Lookup in pending chars is bad practice! Don't copy to other rules!\\n // Pending string is stored in concat mode, indexed lookups will cause\\n // convertion to flat mode.\\n if (!silent) {\\n if (pmax >= 0 && state.pending.charCodeAt(pmax) === 0x20) {\\n if (pmax >= 1 && state.pending.charCodeAt(pmax - 1) === 0x20) {\\n // Find whitespaces tail of pending chars.\\n let ws = pmax - 1\\n while (ws >= 1 && state.pending.charCodeAt(ws - 1) === 0x20) ws--\\n\\n state.pending = state.pending.slice(0, ws)\\n state.push('hardbreak', 'br', 0)\\n } else {\\n state.pending = state.pending.slice(0, -1)\\n state.push('softbreak', 'br', 0)\\n }\\n } else {\\n state.push('softbreak', 'br', 0)\\n }\\n }\\n\\n pos++\\n\\n // skip heading spaces for next line\\n while (pos < max && isSpace(state.src.charCodeAt(pos))) { pos++ }\\n\\n state.pos = pos\\n return true\\n}\\n\",\"// Process escaped chars and hardbreaks\\n\\nimport { isSpace } from '../common/utils.mjs'\\n\\nconst ESCAPED = []\\n\\nfor (let i = 0; i < 256; i++) { ESCAPED.push(0) }\\n\\n'\\\\\\\\!\\\"#$%&\\\\'()*+,./:;<=>?@[]^_`{|}~-'\\n .split('').forEach(function (ch) { ESCAPED[ch.charCodeAt(0)] = 1 })\\n\\nexport default function escape (state, silent) {\\n let pos = state.pos\\n const max = state.posMax\\n\\n if (state.src.charCodeAt(pos) !== 0x5C/* \\\\ */) return false\\n pos++\\n\\n // '\\\\' at the end of the inline block\\n if (pos >= max) return false\\n\\n let ch1 = state.src.charCodeAt(pos)\\n\\n if (ch1 === 0x0A) {\\n if (!silent) {\\n state.push('hardbreak', 'br', 0)\\n }\\n\\n pos++\\n // skip leading whitespaces from next line\\n while (pos < max) {\\n ch1 = state.src.charCodeAt(pos)\\n if (!isSpace(ch1)) break\\n pos++\\n }\\n\\n state.pos = pos\\n return true\\n }\\n\\n let escapedStr = state.src[pos]\\n\\n if (ch1 >= 0xD800 && ch1 <= 0xDBFF && pos + 1 < max) {\\n const ch2 = state.src.charCodeAt(pos + 1)\\n\\n if (ch2 >= 0xDC00 && ch2 <= 0xDFFF) {\\n escapedStr += state.src[pos + 1]\\n pos++\\n }\\n }\\n\\n const origStr = '\\\\\\\\' + escapedStr\\n\\n if (!silent) {\\n const token = state.push('text_special', '', 0)\\n\\n if (ch1 < 256 && ESCAPED[ch1] !== 0) {\\n token.content = escapedStr\\n } else {\\n token.content = origStr\\n }\\n\\n token.markup = origStr\\n token.info = 'escape'\\n }\\n\\n state.pos = pos + 1\\n return true\\n}\\n\",\"// Parse backticks\\n\\nexport default function backtick (state, silent) {\\n let pos = state.pos\\n const ch = state.src.charCodeAt(pos)\\n\\n if (ch !== 0x60/* ` */) { return false }\\n\\n const start = pos\\n pos++\\n const max = state.posMax\\n\\n // scan marker length\\n while (pos < max && state.src.charCodeAt(pos) === 0x60/* ` */) { pos++ }\\n\\n const marker = state.src.slice(start, pos)\\n const openerLength = marker.length\\n\\n if (state.backticksScanned && (state.backticks[openerLength] || 0) <= start) {\\n if (!silent) state.pending += marker\\n state.pos += openerLength\\n return true\\n }\\n\\n let matchEnd = pos\\n let matchStart\\n\\n // Nothing found in the cache, scan until the end of the line (or until marker is found)\\n while ((matchStart = state.src.indexOf('`', matchEnd)) !== -1) {\\n matchEnd = matchStart + 1\\n\\n // scan marker length\\n while (matchEnd < max && state.src.charCodeAt(matchEnd) === 0x60/* ` */) { matchEnd++ }\\n\\n const closerLength = matchEnd - matchStart\\n\\n if (closerLength === openerLength) {\\n // Found matching closer length.\\n if (!silent) {\\n const token = state.push('code_inline', 'code', 0)\\n token.markup = marker\\n token.content = state.src.slice(pos, matchStart)\\n .replace(/\\\\n/g, ' ')\\n .replace(/^ (.+) $/, '$1')\\n }\\n state.pos = matchEnd\\n return true\\n }\\n\\n // Some different length found, put it in cache as upper limit of where closer can be found\\n state.backticks[closerLength] = matchStart\\n }\\n\\n // Scanned through the end, didn't find anything\\n state.backticksScanned = true\\n\\n if (!silent) state.pending += marker\\n state.pos += openerLength\\n return true\\n}\\n\",\"// ~~strike through~~\\n//\\n\\n// Insert each marker as a separate text token, and add it to delimiter list\\n//\\nfunction strikethrough_tokenize (state, silent) {\\n const start = state.pos\\n const marker = state.src.charCodeAt(start)\\n\\n if (silent) { return false }\\n\\n if (marker !== 0x7E/* ~ */) { return false }\\n\\n const scanned = state.scanDelims(state.pos, true)\\n let len = scanned.length\\n const ch = String.fromCharCode(marker)\\n\\n if (len < 2) { return false }\\n\\n let token\\n\\n if (len % 2) {\\n token = state.push('text', '', 0)\\n token.content = ch\\n len--\\n }\\n\\n for (let i = 0; i < len; i += 2) {\\n token = state.push('text', '', 0)\\n token.content = ch + ch\\n\\n state.delimiters.push({\\n marker,\\n length: 0, // disable \\\"rule of 3\\\" length checks meant for emphasis\\n token: state.tokens.length - 1,\\n end: -1,\\n open: scanned.can_open,\\n close: scanned.can_close\\n })\\n }\\n\\n state.pos += scanned.length\\n\\n return true\\n}\\n\\nfunction postProcess (state, delimiters) {\\n let token\\n const loneMarkers = []\\n const max = delimiters.length\\n\\n for (let i = 0; i < max; i++) {\\n const startDelim = delimiters[i]\\n\\n if (startDelim.marker !== 0x7E/* ~ */) {\\n continue\\n }\\n\\n if (startDelim.end === -1) {\\n continue\\n }\\n\\n const endDelim = delimiters[startDelim.end]\\n\\n token = state.tokens[startDelim.token]\\n token.type = 's_open'\\n token.tag = 's'\\n token.nesting = 1\\n token.markup = '~~'\\n token.content = ''\\n\\n token = state.tokens[endDelim.token]\\n token.type = 's_close'\\n token.tag = 's'\\n token.nesting = -1\\n token.markup = '~~'\\n token.content = ''\\n\\n if (state.tokens[endDelim.token - 1].type === 'text' &&\\n state.tokens[endDelim.token - 1].content === '~') {\\n loneMarkers.push(endDelim.token - 1)\\n }\\n }\\n\\n // If a marker sequence has an odd number of characters, it's splitted\\n // like this: `~~~~~` -> `~` + `~~` + `~~`, leaving one marker at the\\n // start of the sequence.\\n //\\n // So, we have to move all those markers after subsequent s_close tags.\\n //\\n while (loneMarkers.length) {\\n const i = loneMarkers.pop()\\n let j = i + 1\\n\\n while (j < state.tokens.length && state.tokens[j].type === 's_close') {\\n j++\\n }\\n\\n j--\\n\\n if (i !== j) {\\n token = state.tokens[j]\\n state.tokens[j] = state.tokens[i]\\n state.tokens[i] = token\\n }\\n }\\n}\\n\\n// Walk through delimiter list and replace text tokens with tags\\n//\\nfunction strikethrough_postProcess (state) {\\n const tokens_meta = state.tokens_meta\\n const max = state.tokens_meta.length\\n\\n postProcess(state, state.delimiters)\\n\\n for (let curr = 0; curr < max; curr++) {\\n if (tokens_meta[curr] && tokens_meta[curr].delimiters) {\\n postProcess(state, tokens_meta[curr].delimiters)\\n }\\n }\\n}\\n\\nexport default {\\n tokenize: strikethrough_tokenize,\\n postProcess: strikethrough_postProcess\\n}\\n\",\"// Process *this* and _that_\\n//\\n\\n// Insert each marker as a separate text token, and add it to delimiter list\\n//\\nfunction emphasis_tokenize (state, silent) {\\n const start = state.pos\\n const marker = state.src.charCodeAt(start)\\n\\n if (silent) { return false }\\n\\n if (marker !== 0x5F /* _ */ && marker !== 0x2A /* * */) { return false }\\n\\n const scanned = state.scanDelims(state.pos, marker === 0x2A)\\n\\n for (let i = 0; i < scanned.length; i++) {\\n const token = state.push('text', '', 0)\\n token.content = String.fromCharCode(marker)\\n\\n state.delimiters.push({\\n // Char code of the starting marker (number).\\n //\\n marker,\\n\\n // Total length of these series of delimiters.\\n //\\n length: scanned.length,\\n\\n // A position of the token this delimiter corresponds to.\\n //\\n token: state.tokens.length - 1,\\n\\n // If this delimiter is matched as a valid opener, `end` will be\\n // equal to its position, otherwise it's `-1`.\\n //\\n end: -1,\\n\\n // Boolean flags that determine if this delimiter could open or close\\n // an emphasis.\\n //\\n open: scanned.can_open,\\n close: scanned.can_close\\n })\\n }\\n\\n state.pos += scanned.length\\n\\n return true\\n}\\n\\nfunction postProcess (state, delimiters) {\\n const max = delimiters.length\\n\\n for (let i = max - 1; i >= 0; i--) {\\n const startDelim = delimiters[i]\\n\\n if (startDelim.marker !== 0x5F/* _ */ && startDelim.marker !== 0x2A/* * */) {\\n continue\\n }\\n\\n // Process only opening markers\\n if (startDelim.end === -1) {\\n continue\\n }\\n\\n const endDelim = delimiters[startDelim.end]\\n\\n // If the previous delimiter has the same marker and is adjacent to this one,\\n // merge those into one strong delimiter.\\n //\\n // `whatever` -> `whatever`\\n //\\n const isStrong = i > 0 &&\\n delimiters[i - 1].end === startDelim.end + 1 &&\\n // check that first two markers match and adjacent\\n delimiters[i - 1].marker === startDelim.marker &&\\n delimiters[i - 1].token === startDelim.token - 1 &&\\n // check that last two markers are adjacent (we can safely assume they match)\\n delimiters[startDelim.end + 1].token === endDelim.token + 1\\n\\n const ch = String.fromCharCode(startDelim.marker)\\n\\n const token_o = state.tokens[startDelim.token]\\n token_o.type = isStrong ? 'strong_open' : 'em_open'\\n token_o.tag = isStrong ? 'strong' : 'em'\\n token_o.nesting = 1\\n token_o.markup = isStrong ? ch + ch : ch\\n token_o.content = ''\\n\\n const token_c = state.tokens[endDelim.token]\\n token_c.type = isStrong ? 'strong_close' : 'em_close'\\n token_c.tag = isStrong ? 'strong' : 'em'\\n token_c.nesting = -1\\n token_c.markup = isStrong ? ch + ch : ch\\n token_c.content = ''\\n\\n if (isStrong) {\\n state.tokens[delimiters[i - 1].token].content = ''\\n state.tokens[delimiters[startDelim.end + 1].token].content = ''\\n i--\\n }\\n }\\n}\\n\\n// Walk through delimiter list and replace text tokens with tags\\n//\\nfunction emphasis_post_process (state) {\\n const tokens_meta = state.tokens_meta\\n const max = state.tokens_meta.length\\n\\n postProcess(state, state.delimiters)\\n\\n for (let curr = 0; curr < max; curr++) {\\n if (tokens_meta[curr] && tokens_meta[curr].delimiters) {\\n postProcess(state, tokens_meta[curr].delimiters)\\n }\\n }\\n}\\n\\nexport default {\\n tokenize: emphasis_tokenize,\\n postProcess: emphasis_post_process\\n}\\n\",\"// Process [link]( \\\"stuff\\\")\\n\\nimport { normalizeReference, isSpace } from '../common/utils.mjs'\\n\\nexport default function link (state, silent) {\\n let code, label, res, ref\\n let href = ''\\n let title = ''\\n let start = state.pos\\n let parseReference = true\\n\\n if (state.src.charCodeAt(state.pos) !== 0x5B/* [ */) { return false }\\n\\n const oldPos = state.pos\\n const max = state.posMax\\n const labelStart = state.pos + 1\\n const labelEnd = state.md.helpers.parseLinkLabel(state, state.pos, true)\\n\\n // parser failed to find ']', so it's not a valid link\\n if (labelEnd < 0) { return false }\\n\\n let pos = labelEnd + 1\\n if (pos < max && state.src.charCodeAt(pos) === 0x28/* ( */) {\\n //\\n // Inline link\\n //\\n\\n // might have found a valid shortcut link, disable reference parsing\\n parseReference = false\\n\\n // [link]( \\\"title\\\" )\\n // ^^ skipping these spaces\\n pos++\\n for (; pos < max; pos++) {\\n code = state.src.charCodeAt(pos)\\n if (!isSpace(code) && code !== 0x0A) { break }\\n }\\n if (pos >= max) { return false }\\n\\n // [link]( \\\"title\\\" )\\n // ^^^^^^ parsing link destination\\n start = pos\\n res = state.md.helpers.parseLinkDestination(state.src, pos, state.posMax)\\n if (res.ok) {\\n href = state.md.normalizeLink(res.str)\\n if (state.md.validateLink(href)) {\\n pos = res.pos\\n } else {\\n href = ''\\n }\\n\\n // [link]( \\\"title\\\" )\\n // ^^ skipping these spaces\\n start = pos\\n for (; pos < max; pos++) {\\n code = state.src.charCodeAt(pos)\\n if (!isSpace(code) && code !== 0x0A) { break }\\n }\\n\\n // [link]( \\\"title\\\" )\\n // ^^^^^^^ parsing link title\\n res = state.md.helpers.parseLinkTitle(state.src, pos, state.posMax)\\n if (pos < max && start !== pos && res.ok) {\\n title = res.str\\n pos = res.pos\\n\\n // [link]( \\\"title\\\" )\\n // ^^ skipping these spaces\\n for (; pos < max; pos++) {\\n code = state.src.charCodeAt(pos)\\n if (!isSpace(code) && code !== 0x0A) { break }\\n }\\n }\\n }\\n\\n if (pos >= max || state.src.charCodeAt(pos) !== 0x29/* ) */) {\\n // parsing a valid shortcut link failed, fallback to reference\\n parseReference = true\\n }\\n pos++\\n }\\n\\n if (parseReference) {\\n //\\n // Link reference\\n //\\n if (typeof state.env.references === 'undefined') { return false }\\n\\n if (pos < max && state.src.charCodeAt(pos) === 0x5B/* [ */) {\\n start = pos + 1\\n pos = state.md.helpers.parseLinkLabel(state, pos)\\n if (pos >= 0) {\\n label = state.src.slice(start, pos++)\\n } else {\\n pos = labelEnd + 1\\n }\\n } else {\\n pos = labelEnd + 1\\n }\\n\\n // covers label === '' and label === undefined\\n // (collapsed reference link and shortcut reference link respectively)\\n if (!label) { label = state.src.slice(labelStart, labelEnd) }\\n\\n ref = state.env.references[normalizeReference(label)]\\n if (!ref) {\\n state.pos = oldPos\\n return false\\n }\\n href = ref.href\\n title = ref.title\\n }\\n\\n //\\n // We found the end of the link, and know for a fact it's a valid link;\\n // so all that's left to do is to call tokenizer.\\n //\\n if (!silent) {\\n state.pos = labelStart\\n state.posMax = labelEnd\\n\\n const token_o = state.push('link_open', 'a', 1)\\n const attrs = [['href', href]]\\n token_o.attrs = attrs\\n if (title) {\\n attrs.push(['title', title])\\n }\\n\\n state.linkLevel++\\n state.md.inline.tokenize(state)\\n state.linkLevel--\\n\\n state.push('link_close', 'a', -1)\\n }\\n\\n state.pos = pos\\n state.posMax = max\\n return true\\n}\\n\",\"// Process ![image]( \\\"title\\\")\\n\\nimport { normalizeReference, isSpace } from '../common/utils.mjs'\\n\\nexport default function image (state, silent) {\\n let code, content, label, pos, ref, res, title, start\\n let href = ''\\n const oldPos = state.pos\\n const max = state.posMax\\n\\n if (state.src.charCodeAt(state.pos) !== 0x21/* ! */) { return false }\\n if (state.src.charCodeAt(state.pos + 1) !== 0x5B/* [ */) { return false }\\n\\n const labelStart = state.pos + 2\\n const labelEnd = state.md.helpers.parseLinkLabel(state, state.pos + 1, false)\\n\\n // parser failed to find ']', so it's not a valid link\\n if (labelEnd < 0) { return false }\\n\\n pos = labelEnd + 1\\n if (pos < max && state.src.charCodeAt(pos) === 0x28/* ( */) {\\n //\\n // Inline link\\n //\\n\\n // [link]( \\\"title\\\" )\\n // ^^ skipping these spaces\\n pos++\\n for (; pos < max; pos++) {\\n code = state.src.charCodeAt(pos)\\n if (!isSpace(code) && code !== 0x0A) { break }\\n }\\n if (pos >= max) { return false }\\n\\n // [link]( \\\"title\\\" )\\n // ^^^^^^ parsing link destination\\n start = pos\\n res = state.md.helpers.parseLinkDestination(state.src, pos, state.posMax)\\n if (res.ok) {\\n href = state.md.normalizeLink(res.str)\\n if (state.md.validateLink(href)) {\\n pos = res.pos\\n } else {\\n href = ''\\n }\\n }\\n\\n // [link]( \\\"title\\\" )\\n // ^^ skipping these spaces\\n start = pos\\n for (; pos < max; pos++) {\\n code = state.src.charCodeAt(pos)\\n if (!isSpace(code) && code !== 0x0A) { break }\\n }\\n\\n // [link]( \\\"title\\\" )\\n // ^^^^^^^ parsing link title\\n res = state.md.helpers.parseLinkTitle(state.src, pos, state.posMax)\\n if (pos < max && start !== pos && res.ok) {\\n title = res.str\\n pos = res.pos\\n\\n // [link]( \\\"title\\\" )\\n // ^^ skipping these spaces\\n for (; pos < max; pos++) {\\n code = state.src.charCodeAt(pos)\\n if (!isSpace(code) && code !== 0x0A) { break }\\n }\\n } else {\\n title = ''\\n }\\n\\n if (pos >= max || state.src.charCodeAt(pos) !== 0x29/* ) */) {\\n state.pos = oldPos\\n return false\\n }\\n pos++\\n } else {\\n //\\n // Link reference\\n //\\n if (typeof state.env.references === 'undefined') { return false }\\n\\n if (pos < max && state.src.charCodeAt(pos) === 0x5B/* [ */) {\\n start = pos + 1\\n pos = state.md.helpers.parseLinkLabel(state, pos)\\n if (pos >= 0) {\\n label = state.src.slice(start, pos++)\\n } else {\\n pos = labelEnd + 1\\n }\\n } else {\\n pos = labelEnd + 1\\n }\\n\\n // covers label === '' and label === undefined\\n // (collapsed reference link and shortcut reference link respectively)\\n if (!label) { label = state.src.slice(labelStart, labelEnd) }\\n\\n ref = state.env.references[normalizeReference(label)]\\n if (!ref) {\\n state.pos = oldPos\\n return false\\n }\\n href = ref.href\\n title = ref.title\\n }\\n\\n //\\n // We found the end of the link, and know for a fact it's a valid link;\\n // so all that's left to do is to call tokenizer.\\n //\\n if (!silent) {\\n content = state.src.slice(labelStart, labelEnd)\\n\\n const tokens = []\\n state.md.inline.parse(\\n content,\\n state.md,\\n state.env,\\n tokens\\n )\\n\\n const token = state.push('image', 'img', 0)\\n const attrs = [['src', href], ['alt', '']]\\n token.attrs = attrs\\n token.children = tokens\\n token.content = content\\n\\n if (title) {\\n attrs.push(['title', title])\\n }\\n }\\n\\n state.pos = pos\\n state.posMax = max\\n return true\\n}\\n\",\"// Process autolinks ''\\n\\n/* eslint max-len:0 */\\nconst EMAIL_RE = /^([a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)$/\\n/* eslint-disable-next-line no-control-regex */\\nconst AUTOLINK_RE = /^([a-zA-Z][a-zA-Z0-9+.-]{1,31}):([^<>\\\\x00-\\\\x20]*)$/\\n\\nexport default function autolink (state, silent) {\\n let pos = state.pos\\n\\n if (state.src.charCodeAt(pos) !== 0x3C/* < */) { return false }\\n\\n const start = state.pos\\n const max = state.posMax\\n\\n for (;;) {\\n if (++pos >= max) return false\\n\\n const ch = state.src.charCodeAt(pos)\\n\\n if (ch === 0x3C /* < */) return false\\n if (ch === 0x3E /* > */) break\\n }\\n\\n const url = state.src.slice(start + 1, pos)\\n\\n if (AUTOLINK_RE.test(url)) {\\n const fullUrl = state.md.normalizeLink(url)\\n if (!state.md.validateLink(fullUrl)) { return false }\\n\\n if (!silent) {\\n const token_o = state.push('link_open', 'a', 1)\\n token_o.attrs = [['href', fullUrl]]\\n token_o.markup = 'autolink'\\n token_o.info = 'auto'\\n\\n const token_t = state.push('text', '', 0)\\n token_t.content = state.md.normalizeLinkText(url)\\n\\n const token_c = state.push('link_close', 'a', -1)\\n token_c.markup = 'autolink'\\n token_c.info = 'auto'\\n }\\n\\n state.pos += url.length + 2\\n return true\\n }\\n\\n if (EMAIL_RE.test(url)) {\\n const fullUrl = state.md.normalizeLink('mailto:' + url)\\n if (!state.md.validateLink(fullUrl)) { return false }\\n\\n if (!silent) {\\n const token_o = state.push('link_open', 'a', 1)\\n token_o.attrs = [['href', fullUrl]]\\n token_o.markup = 'autolink'\\n token_o.info = 'auto'\\n\\n const token_t = state.push('text', '', 0)\\n token_t.content = state.md.normalizeLinkText(url)\\n\\n const token_c = state.push('link_close', 'a', -1)\\n token_c.markup = 'autolink'\\n token_c.info = 'auto'\\n }\\n\\n state.pos += url.length + 2\\n return true\\n }\\n\\n return false\\n}\\n\",\"// Process html tags\\n\\nimport { HTML_TAG_RE } from '../common/html_re.mjs'\\n\\nfunction isLinkOpen (str) {\\n return /^\\\\s]/i.test(str)\\n}\\nfunction isLinkClose (str) {\\n return /^<\\\\/a\\\\s*>/i.test(str)\\n}\\n\\nfunction isLetter (ch) {\\n /* eslint no-bitwise:0 */\\n const lc = ch | 0x20 // to lower case\\n return (lc >= 0x61/* a */) && (lc <= 0x7a/* z */)\\n}\\n\\nexport default function html_inline (state, silent) {\\n if (!state.md.options.html) { return false }\\n\\n // Check start\\n const max = state.posMax\\n const pos = state.pos\\n if (state.src.charCodeAt(pos) !== 0x3C/* < */ ||\\n pos + 2 >= max) {\\n return false\\n }\\n\\n // Quick fail on second char\\n const ch = state.src.charCodeAt(pos + 1)\\n if (ch !== 0x21/* ! */ &&\\n ch !== 0x3F/* ? */ &&\\n ch !== 0x2F/* / */ &&\\n !isLetter(ch)) {\\n return false\\n }\\n\\n const match = state.src.slice(pos).match(HTML_TAG_RE)\\n if (!match) { return false }\\n\\n if (!silent) {\\n const token = state.push('html_inline', '', 0)\\n token.content = match[0]\\n\\n if (isLinkOpen(token.content)) state.linkLevel++\\n if (isLinkClose(token.content)) state.linkLevel--\\n }\\n state.pos += match[0].length\\n return true\\n}\\n\",\"// Process html entity - {, ¯, ", ...\\n\\nimport { decodeHTML } from 'entities'\\nimport { isValidEntityCode, fromCodePoint } from '../common/utils.mjs'\\n\\nconst DIGITAL_RE = /^&#((?:x[a-f0-9]{1,6}|[0-9]{1,7}));/i\\nconst NAMED_RE = /^&([a-z][a-z0-9]{1,31});/i\\n\\nexport default function entity (state, silent) {\\n const pos = state.pos\\n const max = state.posMax\\n\\n if (state.src.charCodeAt(pos) !== 0x26/* & */) return false\\n\\n if (pos + 1 >= max) return false\\n\\n const ch = state.src.charCodeAt(pos + 1)\\n\\n if (ch === 0x23 /* # */) {\\n const match = state.src.slice(pos).match(DIGITAL_RE)\\n if (match) {\\n if (!silent) {\\n const code = match[1][0].toLowerCase() === 'x' ? parseInt(match[1].slice(1), 16) : parseInt(match[1], 10)\\n\\n const token = state.push('text_special', '', 0)\\n token.content = isValidEntityCode(code) ? fromCodePoint(code) : fromCodePoint(0xFFFD)\\n token.markup = match[0]\\n token.info = 'entity'\\n }\\n state.pos += match[0].length\\n return true\\n }\\n } else {\\n const match = state.src.slice(pos).match(NAMED_RE)\\n if (match) {\\n const decoded = decodeHTML(match[0])\\n if (decoded !== match[0]) {\\n if (!silent) {\\n const token = state.push('text_special', '', 0)\\n token.content = decoded\\n token.markup = match[0]\\n token.info = 'entity'\\n }\\n state.pos += match[0].length\\n return true\\n }\\n }\\n }\\n\\n return false\\n}\\n\",\"// For each opening emphasis-like marker find a matching closing one\\n//\\n\\nfunction processDelimiters (delimiters) {\\n const openersBottom = {}\\n const max = delimiters.length\\n\\n if (!max) return\\n\\n // headerIdx is the first delimiter of the current (where closer is) delimiter run\\n let headerIdx = 0\\n let lastTokenIdx = -2 // needs any value lower than -1\\n const jumps = []\\n\\n for (let closerIdx = 0; closerIdx < max; closerIdx++) {\\n const closer = delimiters[closerIdx]\\n\\n jumps.push(0)\\n\\n // markers belong to same delimiter run if:\\n // - they have adjacent tokens\\n // - AND markers are the same\\n //\\n if (delimiters[headerIdx].marker !== closer.marker || lastTokenIdx !== closer.token - 1) {\\n headerIdx = closerIdx\\n }\\n\\n lastTokenIdx = closer.token\\n\\n // Length is only used for emphasis-specific \\\"rule of 3\\\",\\n // if it's not defined (in strikethrough or 3rd party plugins),\\n // we can default it to 0 to disable those checks.\\n //\\n closer.length = closer.length || 0\\n\\n if (!closer.close) continue\\n\\n // Previously calculated lower bounds (previous fails)\\n // for each marker, each delimiter length modulo 3,\\n // and for whether this closer can be an opener;\\n // https://github.com/commonmark/cmark/commit/34250e12ccebdc6372b8b49c44fab57c72443460\\n /* eslint-disable-next-line no-prototype-builtins */\\n if (!openersBottom.hasOwnProperty(closer.marker)) {\\n openersBottom[closer.marker] = [-1, -1, -1, -1, -1, -1]\\n }\\n\\n const minOpenerIdx = openersBottom[closer.marker][(closer.open ? 3 : 0) + (closer.length % 3)]\\n\\n let openerIdx = headerIdx - jumps[headerIdx] - 1\\n\\n let newMinOpenerIdx = openerIdx\\n\\n for (; openerIdx > minOpenerIdx; openerIdx -= jumps[openerIdx] + 1) {\\n const opener = delimiters[openerIdx]\\n\\n if (opener.marker !== closer.marker) continue\\n\\n if (opener.open && opener.end < 0) {\\n let isOddMatch = false\\n\\n // from spec:\\n //\\n // If one of the delimiters can both open and close emphasis, then the\\n // sum of the lengths of the delimiter runs containing the opening and\\n // closing delimiters must not be a multiple of 3 unless both lengths\\n // are multiples of 3.\\n //\\n if (opener.close || closer.open) {\\n if ((opener.length + closer.length) % 3 === 0) {\\n if (opener.length % 3 !== 0 || closer.length % 3 !== 0) {\\n isOddMatch = true\\n }\\n }\\n }\\n\\n if (!isOddMatch) {\\n // If previous delimiter cannot be an opener, we can safely skip\\n // the entire sequence in future checks. This is required to make\\n // sure algorithm has linear complexity (see *_*_*_*_*_... case).\\n //\\n const lastJump = openerIdx > 0 && !delimiters[openerIdx - 1].open\\n ? jumps[openerIdx - 1] + 1\\n : 0\\n\\n jumps[closerIdx] = closerIdx - openerIdx + lastJump\\n jumps[openerIdx] = lastJump\\n\\n closer.open = false\\n opener.end = closerIdx\\n opener.close = false\\n newMinOpenerIdx = -1\\n // treat next token as start of run,\\n // it optimizes skips in **<...>**a**<...>** pathological case\\n lastTokenIdx = -2\\n break\\n }\\n }\\n }\\n\\n if (newMinOpenerIdx !== -1) {\\n // If match for this delimiter run failed, we want to set lower bound for\\n // future lookups. This is required to make sure algorithm has linear\\n // complexity.\\n //\\n // See details here:\\n // https://github.com/commonmark/cmark/issues/178#issuecomment-270417442\\n //\\n openersBottom[closer.marker][(closer.open ? 3 : 0) + ((closer.length || 0) % 3)] = newMinOpenerIdx\\n }\\n }\\n}\\n\\nexport default function link_pairs (state) {\\n const tokens_meta = state.tokens_meta\\n const max = state.tokens_meta.length\\n\\n processDelimiters(state.delimiters)\\n\\n for (let curr = 0; curr < max; curr++) {\\n if (tokens_meta[curr] && tokens_meta[curr].delimiters) {\\n processDelimiters(tokens_meta[curr].delimiters)\\n }\\n }\\n}\\n\",\"// Clean up tokens after emphasis and strikethrough postprocessing:\\n// merge adjacent text nodes into one and re-calculate all token levels\\n//\\n// This is necessary because initially emphasis delimiter markers (*, _, ~)\\n// are treated as their own separate text tokens. Then emphasis rule either\\n// leaves them as text (needed to merge with adjacent text) or turns them\\n// into opening/closing tags (which messes up levels inside).\\n//\\n\\nexport default function fragments_join (state) {\\n let curr, last\\n let level = 0\\n const tokens = state.tokens\\n const max = state.tokens.length\\n\\n for (curr = last = 0; curr < max; curr++) {\\n // re-calculate levels after emphasis/strikethrough turns some text nodes\\n // into opening/closing tags\\n if (tokens[curr].nesting < 0) level-- // closing tag\\n tokens[curr].level = level\\n if (tokens[curr].nesting > 0) level++ // opening tag\\n\\n if (tokens[curr].type === 'text' &&\\n curr + 1 < max &&\\n tokens[curr + 1].type === 'text') {\\n // collapse two adjacent text nodes\\n tokens[curr + 1].content = tokens[curr].content + tokens[curr + 1].content\\n } else {\\n if (curr !== last) { tokens[last] = tokens[curr] }\\n\\n last++\\n }\\n }\\n\\n if (curr !== last) {\\n tokens.length = last\\n }\\n}\\n\",\"/** internal\\n * class ParserInline\\n *\\n * Tokenizes paragraph content.\\n **/\\n\\nimport Ruler from './ruler.mjs'\\nimport StateInline from './rules_inline/state_inline.mjs'\\n\\nimport r_text from './rules_inline/text.mjs'\\nimport r_linkify from './rules_inline/linkify.mjs'\\nimport r_newline from './rules_inline/newline.mjs'\\nimport r_escape from './rules_inline/escape.mjs'\\nimport r_backticks from './rules_inline/backticks.mjs'\\nimport r_strikethrough from './rules_inline/strikethrough.mjs'\\nimport r_emphasis from './rules_inline/emphasis.mjs'\\nimport r_link from './rules_inline/link.mjs'\\nimport r_image from './rules_inline/image.mjs'\\nimport r_autolink from './rules_inline/autolink.mjs'\\nimport r_html_inline from './rules_inline/html_inline.mjs'\\nimport r_entity from './rules_inline/entity.mjs'\\n\\nimport r_balance_pairs from './rules_inline/balance_pairs.mjs'\\nimport r_fragments_join from './rules_inline/fragments_join.mjs'\\n\\n// Parser rules\\n\\nconst _rules = [\\n ['text', r_text],\\n ['linkify', r_linkify],\\n ['newline', r_newline],\\n ['escape', r_escape],\\n ['backticks', r_backticks],\\n ['strikethrough', r_strikethrough.tokenize],\\n ['emphasis', r_emphasis.tokenize],\\n ['link', r_link],\\n ['image', r_image],\\n ['autolink', r_autolink],\\n ['html_inline', r_html_inline],\\n ['entity', r_entity]\\n]\\n\\n// `rule2` ruleset was created specifically for emphasis/strikethrough\\n// post-processing and may be changed in the future.\\n//\\n// Don't use this for anything except pairs (plugins working with `balance_pairs`).\\n//\\nconst _rules2 = [\\n ['balance_pairs', r_balance_pairs],\\n ['strikethrough', r_strikethrough.postProcess],\\n ['emphasis', r_emphasis.postProcess],\\n // rules for pairs separate '**' into its own text tokens, which may be left unused,\\n // rule below merges unused segments back with the rest of the text\\n ['fragments_join', r_fragments_join]\\n]\\n\\n/**\\n * new ParserInline()\\n **/\\nfunction ParserInline () {\\n /**\\n * ParserInline#ruler -> Ruler\\n *\\n * [[Ruler]] instance. Keep configuration of inline rules.\\n **/\\n this.ruler = new Ruler()\\n\\n for (let i = 0; i < _rules.length; i++) {\\n this.ruler.push(_rules[i][0], _rules[i][1])\\n }\\n\\n /**\\n * ParserInline#ruler2 -> Ruler\\n *\\n * [[Ruler]] instance. Second ruler used for post-processing\\n * (e.g. in emphasis-like rules).\\n **/\\n this.ruler2 = new Ruler()\\n\\n for (let i = 0; i < _rules2.length; i++) {\\n this.ruler2.push(_rules2[i][0], _rules2[i][1])\\n }\\n}\\n\\n// Skip single token by running all rules in validation mode;\\n// returns `true` if any rule reported success\\n//\\nParserInline.prototype.skipToken = function (state) {\\n const pos = state.pos\\n const rules = this.ruler.getRules('')\\n const len = rules.length\\n const maxNesting = state.md.options.maxNesting\\n const cache = state.cache\\n\\n if (typeof cache[pos] !== 'undefined') {\\n state.pos = cache[pos]\\n return\\n }\\n\\n let ok = false\\n\\n if (state.level < maxNesting) {\\n for (let i = 0; i < len; i++) {\\n // Increment state.level and decrement it later to limit recursion.\\n // It's harmless to do here, because no tokens are created. But ideally,\\n // we'd need a separate private state variable for this purpose.\\n //\\n state.level++\\n ok = rules[i](state, true)\\n state.level--\\n\\n if (ok) {\\n if (pos >= state.pos) { throw new Error(\\\"inline rule didn't increment state.pos\\\") }\\n break\\n }\\n }\\n } else {\\n // Too much nesting, just skip until the end of the paragraph.\\n //\\n // NOTE: this will cause links to behave incorrectly in the following case,\\n // when an amount of `[` is exactly equal to `maxNesting + 1`:\\n //\\n // [[[[[[[[[[[[[[[[[[[[[foo]()\\n //\\n // TODO: remove this workaround when CM standard will allow nested links\\n // (we can replace it by preventing links from being parsed in\\n // validation mode)\\n //\\n state.pos = state.posMax\\n }\\n\\n if (!ok) { state.pos++ }\\n cache[pos] = state.pos\\n}\\n\\n// Generate tokens for input range\\n//\\nParserInline.prototype.tokenize = function (state) {\\n const rules = this.ruler.getRules('')\\n const len = rules.length\\n const end = state.posMax\\n const maxNesting = state.md.options.maxNesting\\n\\n while (state.pos < end) {\\n // Try all possible rules.\\n // On success, rule should:\\n //\\n // - update `state.pos`\\n // - update `state.tokens`\\n // - return true\\n const prevPos = state.pos\\n let ok = false\\n\\n if (state.level < maxNesting) {\\n for (let i = 0; i < len; i++) {\\n ok = rules[i](state, false)\\n if (ok) {\\n if (prevPos >= state.pos) { throw new Error(\\\"inline rule didn't increment state.pos\\\") }\\n break\\n }\\n }\\n }\\n\\n if (ok) {\\n if (state.pos >= end) { break }\\n continue\\n }\\n\\n state.pending += state.src[state.pos++]\\n }\\n\\n if (state.pending) {\\n state.pushPending()\\n }\\n}\\n\\n/**\\n * ParserInline.parse(str, md, env, outTokens)\\n *\\n * Process input string and push inline tokens into `outTokens`\\n **/\\nParserInline.prototype.parse = function (str, md, env, outTokens) {\\n const state = new this.State(str, md, env, outTokens)\\n\\n this.tokenize(state)\\n\\n const rules = this.ruler2.getRules('')\\n const len = rules.length\\n\\n for (let i = 0; i < len; i++) {\\n rules[i](state)\\n }\\n}\\n\\nParserInline.prototype.State = StateInline\\n\\nexport default ParserInline\\n\",\"import { Any, Cc, Z, P } from 'uc.micro'\\n\\nexport default function (opts) {\\n const re = {}\\n opts = opts || {}\\n\\n re.src_Any = Any.source\\n re.src_Cc = Cc.source\\n re.src_Z = Z.source\\n re.src_P = P.source\\n\\n // \\\\p{\\\\Z\\\\P\\\\Cc\\\\CF} (white spaces + control + format + punctuation)\\n re.src_ZPCc = [re.src_Z, re.src_P, re.src_Cc].join('|')\\n\\n // \\\\p{\\\\Z\\\\Cc} (white spaces + control)\\n re.src_ZCc = [re.src_Z, re.src_Cc].join('|')\\n\\n // Experimental. List of chars, completely prohibited in links\\n // because can separate it from other part of text\\n const text_separators = '[><\\\\uff5c]'\\n\\n // All possible word characters (everything without punctuation, spaces & controls)\\n // Defined via punctuation & spaces to save space\\n // Should be something like \\\\p{\\\\L\\\\N\\\\S\\\\M} (\\\\w but without `_`)\\n re.src_pseudo_letter = '(?:(?!' + text_separators + '|' + re.src_ZPCc + ')' + re.src_Any + ')'\\n // The same as abothe but without [0-9]\\n // var src_pseudo_letter_non_d = '(?:(?![0-9]|' + src_ZPCc + ')' + src_Any + ')';\\n\\n re.src_ip4 =\\n\\n '(?:(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\\\\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'\\n\\n // Prohibit any of \\\"@/[]()\\\" in user/pass to avoid wrong domain fetch.\\n re.src_auth = '(?:(?:(?!' + re.src_ZCc + '|[@/\\\\\\\\[\\\\\\\\]()]).)+@)?'\\n\\n re.src_port =\\n\\n '(?::(?:6(?:[0-4]\\\\\\\\d{3}|5(?:[0-4]\\\\\\\\d{2}|5(?:[0-2]\\\\\\\\d|3[0-5])))|[1-5]?\\\\\\\\d{1,4}))?'\\n\\n re.src_host_terminator =\\n\\n '(?=$|' + text_separators + '|' + re.src_ZPCc + ')' +\\n '(?!' + (opts['---'] ? '-(?!--)|' : '-|') + '_|:\\\\\\\\d|\\\\\\\\.-|\\\\\\\\.(?!$|' + re.src_ZPCc + '))'\\n\\n re.src_path =\\n\\n '(?:' +\\n '[/?#]' +\\n '(?:' +\\n '(?!' + re.src_ZCc + '|' + text_separators + '|[()[\\\\\\\\]{}.,\\\"\\\\'?!\\\\\\\\-;]).|' +\\n '\\\\\\\\[(?:(?!' + re.src_ZCc + '|\\\\\\\\]).)*\\\\\\\\]|' +\\n '\\\\\\\\((?:(?!' + re.src_ZCc + '|[)]).)*\\\\\\\\)|' +\\n '\\\\\\\\{(?:(?!' + re.src_ZCc + '|[}]).)*\\\\\\\\}|' +\\n '\\\\\\\\\\\"(?:(?!' + re.src_ZCc + '|[\\\"]).)+\\\\\\\\\\\"|' +\\n \\\"\\\\\\\\'(?:(?!\\\" + re.src_ZCc + \\\"|[']).)+\\\\\\\\'|\\\" +\\n\\n // allow `I'm_king` if no pair found\\n \\\"\\\\\\\\'(?=\\\" + re.src_pseudo_letter + '|[-])|' +\\n\\n // google has many dots in \\\"google search\\\" links (#66, #81).\\n // github has ... in commit range links,\\n // Restrict to\\n // - english\\n // - percent-encoded\\n // - parts of file path\\n // - params separator\\n // until more examples found.\\n '\\\\\\\\.{2,}[a-zA-Z0-9%/&]|' +\\n\\n '\\\\\\\\.(?!' + re.src_ZCc + '|[.]|$)|' +\\n (opts['---']\\n ? '\\\\\\\\-(?!--(?:[^-]|$))(?:-*)|' // `---` => long dash, terminate\\n : '\\\\\\\\-+|'\\n ) +\\n // allow `,,,` in paths\\n ',(?!' + re.src_ZCc + '|$)|' +\\n\\n // allow `;` if not followed by space-like char\\n ';(?!' + re.src_ZCc + '|$)|' +\\n\\n // allow `!!!` in paths, but not at the end\\n '\\\\\\\\!+(?!' + re.src_ZCc + '|[!]|$)|' +\\n\\n '\\\\\\\\?(?!' + re.src_ZCc + '|[?]|$)' +\\n ')+' +\\n '|\\\\\\\\/' +\\n ')?'\\n\\n // Allow anything in markdown spec, forbid quote (\\\") at the first position\\n // because emails enclosed in quotes are far more common\\n re.src_email_name =\\n\\n '[\\\\\\\\-;:&=\\\\\\\\+\\\\\\\\$,\\\\\\\\.a-zA-Z0-9_][\\\\\\\\-;:&=\\\\\\\\+\\\\\\\\$,\\\\\\\\\\\"\\\\\\\\.a-zA-Z0-9_]*'\\n\\n re.src_xn =\\n\\n 'xn--[a-z0-9\\\\\\\\-]{1,59}'\\n\\n // More to read about domain names\\n // http://serverfault.com/questions/638260/\\n\\n re.src_domain_root =\\n\\n // Allow letters & digits (http://test1)\\n '(?:' +\\n re.src_xn +\\n '|' +\\n re.src_pseudo_letter + '{1,63}' +\\n ')'\\n\\n re.src_domain =\\n\\n '(?:' +\\n re.src_xn +\\n '|' +\\n '(?:' + re.src_pseudo_letter + ')' +\\n '|' +\\n '(?:' + re.src_pseudo_letter + '(?:-|' + re.src_pseudo_letter + '){0,61}' + re.src_pseudo_letter + ')' +\\n ')'\\n\\n re.src_host =\\n\\n '(?:' +\\n // Don't need IP check, because digits are already allowed in normal domain names\\n // src_ip4 +\\n // '|' +\\n '(?:(?:(?:' + re.src_domain + ')\\\\\\\\.)*' + re.src_domain/* _root */ + ')' +\\n ')'\\n\\n re.tpl_host_fuzzy =\\n\\n '(?:' +\\n re.src_ip4 +\\n '|' +\\n '(?:(?:(?:' + re.src_domain + ')\\\\\\\\.)+(?:%TLDS%))' +\\n ')'\\n\\n re.tpl_host_no_ip_fuzzy =\\n\\n '(?:(?:(?:' + re.src_domain + ')\\\\\\\\.)+(?:%TLDS%))'\\n\\n re.src_host_strict =\\n\\n re.src_host + re.src_host_terminator\\n\\n re.tpl_host_fuzzy_strict =\\n\\n re.tpl_host_fuzzy + re.src_host_terminator\\n\\n re.src_host_port_strict =\\n\\n re.src_host + re.src_port + re.src_host_terminator\\n\\n re.tpl_host_port_fuzzy_strict =\\n\\n re.tpl_host_fuzzy + re.src_port + re.src_host_terminator\\n\\n re.tpl_host_port_no_ip_fuzzy_strict =\\n\\n re.tpl_host_no_ip_fuzzy + re.src_port + re.src_host_terminator\\n\\n //\\n // Main rules\\n //\\n\\n // Rude test fuzzy links by host, for quick deny\\n re.tpl_host_fuzzy_test =\\n\\n 'localhost|www\\\\\\\\.|\\\\\\\\.\\\\\\\\d{1,3}\\\\\\\\.|(?:\\\\\\\\.(?:%TLDS%)(?:' + re.src_ZPCc + '|>|$))'\\n\\n re.tpl_email_fuzzy =\\n\\n '(^|' + text_separators + '|\\\"|\\\\\\\\(|' + re.src_ZCc + ')' +\\n '(' + re.src_email_name + '@' + re.tpl_host_fuzzy_strict + ')'\\n\\n re.tpl_link_fuzzy =\\n // Fuzzy link can't be prepended with .:/\\\\- and non punctuation.\\n // but can start with > (markdown blockquote)\\n '(^|(?![.:/\\\\\\\\-_@])(?:[$+<=>^`|\\\\uff5c]|' + re.src_ZPCc + '))' +\\n '((?![$+<=>^`|\\\\uff5c])' + re.tpl_host_port_fuzzy_strict + re.src_path + ')'\\n\\n re.tpl_link_no_ip_fuzzy =\\n // Fuzzy link can't be prepended with .:/\\\\- and non punctuation.\\n // but can start with > (markdown blockquote)\\n '(^|(?![.:/\\\\\\\\-_@])(?:[$+<=>^`|\\\\uff5c]|' + re.src_ZPCc + '))' +\\n '((?![$+<=>^`|\\\\uff5c])' + re.tpl_host_port_no_ip_fuzzy_strict + re.src_path + ')'\\n\\n return re\\n}\\n\",\"import reFactory from './lib/re.mjs'\\n\\n//\\n// Helpers\\n//\\n\\n// Merge objects\\n//\\nfunction assign (obj /* from1, from2, from3, ... */) {\\n const sources = Array.prototype.slice.call(arguments, 1)\\n\\n sources.forEach(function (source) {\\n if (!source) { return }\\n\\n Object.keys(source).forEach(function (key) {\\n obj[key] = source[key]\\n })\\n })\\n\\n return obj\\n}\\n\\nfunction _class (obj) { return Object.prototype.toString.call(obj) }\\nfunction isString (obj) { return _class(obj) === '[object String]' }\\nfunction isObject (obj) { return _class(obj) === '[object Object]' }\\nfunction isRegExp (obj) { return _class(obj) === '[object RegExp]' }\\nfunction isFunction (obj) { return _class(obj) === '[object Function]' }\\n\\nfunction escapeRE (str) { return str.replace(/[.?*+^$[\\\\]\\\\\\\\(){}|-]/g, '\\\\\\\\$&') }\\n\\n//\\n\\nconst defaultOptions = {\\n fuzzyLink: true,\\n fuzzyEmail: true,\\n fuzzyIP: false\\n}\\n\\nfunction isOptionsObj (obj) {\\n return Object.keys(obj || {}).reduce(function (acc, k) {\\n /* eslint-disable-next-line no-prototype-builtins */\\n return acc || defaultOptions.hasOwnProperty(k)\\n }, false)\\n}\\n\\nconst defaultSchemas = {\\n 'http:': {\\n validate: function (text, pos, self) {\\n const tail = text.slice(pos)\\n\\n if (!self.re.http) {\\n // compile lazily, because \\\"host\\\"-containing variables can change on tlds update.\\n self.re.http = new RegExp(\\n '^\\\\\\\\/\\\\\\\\/' + self.re.src_auth + self.re.src_host_port_strict + self.re.src_path, 'i'\\n )\\n }\\n if (self.re.http.test(tail)) {\\n return tail.match(self.re.http)[0].length\\n }\\n return 0\\n }\\n },\\n 'https:': 'http:',\\n 'ftp:': 'http:',\\n '//': {\\n validate: function (text, pos, self) {\\n const tail = text.slice(pos)\\n\\n if (!self.re.no_http) {\\n // compile lazily, because \\\"host\\\"-containing variables can change on tlds update.\\n self.re.no_http = new RegExp(\\n '^' +\\n self.re.src_auth +\\n // Don't allow single-level domains, because of false positives like '//test'\\n // with code comments\\n '(?:localhost|(?:(?:' + self.re.src_domain + ')\\\\\\\\.)+' + self.re.src_domain_root + ')' +\\n self.re.src_port +\\n self.re.src_host_terminator +\\n self.re.src_path,\\n\\n 'i'\\n )\\n }\\n\\n if (self.re.no_http.test(tail)) {\\n // should not be `://` & `///`, that protects from errors in protocol name\\n if (pos >= 3 && text[pos - 3] === ':') { return 0 }\\n if (pos >= 3 && text[pos - 3] === '/') { return 0 }\\n return tail.match(self.re.no_http)[0].length\\n }\\n return 0\\n }\\n },\\n 'mailto:': {\\n validate: function (text, pos, self) {\\n const tail = text.slice(pos)\\n\\n if (!self.re.mailto) {\\n self.re.mailto = new RegExp(\\n '^' + self.re.src_email_name + '@' + self.re.src_host_strict, 'i'\\n )\\n }\\n if (self.re.mailto.test(tail)) {\\n return tail.match(self.re.mailto)[0].length\\n }\\n return 0\\n }\\n }\\n}\\n\\n// RE pattern for 2-character tlds (autogenerated by ./support/tlds_2char_gen.js)\\n/* eslint-disable-next-line max-len */\\nconst tlds_2ch_src_re = 'a[cdefgilmnoqrstuwxz]|b[abdefghijmnorstvwyz]|c[acdfghiklmnoruvwxyz]|d[ejkmoz]|e[cegrstu]|f[ijkmor]|g[abdefghilmnpqrstuwy]|h[kmnrtu]|i[delmnoqrst]|j[emop]|k[eghimnprwyz]|l[abcikrstuvy]|m[acdeghklmnopqrstuvwxyz]|n[acefgilopruz]|om|p[aefghklmnrstwy]|qa|r[eosuw]|s[abcdeghijklmnortuvxyz]|t[cdfghjklmnortvwz]|u[agksyz]|v[aceginu]|w[fs]|y[et]|z[amw]'\\n\\n// DON'T try to make PRs with changes. Extend TLDs with LinkifyIt.tlds() instead\\nconst tlds_default = 'biz|com|edu|gov|net|org|pro|web|xxx|aero|asia|coop|info|museum|name|shop|рф'.split('|')\\n\\nfunction resetScanCache (self) {\\n self.__index__ = -1\\n self.__text_cache__ = ''\\n}\\n\\nfunction createValidator (re) {\\n return function (text, pos) {\\n const tail = text.slice(pos)\\n\\n if (re.test(tail)) {\\n return tail.match(re)[0].length\\n }\\n return 0\\n }\\n}\\n\\nfunction createNormalizer () {\\n return function (match, self) {\\n self.normalize(match)\\n }\\n}\\n\\n// Schemas compiler. Build regexps.\\n//\\nfunction compile (self) {\\n // Load & clone RE patterns.\\n const re = self.re = reFactory(self.__opts__)\\n\\n // Define dynamic patterns\\n const tlds = self.__tlds__.slice()\\n\\n self.onCompile()\\n\\n if (!self.__tlds_replaced__) {\\n tlds.push(tlds_2ch_src_re)\\n }\\n tlds.push(re.src_xn)\\n\\n re.src_tlds = tlds.join('|')\\n\\n function untpl (tpl) { return tpl.replace('%TLDS%', re.src_tlds) }\\n\\n re.email_fuzzy = RegExp(untpl(re.tpl_email_fuzzy), 'i')\\n re.link_fuzzy = RegExp(untpl(re.tpl_link_fuzzy), 'i')\\n re.link_no_ip_fuzzy = RegExp(untpl(re.tpl_link_no_ip_fuzzy), 'i')\\n re.host_fuzzy_test = RegExp(untpl(re.tpl_host_fuzzy_test), 'i')\\n\\n //\\n // Compile each schema\\n //\\n\\n const aliases = []\\n\\n self.__compiled__ = {} // Reset compiled data\\n\\n function schemaError (name, val) {\\n throw new Error('(LinkifyIt) Invalid schema \\\"' + name + '\\\": ' + val)\\n }\\n\\n Object.keys(self.__schemas__).forEach(function (name) {\\n const val = self.__schemas__[name]\\n\\n // skip disabled methods\\n if (val === null) { return }\\n\\n const compiled = { validate: null, link: null }\\n\\n self.__compiled__[name] = compiled\\n\\n if (isObject(val)) {\\n if (isRegExp(val.validate)) {\\n compiled.validate = createValidator(val.validate)\\n } else if (isFunction(val.validate)) {\\n compiled.validate = val.validate\\n } else {\\n schemaError(name, val)\\n }\\n\\n if (isFunction(val.normalize)) {\\n compiled.normalize = val.normalize\\n } else if (!val.normalize) {\\n compiled.normalize = createNormalizer()\\n } else {\\n schemaError(name, val)\\n }\\n\\n return\\n }\\n\\n if (isString(val)) {\\n aliases.push(name)\\n return\\n }\\n\\n schemaError(name, val)\\n })\\n\\n //\\n // Compile postponed aliases\\n //\\n\\n aliases.forEach(function (alias) {\\n if (!self.__compiled__[self.__schemas__[alias]]) {\\n // Silently fail on missed schemas to avoid errons on disable.\\n // schemaError(alias, self.__schemas__[alias]);\\n return\\n }\\n\\n self.__compiled__[alias].validate =\\n self.__compiled__[self.__schemas__[alias]].validate\\n self.__compiled__[alias].normalize =\\n self.__compiled__[self.__schemas__[alias]].normalize\\n })\\n\\n //\\n // Fake record for guessed links\\n //\\n self.__compiled__[''] = { validate: null, normalize: createNormalizer() }\\n\\n //\\n // Build schema condition\\n //\\n const slist = Object.keys(self.__compiled__)\\n .filter(function (name) {\\n // Filter disabled & fake schemas\\n return name.length > 0 && self.__compiled__[name]\\n })\\n .map(escapeRE)\\n .join('|')\\n // (?!_) cause 1.5x slowdown\\n self.re.schema_test = RegExp('(^|(?!_)(?:[><\\\\uff5c]|' + re.src_ZPCc + '))(' + slist + ')', 'i')\\n self.re.schema_search = RegExp('(^|(?!_)(?:[><\\\\uff5c]|' + re.src_ZPCc + '))(' + slist + ')', 'ig')\\n self.re.schema_at_start = RegExp('^' + self.re.schema_search.source, 'i')\\n\\n self.re.pretest = RegExp(\\n '(' + self.re.schema_test.source + ')|(' + self.re.host_fuzzy_test.source + ')|@',\\n 'i'\\n )\\n\\n //\\n // Cleanup\\n //\\n\\n resetScanCache(self)\\n}\\n\\n/**\\n * class Match\\n *\\n * Match result. Single element of array, returned by [[LinkifyIt#match]]\\n **/\\nfunction Match (self, shift) {\\n const start = self.__index__\\n const end = self.__last_index__\\n const text = self.__text_cache__.slice(start, end)\\n\\n /**\\n * Match#schema -> String\\n *\\n * Prefix (protocol) for matched string.\\n **/\\n this.schema = self.__schema__.toLowerCase()\\n /**\\n * Match#index -> Number\\n *\\n * First position of matched string.\\n **/\\n this.index = start + shift\\n /**\\n * Match#lastIndex -> Number\\n *\\n * Next position after matched string.\\n **/\\n this.lastIndex = end + shift\\n /**\\n * Match#raw -> String\\n *\\n * Matched string.\\n **/\\n this.raw = text\\n /**\\n * Match#text -> String\\n *\\n * Notmalized text of matched string.\\n **/\\n this.text = text\\n /**\\n * Match#url -> String\\n *\\n * Normalized url of matched string.\\n **/\\n this.url = text\\n}\\n\\nfunction createMatch (self, shift) {\\n const match = new Match(self, shift)\\n\\n self.__compiled__[match.schema].normalize(match, self)\\n\\n return match\\n}\\n\\n/**\\n * class LinkifyIt\\n **/\\n\\n/**\\n * new LinkifyIt(schemas, options)\\n * - schemas (Object): Optional. Additional schemas to validate (prefix/validator)\\n * - options (Object): { fuzzyLink|fuzzyEmail|fuzzyIP: true|false }\\n *\\n * Creates new linkifier instance with optional additional schemas.\\n * Can be called without `new` keyword for convenience.\\n *\\n * By default understands:\\n *\\n * - `http(s)://...` , `ftp://...`, `mailto:...` & `//...` links\\n * - \\\"fuzzy\\\" links and emails (example.com, foo@bar.com).\\n *\\n * `schemas` is an object, where each key/value describes protocol/rule:\\n *\\n * - __key__ - link prefix (usually, protocol name with `:` at the end, `skype:`\\n * for example). `linkify-it` makes shure that prefix is not preceeded with\\n * alphanumeric char and symbols. Only whitespaces and punctuation allowed.\\n * - __value__ - rule to check tail after link prefix\\n * - _String_ - just alias to existing rule\\n * - _Object_\\n * - _validate_ - validator function (should return matched length on success),\\n * or `RegExp`.\\n * - _normalize_ - optional function to normalize text & url of matched result\\n * (for example, for @twitter mentions).\\n *\\n * `options`:\\n *\\n * - __fuzzyLink__ - recognige URL-s without `http(s):` prefix. Default `true`.\\n * - __fuzzyIP__ - allow IPs in fuzzy links above. Can conflict with some texts\\n * like version numbers. Default `false`.\\n * - __fuzzyEmail__ - recognize emails without `mailto:` prefix.\\n *\\n **/\\nfunction LinkifyIt (schemas, options) {\\n if (!(this instanceof LinkifyIt)) {\\n return new LinkifyIt(schemas, options)\\n }\\n\\n if (!options) {\\n if (isOptionsObj(schemas)) {\\n options = schemas\\n schemas = {}\\n }\\n }\\n\\n this.__opts__ = assign({}, defaultOptions, options)\\n\\n // Cache last tested result. Used to skip repeating steps on next `match` call.\\n this.__index__ = -1\\n this.__last_index__ = -1 // Next scan position\\n this.__schema__ = ''\\n this.__text_cache__ = ''\\n\\n this.__schemas__ = assign({}, defaultSchemas, schemas)\\n this.__compiled__ = {}\\n\\n this.__tlds__ = tlds_default\\n this.__tlds_replaced__ = false\\n\\n this.re = {}\\n\\n compile(this)\\n}\\n\\n/** chainable\\n * LinkifyIt#add(schema, definition)\\n * - schema (String): rule name (fixed pattern prefix)\\n * - definition (String|RegExp|Object): schema definition\\n *\\n * Add new rule definition. See constructor description for details.\\n **/\\nLinkifyIt.prototype.add = function add (schema, definition) {\\n this.__schemas__[schema] = definition\\n compile(this)\\n return this\\n}\\n\\n/** chainable\\n * LinkifyIt#set(options)\\n * - options (Object): { fuzzyLink|fuzzyEmail|fuzzyIP: true|false }\\n *\\n * Set recognition options for links without schema.\\n **/\\nLinkifyIt.prototype.set = function set (options) {\\n this.__opts__ = assign(this.__opts__, options)\\n return this\\n}\\n\\n/**\\n * LinkifyIt#test(text) -> Boolean\\n *\\n * Searches linkifiable pattern and returns `true` on success or `false` on fail.\\n **/\\nLinkifyIt.prototype.test = function test (text) {\\n // Reset scan cache\\n this.__text_cache__ = text\\n this.__index__ = -1\\n\\n if (!text.length) { return false }\\n\\n let m, ml, me, len, shift, next, re, tld_pos, at_pos\\n\\n // try to scan for link with schema - that's the most simple rule\\n if (this.re.schema_test.test(text)) {\\n re = this.re.schema_search\\n re.lastIndex = 0\\n while ((m = re.exec(text)) !== null) {\\n len = this.testSchemaAt(text, m[2], re.lastIndex)\\n if (len) {\\n this.__schema__ = m[2]\\n this.__index__ = m.index + m[1].length\\n this.__last_index__ = m.index + m[0].length + len\\n break\\n }\\n }\\n }\\n\\n if (this.__opts__.fuzzyLink && this.__compiled__['http:']) {\\n // guess schemaless links\\n tld_pos = text.search(this.re.host_fuzzy_test)\\n if (tld_pos >= 0) {\\n // if tld is located after found link - no need to check fuzzy pattern\\n if (this.__index__ < 0 || tld_pos < this.__index__) {\\n if ((ml = text.match(this.__opts__.fuzzyIP ? this.re.link_fuzzy : this.re.link_no_ip_fuzzy)) !== null) {\\n shift = ml.index + ml[1].length\\n\\n if (this.__index__ < 0 || shift < this.__index__) {\\n this.__schema__ = ''\\n this.__index__ = shift\\n this.__last_index__ = ml.index + ml[0].length\\n }\\n }\\n }\\n }\\n }\\n\\n if (this.__opts__.fuzzyEmail && this.__compiled__['mailto:']) {\\n // guess schemaless emails\\n at_pos = text.indexOf('@')\\n if (at_pos >= 0) {\\n // We can't skip this check, because this cases are possible:\\n // 192.168.1.1@gmail.com, my.in@example.com\\n if ((me = text.match(this.re.email_fuzzy)) !== null) {\\n shift = me.index + me[1].length\\n next = me.index + me[0].length\\n\\n if (this.__index__ < 0 || shift < this.__index__ ||\\n (shift === this.__index__ && next > this.__last_index__)) {\\n this.__schema__ = 'mailto:'\\n this.__index__ = shift\\n this.__last_index__ = next\\n }\\n }\\n }\\n }\\n\\n return this.__index__ >= 0\\n}\\n\\n/**\\n * LinkifyIt#pretest(text) -> Boolean\\n *\\n * Very quick check, that can give false positives. Returns true if link MAY BE\\n * can exists. Can be used for speed optimization, when you need to check that\\n * link NOT exists.\\n **/\\nLinkifyIt.prototype.pretest = function pretest (text) {\\n return this.re.pretest.test(text)\\n}\\n\\n/**\\n * LinkifyIt#testSchemaAt(text, name, position) -> Number\\n * - text (String): text to scan\\n * - name (String): rule (schema) name\\n * - position (Number): text offset to check from\\n *\\n * Similar to [[LinkifyIt#test]] but checks only specific protocol tail exactly\\n * at given position. Returns length of found pattern (0 on fail).\\n **/\\nLinkifyIt.prototype.testSchemaAt = function testSchemaAt (text, schema, pos) {\\n // If not supported schema check requested - terminate\\n if (!this.__compiled__[schema.toLowerCase()]) {\\n return 0\\n }\\n return this.__compiled__[schema.toLowerCase()].validate(text, pos, this)\\n}\\n\\n/**\\n * LinkifyIt#match(text) -> Array|null\\n *\\n * Returns array of found link descriptions or `null` on fail. We strongly\\n * recommend to use [[LinkifyIt#test]] first, for best speed.\\n *\\n * ##### Result match description\\n *\\n * - __schema__ - link schema, can be empty for fuzzy links, or `//` for\\n * protocol-neutral links.\\n * - __index__ - offset of matched text\\n * - __lastIndex__ - index of next char after mathch end\\n * - __raw__ - matched text\\n * - __text__ - normalized text\\n * - __url__ - link, generated from matched text\\n **/\\nLinkifyIt.prototype.match = function match (text) {\\n const result = []\\n let shift = 0\\n\\n // Try to take previous element from cache, if .test() called before\\n if (this.__index__ >= 0 && this.__text_cache__ === text) {\\n result.push(createMatch(this, shift))\\n shift = this.__last_index__\\n }\\n\\n // Cut head if cache was used\\n let tail = shift ? text.slice(shift) : text\\n\\n // Scan string until end reached\\n while (this.test(tail)) {\\n result.push(createMatch(this, shift))\\n\\n tail = tail.slice(this.__last_index__)\\n shift += this.__last_index__\\n }\\n\\n if (result.length) {\\n return result\\n }\\n\\n return null\\n}\\n\\n/**\\n * LinkifyIt#matchAtStart(text) -> Match|null\\n *\\n * Returns fully-formed (not fuzzy) link if it starts at the beginning\\n * of the string, and null otherwise.\\n **/\\nLinkifyIt.prototype.matchAtStart = function matchAtStart (text) {\\n // Reset scan cache\\n this.__text_cache__ = text\\n this.__index__ = -1\\n\\n if (!text.length) return null\\n\\n const m = this.re.schema_at_start.exec(text)\\n if (!m) return null\\n\\n const len = this.testSchemaAt(text, m[2], m[0].length)\\n if (!len) return null\\n\\n this.__schema__ = m[2]\\n this.__index__ = m.index + m[1].length\\n this.__last_index__ = m.index + m[0].length + len\\n\\n return createMatch(this, 0)\\n}\\n\\n/** chainable\\n * LinkifyIt#tlds(list [, keepOld]) -> this\\n * - list (Array): list of tlds\\n * - keepOld (Boolean): merge with current list if `true` (`false` by default)\\n *\\n * Load (or merge) new tlds list. Those are user for fuzzy links (without prefix)\\n * to avoid false positives. By default this algorythm used:\\n *\\n * - hostname with any 2-letter root zones are ok.\\n * - biz|com|edu|gov|net|org|pro|web|xxx|aero|asia|coop|info|museum|name|shop|рф\\n * are ok.\\n * - encoded (`xn--...`) root zones are ok.\\n *\\n * If list is replaced, then exact match for 2-chars root zones will be checked.\\n **/\\nLinkifyIt.prototype.tlds = function tlds (list, keepOld) {\\n list = Array.isArray(list) ? list : [list]\\n\\n if (!keepOld) {\\n this.__tlds__ = list.slice()\\n this.__tlds_replaced__ = true\\n compile(this)\\n return this\\n }\\n\\n this.__tlds__ = this.__tlds__.concat(list)\\n .sort()\\n .filter(function (el, idx, arr) {\\n return el !== arr[idx - 1]\\n })\\n .reverse()\\n\\n compile(this)\\n return this\\n}\\n\\n/**\\n * LinkifyIt#normalize(match)\\n *\\n * Default normalizer (if schema does not define it's own).\\n **/\\nLinkifyIt.prototype.normalize = function normalize (match) {\\n // Do minimal possible changes by default. Need to collect feedback prior\\n // to move forward https://github.com/markdown-it/linkify-it/issues/1\\n\\n if (!match.schema) { match.url = 'http://' + match.url }\\n\\n if (match.schema === 'mailto:' && !/^mailto:/i.test(match.url)) {\\n match.url = 'mailto:' + match.url\\n }\\n}\\n\\n/**\\n * LinkifyIt#onCompile()\\n *\\n * Override to modify basic RegExp-s.\\n **/\\nLinkifyIt.prototype.onCompile = function onCompile () {\\n}\\n\\nexport default LinkifyIt\\n\",\"'use strict';\\n\\n/** Highest positive signed 32-bit float value */\\nconst maxInt = 2147483647; // aka. 0x7FFFFFFF or 2^31-1\\n\\n/** Bootstring parameters */\\nconst base = 36;\\nconst tMin = 1;\\nconst tMax = 26;\\nconst skew = 38;\\nconst damp = 700;\\nconst initialBias = 72;\\nconst initialN = 128; // 0x80\\nconst delimiter = '-'; // '\\\\x2D'\\n\\n/** Regular expressions */\\nconst regexPunycode = /^xn--/;\\nconst regexNonASCII = /[^\\\\0-\\\\x7F]/; // Note: U+007F DEL is excluded too.\\nconst regexSeparators = /[\\\\x2E\\\\u3002\\\\uFF0E\\\\uFF61]/g; // RFC 3490 separators\\n\\n/** Error messages */\\nconst errors = {\\n\\t'overflow': 'Overflow: input needs wider integers to process',\\n\\t'not-basic': 'Illegal input >= 0x80 (not a basic code point)',\\n\\t'invalid-input': 'Invalid input'\\n};\\n\\n/** Convenience shortcuts */\\nconst baseMinusTMin = base - tMin;\\nconst floor = Math.floor;\\nconst stringFromCharCode = String.fromCharCode;\\n\\n/*--------------------------------------------------------------------------*/\\n\\n/**\\n * A generic error utility function.\\n * @private\\n * @param {String} type The error type.\\n * @returns {Error} Throws a `RangeError` with the applicable error message.\\n */\\nfunction error(type) {\\n\\tthrow new RangeError(errors[type]);\\n}\\n\\n/**\\n * A generic `Array#map` utility function.\\n * @private\\n * @param {Array} array The array to iterate over.\\n * @param {Function} callback The function that gets called for every array\\n * item.\\n * @returns {Array} A new array of values returned by the callback function.\\n */\\nfunction map(array, callback) {\\n\\tconst result = [];\\n\\tlet length = array.length;\\n\\twhile (length--) {\\n\\t\\tresult[length] = callback(array[length]);\\n\\t}\\n\\treturn result;\\n}\\n\\n/**\\n * A simple `Array#map`-like wrapper to work with domain name strings or email\\n * addresses.\\n * @private\\n * @param {String} domain The domain name or email address.\\n * @param {Function} callback The function that gets called for every\\n * character.\\n * @returns {String} A new string of characters returned by the callback\\n * function.\\n */\\nfunction mapDomain(domain, callback) {\\n\\tconst parts = domain.split('@');\\n\\tlet result = '';\\n\\tif (parts.length > 1) {\\n\\t\\t// In email addresses, only the domain name should be punycoded. Leave\\n\\t\\t// the local part (i.e. everything up to `@`) intact.\\n\\t\\tresult = parts[0] + '@';\\n\\t\\tdomain = parts[1];\\n\\t}\\n\\t// Avoid `split(regex)` for IE8 compatibility. See #17.\\n\\tdomain = domain.replace(regexSeparators, '\\\\x2E');\\n\\tconst labels = domain.split('.');\\n\\tconst encoded = map(labels, callback).join('.');\\n\\treturn result + encoded;\\n}\\n\\n/**\\n * Creates an array containing the numeric code points of each Unicode\\n * character in the string. While JavaScript uses UCS-2 internally,\\n * this function will convert a pair of surrogate halves (each of which\\n * UCS-2 exposes as separate characters) into a single code point,\\n * matching UTF-16.\\n * @see `punycode.ucs2.encode`\\n * @see \\n * @memberOf punycode.ucs2\\n * @name decode\\n * @param {String} string The Unicode input string (UCS-2).\\n * @returns {Array} The new array of code points.\\n */\\nfunction ucs2decode(string) {\\n\\tconst output = [];\\n\\tlet counter = 0;\\n\\tconst length = string.length;\\n\\twhile (counter < length) {\\n\\t\\tconst value = string.charCodeAt(counter++);\\n\\t\\tif (value >= 0xD800 && value <= 0xDBFF && counter < length) {\\n\\t\\t\\t// It's a high surrogate, and there is a next character.\\n\\t\\t\\tconst extra = string.charCodeAt(counter++);\\n\\t\\t\\tif ((extra & 0xFC00) == 0xDC00) { // Low surrogate.\\n\\t\\t\\t\\toutput.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);\\n\\t\\t\\t} else {\\n\\t\\t\\t\\t// It's an unmatched surrogate; only append this code unit, in case the\\n\\t\\t\\t\\t// next code unit is the high surrogate of a surrogate pair.\\n\\t\\t\\t\\toutput.push(value);\\n\\t\\t\\t\\tcounter--;\\n\\t\\t\\t}\\n\\t\\t} else {\\n\\t\\t\\toutput.push(value);\\n\\t\\t}\\n\\t}\\n\\treturn output;\\n}\\n\\n/**\\n * Creates a string based on an array of numeric code points.\\n * @see `punycode.ucs2.decode`\\n * @memberOf punycode.ucs2\\n * @name encode\\n * @param {Array} codePoints The array of numeric code points.\\n * @returns {String} The new Unicode string (UCS-2).\\n */\\nconst ucs2encode = codePoints => String.fromCodePoint(...codePoints);\\n\\n/**\\n * Converts a basic code point into a digit/integer.\\n * @see `digitToBasic()`\\n * @private\\n * @param {Number} codePoint The basic numeric code point value.\\n * @returns {Number} The numeric value of a basic code point (for use in\\n * representing integers) in the range `0` to `base - 1`, or `base` if\\n * the code point does not represent a value.\\n */\\nconst basicToDigit = function(codePoint) {\\n\\tif (codePoint >= 0x30 && codePoint < 0x3A) {\\n\\t\\treturn 26 + (codePoint - 0x30);\\n\\t}\\n\\tif (codePoint >= 0x41 && codePoint < 0x5B) {\\n\\t\\treturn codePoint - 0x41;\\n\\t}\\n\\tif (codePoint >= 0x61 && codePoint < 0x7B) {\\n\\t\\treturn codePoint - 0x61;\\n\\t}\\n\\treturn base;\\n};\\n\\n/**\\n * Converts a digit/integer into a basic code point.\\n * @see `basicToDigit()`\\n * @private\\n * @param {Number} digit The numeric value of a basic code point.\\n * @returns {Number} The basic code point whose value (when used for\\n * representing integers) is `digit`, which needs to be in the range\\n * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is\\n * used; else, the lowercase form is used. The behavior is undefined\\n * if `flag` is non-zero and `digit` has no uppercase form.\\n */\\nconst digitToBasic = function(digit, flag) {\\n\\t// 0..25 map to ASCII a..z or A..Z\\n\\t// 26..35 map to ASCII 0..9\\n\\treturn digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);\\n};\\n\\n/**\\n * Bias adaptation function as per section 3.4 of RFC 3492.\\n * https://tools.ietf.org/html/rfc3492#section-3.4\\n * @private\\n */\\nconst adapt = function(delta, numPoints, firstTime) {\\n\\tlet k = 0;\\n\\tdelta = firstTime ? floor(delta / damp) : delta >> 1;\\n\\tdelta += floor(delta / numPoints);\\n\\tfor (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {\\n\\t\\tdelta = floor(delta / baseMinusTMin);\\n\\t}\\n\\treturn floor(k + (baseMinusTMin + 1) * delta / (delta + skew));\\n};\\n\\n/**\\n * Converts a Punycode string of ASCII-only symbols to a string of Unicode\\n * symbols.\\n * @memberOf punycode\\n * @param {String} input The Punycode string of ASCII-only symbols.\\n * @returns {String} The resulting string of Unicode symbols.\\n */\\nconst decode = function(input) {\\n\\t// Don't use UCS-2.\\n\\tconst output = [];\\n\\tconst inputLength = input.length;\\n\\tlet i = 0;\\n\\tlet n = initialN;\\n\\tlet bias = initialBias;\\n\\n\\t// Handle the basic code points: let `basic` be the number of input code\\n\\t// points before the last delimiter, or `0` if there is none, then copy\\n\\t// the first basic code points to the output.\\n\\n\\tlet basic = input.lastIndexOf(delimiter);\\n\\tif (basic < 0) {\\n\\t\\tbasic = 0;\\n\\t}\\n\\n\\tfor (let j = 0; j < basic; ++j) {\\n\\t\\t// if it's not a basic code point\\n\\t\\tif (input.charCodeAt(j) >= 0x80) {\\n\\t\\t\\terror('not-basic');\\n\\t\\t}\\n\\t\\toutput.push(input.charCodeAt(j));\\n\\t}\\n\\n\\t// Main decoding loop: start just after the last delimiter if any basic code\\n\\t// points were copied; start at the beginning otherwise.\\n\\n\\tfor (let index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {\\n\\n\\t\\t// `index` is the index of the next character to be consumed.\\n\\t\\t// Decode a generalized variable-length integer into `delta`,\\n\\t\\t// which gets added to `i`. The overflow checking is easier\\n\\t\\t// if we increase `i` as we go, then subtract off its starting\\n\\t\\t// value at the end to obtain `delta`.\\n\\t\\tconst oldi = i;\\n\\t\\tfor (let w = 1, k = base; /* no condition */; k += base) {\\n\\n\\t\\t\\tif (index >= inputLength) {\\n\\t\\t\\t\\terror('invalid-input');\\n\\t\\t\\t}\\n\\n\\t\\t\\tconst digit = basicToDigit(input.charCodeAt(index++));\\n\\n\\t\\t\\tif (digit >= base) {\\n\\t\\t\\t\\terror('invalid-input');\\n\\t\\t\\t}\\n\\t\\t\\tif (digit > floor((maxInt - i) / w)) {\\n\\t\\t\\t\\terror('overflow');\\n\\t\\t\\t}\\n\\n\\t\\t\\ti += digit * w;\\n\\t\\t\\tconst t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);\\n\\n\\t\\t\\tif (digit < t) {\\n\\t\\t\\t\\tbreak;\\n\\t\\t\\t}\\n\\n\\t\\t\\tconst baseMinusT = base - t;\\n\\t\\t\\tif (w > floor(maxInt / baseMinusT)) {\\n\\t\\t\\t\\terror('overflow');\\n\\t\\t\\t}\\n\\n\\t\\t\\tw *= baseMinusT;\\n\\n\\t\\t}\\n\\n\\t\\tconst out = output.length + 1;\\n\\t\\tbias = adapt(i - oldi, out, oldi == 0);\\n\\n\\t\\t// `i` was supposed to wrap around from `out` to `0`,\\n\\t\\t// incrementing `n` each time, so we'll fix that now:\\n\\t\\tif (floor(i / out) > maxInt - n) {\\n\\t\\t\\terror('overflow');\\n\\t\\t}\\n\\n\\t\\tn += floor(i / out);\\n\\t\\ti %= out;\\n\\n\\t\\t// Insert `n` at position `i` of the output.\\n\\t\\toutput.splice(i++, 0, n);\\n\\n\\t}\\n\\n\\treturn String.fromCodePoint(...output);\\n};\\n\\n/**\\n * Converts a string of Unicode symbols (e.g. a domain name label) to a\\n * Punycode string of ASCII-only symbols.\\n * @memberOf punycode\\n * @param {String} input The string of Unicode symbols.\\n * @returns {String} The resulting Punycode string of ASCII-only symbols.\\n */\\nconst encode = function(input) {\\n\\tconst output = [];\\n\\n\\t// Convert the input in UCS-2 to an array of Unicode code points.\\n\\tinput = ucs2decode(input);\\n\\n\\t// Cache the length.\\n\\tconst inputLength = input.length;\\n\\n\\t// Initialize the state.\\n\\tlet n = initialN;\\n\\tlet delta = 0;\\n\\tlet bias = initialBias;\\n\\n\\t// Handle the basic code points.\\n\\tfor (const currentValue of input) {\\n\\t\\tif (currentValue < 0x80) {\\n\\t\\t\\toutput.push(stringFromCharCode(currentValue));\\n\\t\\t}\\n\\t}\\n\\n\\tconst basicLength = output.length;\\n\\tlet handledCPCount = basicLength;\\n\\n\\t// `handledCPCount` is the number of code points that have been handled;\\n\\t// `basicLength` is the number of basic code points.\\n\\n\\t// Finish the basic string with a delimiter unless it's empty.\\n\\tif (basicLength) {\\n\\t\\toutput.push(delimiter);\\n\\t}\\n\\n\\t// Main encoding loop:\\n\\twhile (handledCPCount < inputLength) {\\n\\n\\t\\t// All non-basic code points < n have been handled already. Find the next\\n\\t\\t// larger one:\\n\\t\\tlet m = maxInt;\\n\\t\\tfor (const currentValue of input) {\\n\\t\\t\\tif (currentValue >= n && currentValue < m) {\\n\\t\\t\\t\\tm = currentValue;\\n\\t\\t\\t}\\n\\t\\t}\\n\\n\\t\\t// Increase `delta` enough to advance the decoder's state to ,\\n\\t\\t// but guard against overflow.\\n\\t\\tconst handledCPCountPlusOne = handledCPCount + 1;\\n\\t\\tif (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {\\n\\t\\t\\terror('overflow');\\n\\t\\t}\\n\\n\\t\\tdelta += (m - n) * handledCPCountPlusOne;\\n\\t\\tn = m;\\n\\n\\t\\tfor (const currentValue of input) {\\n\\t\\t\\tif (currentValue < n && ++delta > maxInt) {\\n\\t\\t\\t\\terror('overflow');\\n\\t\\t\\t}\\n\\t\\t\\tif (currentValue === n) {\\n\\t\\t\\t\\t// Represent delta as a generalized variable-length integer.\\n\\t\\t\\t\\tlet q = delta;\\n\\t\\t\\t\\tfor (let k = base; /* no condition */; k += base) {\\n\\t\\t\\t\\t\\tconst t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);\\n\\t\\t\\t\\t\\tif (q < t) {\\n\\t\\t\\t\\t\\t\\tbreak;\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t\\tconst qMinusT = q - t;\\n\\t\\t\\t\\t\\tconst baseMinusT = base - t;\\n\\t\\t\\t\\t\\toutput.push(\\n\\t\\t\\t\\t\\t\\tstringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))\\n\\t\\t\\t\\t\\t);\\n\\t\\t\\t\\t\\tq = floor(qMinusT / baseMinusT);\\n\\t\\t\\t\\t}\\n\\n\\t\\t\\t\\toutput.push(stringFromCharCode(digitToBasic(q, 0)));\\n\\t\\t\\t\\tbias = adapt(delta, handledCPCountPlusOne, handledCPCount === basicLength);\\n\\t\\t\\t\\tdelta = 0;\\n\\t\\t\\t\\t++handledCPCount;\\n\\t\\t\\t}\\n\\t\\t}\\n\\n\\t\\t++delta;\\n\\t\\t++n;\\n\\n\\t}\\n\\treturn output.join('');\\n};\\n\\n/**\\n * Converts a Punycode string representing a domain name or an email address\\n * to Unicode. Only the Punycoded parts of the input will be converted, i.e.\\n * it doesn't matter if you call it on a string that has already been\\n * converted to Unicode.\\n * @memberOf punycode\\n * @param {String} input The Punycoded domain name or email address to\\n * convert to Unicode.\\n * @returns {String} The Unicode representation of the given Punycode\\n * string.\\n */\\nconst toUnicode = function(input) {\\n\\treturn mapDomain(input, function(string) {\\n\\t\\treturn regexPunycode.test(string)\\n\\t\\t\\t? decode(string.slice(4).toLowerCase())\\n\\t\\t\\t: string;\\n\\t});\\n};\\n\\n/**\\n * Converts a Unicode string representing a domain name or an email address to\\n * Punycode. Only the non-ASCII parts of the domain name will be converted,\\n * i.e. it doesn't matter if you call it with a domain that's already in\\n * ASCII.\\n * @memberOf punycode\\n * @param {String} input The domain name or email address to convert, as a\\n * Unicode string.\\n * @returns {String} The Punycode representation of the given domain name or\\n * email address.\\n */\\nconst toASCII = function(input) {\\n\\treturn mapDomain(input, function(string) {\\n\\t\\treturn regexNonASCII.test(string)\\n\\t\\t\\t? 'xn--' + encode(string)\\n\\t\\t\\t: string;\\n\\t});\\n};\\n\\n/*--------------------------------------------------------------------------*/\\n\\n/** Define the public API */\\nconst punycode = {\\n\\t/**\\n\\t * A string representing the current Punycode.js version number.\\n\\t * @memberOf punycode\\n\\t * @type String\\n\\t */\\n\\t'version': '2.3.1',\\n\\t/**\\n\\t * An object of methods to convert from JavaScript's internal character\\n\\t * representation (UCS-2) to Unicode code points, and back.\\n\\t * @see \\n\\t * @memberOf punycode\\n\\t * @type Object\\n\\t */\\n\\t'ucs2': {\\n\\t\\t'decode': ucs2decode,\\n\\t\\t'encode': ucs2encode\\n\\t},\\n\\t'decode': decode,\\n\\t'encode': encode,\\n\\t'toASCII': toASCII,\\n\\t'toUnicode': toUnicode\\n};\\n\\nexport { ucs2decode, ucs2encode, decode, encode, toASCII, toUnicode };\\nexport default punycode;\\n\",\"// markdown-it default options\\n\\nexport default {\\n options: {\\n // Enable HTML tags in source\\n html: false,\\n\\n // Use '/' to close single tags (
)\\n xhtmlOut: false,\\n\\n // Convert '\\\\n' in paragraphs into
\\n breaks: false,\\n\\n // CSS language prefix for fenced blocks\\n langPrefix: 'language-',\\n\\n // autoconvert URL-like texts to links\\n linkify: false,\\n\\n // Enable some language-neutral replacements + quotes beautification\\n typographer: false,\\n\\n // Double + single quotes replacement pairs, when typographer enabled,\\n // and smartquotes on. Could be either a String or an Array.\\n //\\n // For example, you can use '«»„“' for Russian, '„“‚‘' for German,\\n // and ['«\\\\xA0', '\\\\xA0»', '‹\\\\xA0', '\\\\xA0›'] for French (including nbsp).\\n quotes: '\\\\u201c\\\\u201d\\\\u2018\\\\u2019', /* “”‘’ */\\n\\n // Highlighter function. Should return escaped HTML,\\n // or '' if the source string is not changed and should be escaped externaly.\\n // If result starts with )\\n xhtmlOut: false,\\n\\n // Convert '\\\\n' in paragraphs into
\\n breaks: false,\\n\\n // CSS language prefix for fenced blocks\\n langPrefix: 'language-',\\n\\n // autoconvert URL-like texts to links\\n linkify: false,\\n\\n // Enable some language-neutral replacements + quotes beautification\\n typographer: false,\\n\\n // Double + single quotes replacement pairs, when typographer enabled,\\n // and smartquotes on. Could be either a String or an Array.\\n //\\n // For example, you can use '«»„“' for Russian, '„“‚‘' for German,\\n // and ['«\\\\xA0', '\\\\xA0»', '‹\\\\xA0', '\\\\xA0›'] for French (including nbsp).\\n quotes: '\\\\u201c\\\\u201d\\\\u2018\\\\u2019', /* “”‘’ */\\n\\n // Highlighter function. Should return escaped HTML,\\n // or '' if the source string is not changed and should be escaped externaly.\\n // If result starts with )\\n xhtmlOut: true,\\n\\n // Convert '\\\\n' in paragraphs into
\\n breaks: false,\\n\\n // CSS language prefix for fenced blocks\\n langPrefix: 'language-',\\n\\n // autoconvert URL-like texts to links\\n linkify: false,\\n\\n // Enable some language-neutral replacements + quotes beautification\\n typographer: false,\\n\\n // Double + single quotes replacement pairs, when typographer enabled,\\n // and smartquotes on. Could be either a String or an Array.\\n //\\n // For example, you can use '«»„“' for Russian, '„“‚‘' for German,\\n // and ['«\\\\xA0', '\\\\xA0»', '‹\\\\xA0', '\\\\xA0›'] for French (including nbsp).\\n quotes: '\\\\u201c\\\\u201d\\\\u2018\\\\u2019', /* “”‘’ */\\n\\n // Highlighter function. Should return escaped HTML,\\n // or '' if the source string is not changed and should be escaped externaly.\\n // If result starts with = 0) {\\n try {\\n parsed.hostname = punycode.toASCII(parsed.hostname)\\n } catch (er) { /**/ }\\n }\\n }\\n\\n return mdurl.encode(mdurl.format(parsed))\\n}\\n\\nfunction normalizeLinkText (url) {\\n const parsed = mdurl.parse(url, true)\\n\\n if (parsed.hostname) {\\n // Encode hostnames in urls like:\\n // `http://host/`, `https://host/`, `mailto:user@host`, `//host/`\\n //\\n // We don't encode unknown schemas, because it's likely that we encode\\n // something we shouldn't (e.g. `skype:name` treated as `skype:host`)\\n //\\n if (!parsed.protocol || RECODE_HOSTNAME_FOR.indexOf(parsed.protocol) >= 0) {\\n try {\\n parsed.hostname = punycode.toUnicode(parsed.hostname)\\n } catch (er) { /**/ }\\n }\\n }\\n\\n // add '%' to exclude list because of https://github.com/markdown-it/markdown-it/issues/720\\n return mdurl.decode(mdurl.format(parsed), mdurl.decode.defaultChars + '%')\\n}\\n\\n/**\\n * class MarkdownIt\\n *\\n * Main parser/renderer class.\\n *\\n * ##### Usage\\n *\\n * ```javascript\\n * // node.js, \\\"classic\\\" way:\\n * var MarkdownIt = require('markdown-it'),\\n * md = new MarkdownIt();\\n * var result = md.render('# markdown-it rulezz!');\\n *\\n * // node.js, the same, but with sugar:\\n * var md = require('markdown-it')();\\n * var result = md.render('# markdown-it rulezz!');\\n *\\n * // browser without AMD, added to \\\"window\\\" on script load\\n * // Note, there are no dash.\\n * var md = window.markdownit();\\n * var result = md.render('# markdown-it rulezz!');\\n * ```\\n *\\n * Single line rendering, without paragraph wrap:\\n *\\n * ```javascript\\n * var md = require('markdown-it')();\\n * var result = md.renderInline('__markdown-it__ rulezz!');\\n * ```\\n **/\\n\\n/**\\n * new MarkdownIt([presetName, options])\\n * - presetName (String): optional, `commonmark` / `zero`\\n * - options (Object)\\n *\\n * Creates parser instanse with given config. Can be called without `new`.\\n *\\n * ##### presetName\\n *\\n * MarkdownIt provides named presets as a convenience to quickly\\n * enable/disable active syntax rules and options for common use cases.\\n *\\n * - [\\\"commonmark\\\"](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/commonmark.mjs) -\\n * configures parser to strict [CommonMark](http://commonmark.org/) mode.\\n * - [default](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/default.mjs) -\\n * similar to GFM, used when no preset name given. Enables all available rules,\\n * but still without html, typographer & autolinker.\\n * - [\\\"zero\\\"](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/zero.mjs) -\\n * all rules disabled. Useful to quickly setup your config via `.enable()`.\\n * For example, when you need only `bold` and `italic` markup and nothing else.\\n *\\n * ##### options:\\n *\\n * - __html__ - `false`. Set `true` to enable HTML tags in source. Be careful!\\n * That's not safe! You may need external sanitizer to protect output from XSS.\\n * It's better to extend features via plugins, instead of enabling HTML.\\n * - __xhtmlOut__ - `false`. Set `true` to add '/' when closing single tags\\n * (`
`). This is needed only for full CommonMark compatibility. In real\\n * world you will need HTML output.\\n * - __breaks__ - `false`. Set `true` to convert `\\\\n` in paragraphs into `
`.\\n * - __langPrefix__ - `language-`. CSS language class prefix for fenced blocks.\\n * Can be useful for external highlighters.\\n * - __linkify__ - `false`. Set `true` to autoconvert URL-like text to links.\\n * - __typographer__ - `false`. Set `true` to enable [some language-neutral\\n * replacement](https://github.com/markdown-it/markdown-it/blob/master/lib/rules_core/replacements.mjs) +\\n * quotes beautification (smartquotes).\\n * - __quotes__ - `“”‘’`, String or Array. Double + single quotes replacement\\n * pairs, when typographer enabled and smartquotes on. For example, you can\\n * use `'«»„“'` for Russian, `'„“‚‘'` for German, and\\n * `['«\\\\xA0', '\\\\xA0»', '‹\\\\xA0', '\\\\xA0›']` for French (including nbsp).\\n * - __highlight__ - `null`. Highlighter function for fenced code blocks.\\n * Highlighter `function (str, lang)` should return escaped HTML. It can also\\n * return empty string if the source was not changed and should be escaped\\n * externaly. If result starts with ` or ``):\\n *\\n * ```javascript\\n * var hljs = require('highlight.js') // https://highlightjs.org/\\n *\\n * // Actual default values\\n * var md = require('markdown-it')({\\n * highlight: function (str, lang) {\\n * if (lang && hljs.getLanguage(lang)) {\\n * try {\\n * return '
' +\\n *                hljs.highlight(str, { language: lang, ignoreIllegals: true }).value +\\n *                '
';\\n * } catch (__) {}\\n * }\\n *\\n * return '
' + md.utils.escapeHtml(str) + '
';\\n * }\\n * });\\n * ```\\n *\\n **/\\nfunction MarkdownIt (presetName, options) {\\n if (!(this instanceof MarkdownIt)) {\\n return new MarkdownIt(presetName, options)\\n }\\n\\n if (!options) {\\n if (!utils.isString(presetName)) {\\n options = presetName || {}\\n presetName = 'default'\\n }\\n }\\n\\n /**\\n * MarkdownIt#inline -> ParserInline\\n *\\n * Instance of [[ParserInline]]. You may need it to add new rules when\\n * writing plugins. For simple rules control use [[MarkdownIt.disable]] and\\n * [[MarkdownIt.enable]].\\n **/\\n this.inline = new ParserInline()\\n\\n /**\\n * MarkdownIt#block -> ParserBlock\\n *\\n * Instance of [[ParserBlock]]. You may need it to add new rules when\\n * writing plugins. For simple rules control use [[MarkdownIt.disable]] and\\n * [[MarkdownIt.enable]].\\n **/\\n this.block = new ParserBlock()\\n\\n /**\\n * MarkdownIt#core -> Core\\n *\\n * Instance of [[Core]] chain executor. You may need it to add new rules when\\n * writing plugins. For simple rules control use [[MarkdownIt.disable]] and\\n * [[MarkdownIt.enable]].\\n **/\\n this.core = new ParserCore()\\n\\n /**\\n * MarkdownIt#renderer -> Renderer\\n *\\n * Instance of [[Renderer]]. Use it to modify output look. Or to add rendering\\n * rules for new token types, generated by plugins.\\n *\\n * ##### Example\\n *\\n * ```javascript\\n * var md = require('markdown-it')();\\n *\\n * function myToken(tokens, idx, options, env, self) {\\n * //...\\n * return result;\\n * };\\n *\\n * md.renderer.rules['my_token'] = myToken\\n * ```\\n *\\n * See [[Renderer]] docs and [source code](https://github.com/markdown-it/markdown-it/blob/master/lib/renderer.mjs).\\n **/\\n this.renderer = new Renderer()\\n\\n /**\\n * MarkdownIt#linkify -> LinkifyIt\\n *\\n * [linkify-it](https://github.com/markdown-it/linkify-it) instance.\\n * Used by [linkify](https://github.com/markdown-it/markdown-it/blob/master/lib/rules_core/linkify.mjs)\\n * rule.\\n **/\\n this.linkify = new LinkifyIt()\\n\\n /**\\n * MarkdownIt#validateLink(url) -> Boolean\\n *\\n * Link validation function. CommonMark allows too much in links. By default\\n * we disable `javascript:`, `vbscript:`, `file:` schemas, and almost all `data:...` schemas\\n * except some embedded image types.\\n *\\n * You can change this behaviour:\\n *\\n * ```javascript\\n * var md = require('markdown-it')();\\n * // enable everything\\n * md.validateLink = function () { return true; }\\n * ```\\n **/\\n this.validateLink = validateLink\\n\\n /**\\n * MarkdownIt#normalizeLink(url) -> String\\n *\\n * Function used to encode link url to a machine-readable format,\\n * which includes url-encoding, punycode, etc.\\n **/\\n this.normalizeLink = normalizeLink\\n\\n /**\\n * MarkdownIt#normalizeLinkText(url) -> String\\n *\\n * Function used to decode link url to a human-readable format`\\n **/\\n this.normalizeLinkText = normalizeLinkText\\n\\n // Expose utils & helpers for easy acces from plugins\\n\\n /**\\n * MarkdownIt#utils -> utils\\n *\\n * Assorted utility functions, useful to write plugins. See details\\n * [here](https://github.com/markdown-it/markdown-it/blob/master/lib/common/utils.mjs).\\n **/\\n this.utils = utils\\n\\n /**\\n * MarkdownIt#helpers -> helpers\\n *\\n * Link components parser functions, useful to write plugins. See details\\n * [here](https://github.com/markdown-it/markdown-it/blob/master/lib/helpers).\\n **/\\n this.helpers = utils.assign({}, helpers)\\n\\n this.options = {}\\n this.configure(presetName)\\n\\n if (options) { this.set(options) }\\n}\\n\\n/** chainable\\n * MarkdownIt.set(options)\\n *\\n * Set parser options (in the same format as in constructor). Probably, you\\n * will never need it, but you can change options after constructor call.\\n *\\n * ##### Example\\n *\\n * ```javascript\\n * var md = require('markdown-it')()\\n * .set({ html: true, breaks: true })\\n * .set({ typographer, true });\\n * ```\\n *\\n * __Note:__ To achieve the best possible performance, don't modify a\\n * `markdown-it` instance options on the fly. If you need multiple configurations\\n * it's best to create multiple instances and initialize each with separate\\n * config.\\n **/\\nMarkdownIt.prototype.set = function (options) {\\n utils.assign(this.options, options)\\n return this\\n}\\n\\n/** chainable, internal\\n * MarkdownIt.configure(presets)\\n *\\n * Batch load of all options and compenent settings. This is internal method,\\n * and you probably will not need it. But if you will - see available presets\\n * and data structure [here](https://github.com/markdown-it/markdown-it/tree/master/lib/presets)\\n *\\n * We strongly recommend to use presets instead of direct config loads. That\\n * will give better compatibility with next versions.\\n **/\\nMarkdownIt.prototype.configure = function (presets) {\\n const self = this\\n\\n if (utils.isString(presets)) {\\n const presetName = presets\\n presets = config[presetName]\\n if (!presets) { throw new Error('Wrong `markdown-it` preset \\\"' + presetName + '\\\", check name') }\\n }\\n\\n if (!presets) { throw new Error('Wrong `markdown-it` preset, can\\\\'t be empty') }\\n\\n if (presets.options) { self.set(presets.options) }\\n\\n if (presets.components) {\\n Object.keys(presets.components).forEach(function (name) {\\n if (presets.components[name].rules) {\\n self[name].ruler.enableOnly(presets.components[name].rules)\\n }\\n if (presets.components[name].rules2) {\\n self[name].ruler2.enableOnly(presets.components[name].rules2)\\n }\\n })\\n }\\n return this\\n}\\n\\n/** chainable\\n * MarkdownIt.enable(list, ignoreInvalid)\\n * - list (String|Array): rule name or list of rule names to enable\\n * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.\\n *\\n * Enable list or rules. It will automatically find appropriate components,\\n * containing rules with given names. If rule not found, and `ignoreInvalid`\\n * not set - throws exception.\\n *\\n * ##### Example\\n *\\n * ```javascript\\n * var md = require('markdown-it')()\\n * .enable(['sub', 'sup'])\\n * .disable('smartquotes');\\n * ```\\n **/\\nMarkdownIt.prototype.enable = function (list, ignoreInvalid) {\\n let result = []\\n\\n if (!Array.isArray(list)) { list = [list] }\\n\\n ['core', 'block', 'inline'].forEach(function (chain) {\\n result = result.concat(this[chain].ruler.enable(list, true))\\n }, this)\\n\\n result = result.concat(this.inline.ruler2.enable(list, true))\\n\\n const missed = list.filter(function (name) { return result.indexOf(name) < 0 })\\n\\n if (missed.length && !ignoreInvalid) {\\n throw new Error('MarkdownIt. Failed to enable unknown rule(s): ' + missed)\\n }\\n\\n return this\\n}\\n\\n/** chainable\\n * MarkdownIt.disable(list, ignoreInvalid)\\n * - list (String|Array): rule name or list of rule names to disable.\\n * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.\\n *\\n * The same as [[MarkdownIt.enable]], but turn specified rules off.\\n **/\\nMarkdownIt.prototype.disable = function (list, ignoreInvalid) {\\n let result = []\\n\\n if (!Array.isArray(list)) { list = [list] }\\n\\n ['core', 'block', 'inline'].forEach(function (chain) {\\n result = result.concat(this[chain].ruler.disable(list, true))\\n }, this)\\n\\n result = result.concat(this.inline.ruler2.disable(list, true))\\n\\n const missed = list.filter(function (name) { return result.indexOf(name) < 0 })\\n\\n if (missed.length && !ignoreInvalid) {\\n throw new Error('MarkdownIt. Failed to disable unknown rule(s): ' + missed)\\n }\\n return this\\n}\\n\\n/** chainable\\n * MarkdownIt.use(plugin, params)\\n *\\n * Load specified plugin with given params into current parser instance.\\n * It's just a sugar to call `plugin(md, params)` with curring.\\n *\\n * ##### Example\\n *\\n * ```javascript\\n * var iterator = require('markdown-it-for-inline');\\n * var md = require('markdown-it')()\\n * .use(iterator, 'foo_replace', 'text', function (tokens, idx) {\\n * tokens[idx].content = tokens[idx].content.replace(/foo/g, 'bar');\\n * });\\n * ```\\n **/\\nMarkdownIt.prototype.use = function (plugin /*, params, ... */) {\\n const args = [this].concat(Array.prototype.slice.call(arguments, 1))\\n plugin.apply(plugin, args)\\n return this\\n}\\n\\n/** internal\\n * MarkdownIt.parse(src, env) -> Array\\n * - src (String): source string\\n * - env (Object): environment sandbox\\n *\\n * Parse input string and return list of block tokens (special token type\\n * \\\"inline\\\" will contain list of inline tokens). You should not call this\\n * method directly, until you write custom renderer (for example, to produce\\n * AST).\\n *\\n * `env` is used to pass data between \\\"distributed\\\" rules and return additional\\n * metadata like reference info, needed for the renderer. It also can be used to\\n * inject data in specific cases. Usually, you will be ok to pass `{}`,\\n * and then pass updated object to renderer.\\n **/\\nMarkdownIt.prototype.parse = function (src, env) {\\n if (typeof src !== 'string') {\\n throw new Error('Input data should be a String')\\n }\\n\\n const state = new this.core.State(src, this, env)\\n\\n this.core.process(state)\\n\\n return state.tokens\\n}\\n\\n/**\\n * MarkdownIt.render(src [, env]) -> String\\n * - src (String): source string\\n * - env (Object): environment sandbox\\n *\\n * Render markdown string into html. It does all magic for you :).\\n *\\n * `env` can be used to inject additional metadata (`{}` by default).\\n * But you will not need it with high probability. See also comment\\n * in [[MarkdownIt.parse]].\\n **/\\nMarkdownIt.prototype.render = function (src, env) {\\n env = env || {}\\n\\n return this.renderer.render(this.parse(src, env), this.options, env)\\n}\\n\\n/** internal\\n * MarkdownIt.parseInline(src, env) -> Array\\n * - src (String): source string\\n * - env (Object): environment sandbox\\n *\\n * The same as [[MarkdownIt.parse]] but skip all block rules. It returns the\\n * block tokens list with the single `inline` element, containing parsed inline\\n * tokens in `children` property. Also updates `env` object.\\n **/\\nMarkdownIt.prototype.parseInline = function (src, env) {\\n const state = new this.core.State(src, this, env)\\n\\n state.inlineMode = true\\n this.core.process(state)\\n\\n return state.tokens\\n}\\n\\n/**\\n * MarkdownIt.renderInline(src [, env]) -> String\\n * - src (String): source string\\n * - env (Object): environment sandbox\\n *\\n * Similar to [[MarkdownIt.render]] but for single paragraph content. Result\\n * will NOT be wrapped into `

` tags.\\n **/\\nMarkdownIt.prototype.renderInline = function (src, env) {\\n env = env || {}\\n\\n return this.renderer.render(this.parseInline(src, env), this.options, env)\\n}\\n\\nexport default MarkdownIt\\n\",\"import MarkdownIt from 'markdown-it';\\n\\nconst md = new MarkdownIt({\\n linkify: true,\\n});\\nconst source = Host.v1.document.get('text/markdown-case');\\nconst tokens = md.parse(source, {});\\nconst links = md.render(source).match(/ token.type),\\n tokenCount: tokens.length,\\n linkCount: links,\\n};\\n\"],\"version\":3}", + "originMeta": { + "originalPath": "node_modules/.pnpm/entities@4.5.0/node_modules/entities/lib/esm/decode.js", + "packageName": "entities", + "packageVersion": "4.5.0", + "integrity": "483aad47a5ae3669a320d313a6ce1be9be705b5c52775cba1b4f45d1fada0562" + } + } + ], + "builderVersion": "deterministic-builder-v1", + "dependencyIntegrity": "483aad47a5ae3669a320d313a6ce1be9be705b5c52775cba1b4f45d1fada0562", + "diagnosticsMeta": { + "entryPath": "/workspace/apps/ecosystem-certifier/fixtures/positive/markdown-it-entry.ts", + "modulePaths": [ + "./markdown-it-entry.js" + ] + }, + "graphHash": "6715cbd20f57956012dee5439799c99cde5890a813559ad2f7440e37c71896f8" + } + } + }, + "manifest": { + "abi_id": "Host.v1", + "abi_version": 1, + "functions": [ + { + "fn_id": 1, + "js_path": [ + "document", + "get" + ], + "effect": "READ", + "arity": 1, + "arg_schema": [ + { + "type": "string" + } + ], + "return_schema": { + "type": "dv" + }, + "gas": { + "schedule_id": "doc-read-v1", + "base": 20, + "k_arg_bytes": 1, + "k_ret_bytes": 1, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 4096, + "max_response_bytes": 262144, + "max_units": 1000, + "arg_utf8_max": [ + 2048 + ] + }, + "error_codes": [ + { + "code": "INVALID_PATH", + "tag": "host/invalid_path" + }, + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + }, + { + "code": "NOT_FOUND", + "tag": "host/not_found" + } + ] + }, + { + "fn_id": 2, + "js_path": [ + "document", + "getCanonical" + ], + "effect": "READ", + "arity": 1, + "arg_schema": [ + { + "type": "string" + } + ], + "return_schema": { + "type": "dv" + }, + "gas": { + "schedule_id": "doc-read-v1", + "base": 20, + "k_arg_bytes": 1, + "k_ret_bytes": 1, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 4096, + "max_response_bytes": 262144, + "max_units": 1000, + "arg_utf8_max": [ + 2048 + ] + }, + "error_codes": [ + { + "code": "INVALID_PATH", + "tag": "host/invalid_path" + }, + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + }, + { + "code": "NOT_FOUND", + "tag": "host/not_found" + } + ] + }, + { + "fn_id": 3, + "js_path": [ + "emit" + ], + "effect": "EMIT", + "arity": 1, + "arg_schema": [ + { + "type": "dv" + } + ], + "return_schema": { + "type": "null" + }, + "gas": { + "schedule_id": "emit-v1", + "base": 5, + "k_arg_bytes": 1, + "k_ret_bytes": 0, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 32768, + "max_response_bytes": 64, + "max_units": 1024 + }, + "error_codes": [ + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + } + ] + } + ] + } + }, + { + "id": "green-noble-sha", + "title": "@noble/hashes deterministic digest", + "kind": "ecosystem-green", + "badge": "Green ecosystem fixture", + "description": "A binary-heavy crypto-style fixture showing deterministic digest behavior.", + "certified": true, + "executionProfile": "compat-binary-v1", + "sourceKind": "module-pack", + "abiId": "Host.v2", + "gasLimit": "5000000", + "sourcePaths": [ + "libs/test-harness/fixtures/library-reuse/binary-sha256-entry.ts" + ], + "sourceText": "import { sha256 } from '@noble/hashes/sha256';\nimport { bytesToHex } from '@noble/hashes/utils';\n\nconst digest = sha256(\n Uint8Array.from([\n 98, 108, 117, 101, 45, 113, 117, 105, 99, 107, 106, 115, 45, 98, 105, 110,\n 97, 114, 121, 45, 102, 105, 120, 116, 117, 114, 101,\n ]),\n);\n\nexport default {\n hex: bytesToHex(digest),\n length: digest.length,\n first: digest[0],\n last: digest[digest.length - 1],\n};\n", + "hostPreset": "certification", + "hostSummary": { + "label": "Certification host", + "description": "Provides the ecosystem-certifier text and binary documents used for workload certification.", + "documents": [ + "pack/metadata.json", + "pack/metadata.yaml", + "docs/a.md", + "docs/b.md", + "docs/c.md", + "docs/d.md", + "bytes/payload", + "bytes/flagship-extra", + "pack/attachment.deflated" + ] + }, + "docsLinks": [ + { + "label": "Workload certification", + "href": "/docs/workload-certification.md" + }, + { + "label": "Compatibility report", + "href": "/docs/ecosystem-compatibility-report.md" + } + ], + "supportsOogSearch": false, + "program": { + "version": 2, + "abiId": "Host.v2", + "abiVersion": 2, + "abiManifestHash": "ec5c3df99a1b0ab84b692996193707ae6c931382e75c96c7c14b4f8baaae5af2", + "engineBuildHash": "f91091cb7feb788df340305a877a9cadb0c6f4d13aea8a7da4040b6367d178ea", + "gasVersion": 8, + "executionProfile": "compat-binary-v1", + "sourceKind": "module-pack", + "source": { + "modulePack": { + "version": 1, + "entrySpecifier": "./binary-sha256-entry.js", + "entryExport": "default", + "modules": [ + { + "specifier": "./binary-sha256-entry.js", + "source": "// node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/utils.js\nfunction isBytes(a) {\n return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === \"Uint8Array\";\n}\nfunction abytes(b, ...lengths) {\n if (!isBytes(b))\n throw new Error(\"Uint8Array expected\");\n if (lengths.length > 0 && !lengths.includes(b.length))\n throw new Error(\"Uint8Array expected of length \" + lengths + \", got length=\" + b.length);\n}\nfunction aexists(instance, checkFinished = true) {\n if (instance.destroyed)\n throw new Error(\"Hash instance has been destroyed\");\n if (checkFinished && instance.finished)\n throw new Error(\"Hash#digest() has already been called\");\n}\nfunction aoutput(out, instance) {\n abytes(out);\n const min = instance.outputLen;\n if (out.length < min) {\n throw new Error(\"digestInto() expects output buffer of length at least \" + min);\n }\n}\nfunction clean(...arrays) {\n for (let i = 0; i < arrays.length; i++) {\n arrays[i].fill(0);\n }\n}\nfunction createView(arr) {\n return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);\n}\nfunction rotr(word, shift) {\n return word << 32 - shift | word >>> shift;\n}\nvar hasHexBuiltin = /* @__PURE__ */ (() => (\n // @ts-ignore\n typeof Uint8Array.from([]).toHex === \"function\" && typeof Uint8Array.fromHex === \"function\"\n))();\nvar hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, \"0\"));\nfunction bytesToHex(bytes) {\n abytes(bytes);\n if (hasHexBuiltin)\n return bytes.toHex();\n let hex = \"\";\n for (let i = 0; i < bytes.length; i++) {\n hex += hexes[bytes[i]];\n }\n return hex;\n}\nfunction utf8ToBytes(str) {\n if (typeof str !== \"string\")\n throw new Error(\"string expected\");\n return new Uint8Array(new TextEncoder().encode(str));\n}\nfunction toBytes(data) {\n if (typeof data === \"string\")\n data = utf8ToBytes(data);\n abytes(data);\n return data;\n}\nvar Hash = class {\n};\nfunction createHasher(hashCons) {\n const hashC = (msg) => hashCons().update(toBytes(msg)).digest();\n const tmp = hashCons();\n hashC.outputLen = tmp.outputLen;\n hashC.blockLen = tmp.blockLen;\n hashC.create = () => hashCons();\n return hashC;\n}\n\n// node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/_md.js\nfunction setBigUint64(view, byteOffset, value, isLE) {\n if (typeof view.setBigUint64 === \"function\")\n return view.setBigUint64(byteOffset, value, isLE);\n const _32n = BigInt(32);\n const _u32_max = BigInt(4294967295);\n const wh = Number(value >> _32n & _u32_max);\n const wl = Number(value & _u32_max);\n const h = isLE ? 4 : 0;\n const l = isLE ? 0 : 4;\n view.setUint32(byteOffset + h, wh, isLE);\n view.setUint32(byteOffset + l, wl, isLE);\n}\nfunction Chi(a, b, c) {\n return a & b ^ ~a & c;\n}\nfunction Maj(a, b, c) {\n return a & b ^ a & c ^ b & c;\n}\nvar HashMD = class extends Hash {\n constructor(blockLen, outputLen, padOffset, isLE) {\n super();\n this.finished = false;\n this.length = 0;\n this.pos = 0;\n this.destroyed = false;\n this.blockLen = blockLen;\n this.outputLen = outputLen;\n this.padOffset = padOffset;\n this.isLE = isLE;\n this.buffer = new Uint8Array(blockLen);\n this.view = createView(this.buffer);\n }\n update(data) {\n aexists(this);\n data = toBytes(data);\n abytes(data);\n const { view, buffer, blockLen } = this;\n const len = data.length;\n for (let pos = 0; pos < len; ) {\n const take = Math.min(blockLen - this.pos, len - pos);\n if (take === blockLen) {\n const dataView = createView(data);\n for (; blockLen <= len - pos; pos += blockLen)\n this.process(dataView, pos);\n continue;\n }\n buffer.set(data.subarray(pos, pos + take), this.pos);\n this.pos += take;\n pos += take;\n if (this.pos === blockLen) {\n this.process(view, 0);\n this.pos = 0;\n }\n }\n this.length += data.length;\n this.roundClean();\n return this;\n }\n digestInto(out) {\n aexists(this);\n aoutput(out, this);\n this.finished = true;\n const { buffer, view, blockLen, isLE } = this;\n let { pos } = this;\n buffer[pos++] = 128;\n clean(this.buffer.subarray(pos));\n if (this.padOffset > blockLen - pos) {\n this.process(view, 0);\n pos = 0;\n }\n for (let i = pos; i < blockLen; i++)\n buffer[i] = 0;\n setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE);\n this.process(view, 0);\n const oview = createView(out);\n const len = this.outputLen;\n if (len % 4)\n throw new Error(\"_sha2: outputLen should be aligned to 32bit\");\n const outLen = len / 4;\n const state = this.get();\n if (outLen > state.length)\n throw new Error(\"_sha2: outputLen bigger than state\");\n for (let i = 0; i < outLen; i++)\n oview.setUint32(4 * i, state[i], isLE);\n }\n digest() {\n const { buffer, outputLen } = this;\n this.digestInto(buffer);\n const res = buffer.slice(0, outputLen);\n this.destroy();\n return res;\n }\n _cloneInto(to) {\n to || (to = new this.constructor());\n to.set(...this.get());\n const { blockLen, buffer, length, finished, destroyed, pos } = this;\n to.destroyed = destroyed;\n to.finished = finished;\n to.length = length;\n to.pos = pos;\n if (length % blockLen)\n to.buffer.set(buffer);\n return to;\n }\n clone() {\n return this._cloneInto();\n }\n};\nvar SHA256_IV = /* @__PURE__ */ Uint32Array.from([\n 1779033703,\n 3144134277,\n 1013904242,\n 2773480762,\n 1359893119,\n 2600822924,\n 528734635,\n 1541459225\n]);\n\n// node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/sha2.js\nvar SHA256_K = /* @__PURE__ */ Uint32Array.from([\n 1116352408,\n 1899447441,\n 3049323471,\n 3921009573,\n 961987163,\n 1508970993,\n 2453635748,\n 2870763221,\n 3624381080,\n 310598401,\n 607225278,\n 1426881987,\n 1925078388,\n 2162078206,\n 2614888103,\n 3248222580,\n 3835390401,\n 4022224774,\n 264347078,\n 604807628,\n 770255983,\n 1249150122,\n 1555081692,\n 1996064986,\n 2554220882,\n 2821834349,\n 2952996808,\n 3210313671,\n 3336571891,\n 3584528711,\n 113926993,\n 338241895,\n 666307205,\n 773529912,\n 1294757372,\n 1396182291,\n 1695183700,\n 1986661051,\n 2177026350,\n 2456956037,\n 2730485921,\n 2820302411,\n 3259730800,\n 3345764771,\n 3516065817,\n 3600352804,\n 4094571909,\n 275423344,\n 430227734,\n 506948616,\n 659060556,\n 883997877,\n 958139571,\n 1322822218,\n 1537002063,\n 1747873779,\n 1955562222,\n 2024104815,\n 2227730452,\n 2361852424,\n 2428436474,\n 2756734187,\n 3204031479,\n 3329325298\n]);\nvar SHA256_W = /* @__PURE__ */ new Uint32Array(64);\nvar SHA256 = class extends HashMD {\n constructor(outputLen = 32) {\n super(64, outputLen, 8, false);\n this.A = SHA256_IV[0] | 0;\n this.B = SHA256_IV[1] | 0;\n this.C = SHA256_IV[2] | 0;\n this.D = SHA256_IV[3] | 0;\n this.E = SHA256_IV[4] | 0;\n this.F = SHA256_IV[5] | 0;\n this.G = SHA256_IV[6] | 0;\n this.H = SHA256_IV[7] | 0;\n }\n get() {\n const { A, B, C, D, E, F, G, H } = this;\n return [A, B, C, D, E, F, G, H];\n }\n // prettier-ignore\n set(A, B, C, D, E, F, G, H) {\n this.A = A | 0;\n this.B = B | 0;\n this.C = C | 0;\n this.D = D | 0;\n this.E = E | 0;\n this.F = F | 0;\n this.G = G | 0;\n this.H = H | 0;\n }\n process(view, offset) {\n for (let i = 0; i < 16; i++, offset += 4)\n SHA256_W[i] = view.getUint32(offset, false);\n for (let i = 16; i < 64; i++) {\n const W15 = SHA256_W[i - 15];\n const W2 = SHA256_W[i - 2];\n const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ W15 >>> 3;\n const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ W2 >>> 10;\n SHA256_W[i] = s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16] | 0;\n }\n let { A, B, C, D, E, F, G, H } = this;\n for (let i = 0; i < 64; i++) {\n const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);\n const T1 = H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i] | 0;\n const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22);\n const T2 = sigma0 + Maj(A, B, C) | 0;\n H = G;\n G = F;\n F = E;\n E = D + T1 | 0;\n D = C;\n C = B;\n B = A;\n A = T1 + T2 | 0;\n }\n A = A + this.A | 0;\n B = B + this.B | 0;\n C = C + this.C | 0;\n D = D + this.D | 0;\n E = E + this.E | 0;\n F = F + this.F | 0;\n G = G + this.G | 0;\n H = H + this.H | 0;\n this.set(A, B, C, D, E, F, G, H);\n }\n roundClean() {\n clean(SHA256_W);\n }\n destroy() {\n this.set(0, 0, 0, 0, 0, 0, 0, 0);\n clean(this.buffer);\n }\n};\nvar sha256 = /* @__PURE__ */ createHasher(() => new SHA256());\n\n// node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/sha256.js\nvar sha2562 = sha256;\n\n// libs/test-harness/fixtures/library-reuse/binary-sha256-entry.ts\nvar digest = sha2562(\n Uint8Array.from([\n 98,\n 108,\n 117,\n 101,\n 45,\n 113,\n 117,\n 105,\n 99,\n 107,\n 106,\n 115,\n 45,\n 98,\n 105,\n 110,\n 97,\n 114,\n 121,\n 45,\n 102,\n 105,\n 120,\n 116,\n 117,\n 114,\n 101\n ])\n);\nvar binary_sha256_entry_default = {\n hex: bytesToHex(digest),\n length: digest.length,\n first: digest[0],\n last: digest[digest.length - 1]\n};\nexport {\n binary_sha256_entry_default as default\n};\n", + "sourceMap": "{\"mappings\":\"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\",\"names\":[\"sha256\",\"sha256\"],\"sources\":[\"../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/src/utils.ts\",\"../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/src/_md.ts\",\"../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/src/sha2.ts\",\"../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/src/sha256.ts\",\"../libs/test-harness/fixtures/library-reuse/binary-sha256-entry.ts\"],\"sourcesContent\":[\"/**\\n * Utilities for hex, bytes, CSPRNG.\\n * @module\\n */\\n/*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */\\n\\n// We use WebCrypto aka globalThis.crypto, which exists in browsers and node.js 16+.\\n// node.js versions earlier than v19 don't declare it in global scope.\\n// For node.js, package.json#exports field mapping rewrites import\\n// from `crypto` to `cryptoNode`, which imports native module.\\n// Makes the utils un-importable in browsers without a bundler.\\n// Once node.js 18 is deprecated (2025-04-30), we can just drop the import.\\nimport { crypto } from '@noble/hashes/crypto';\\n\\n/** Checks if something is Uint8Array. Be careful: nodejs Buffer will return true. */\\nexport function isBytes(a: unknown): a is Uint8Array {\\n return a instanceof Uint8Array || (ArrayBuffer.isView(a) && a.constructor.name === 'Uint8Array');\\n}\\n\\n/** Asserts something is positive integer. */\\nexport function anumber(n: number): void {\\n if (!Number.isSafeInteger(n) || n < 0) throw new Error('positive integer expected, got ' + n);\\n}\\n\\n/** Asserts something is Uint8Array. */\\nexport function abytes(b: Uint8Array | undefined, ...lengths: number[]): void {\\n if (!isBytes(b)) throw new Error('Uint8Array expected');\\n if (lengths.length > 0 && !lengths.includes(b.length))\\n throw new Error('Uint8Array expected of length ' + lengths + ', got length=' + b.length);\\n}\\n\\n/** Asserts something is hash */\\nexport function ahash(h: IHash): void {\\n if (typeof h !== 'function' || typeof h.create !== 'function')\\n throw new Error('Hash should be wrapped by utils.createHasher');\\n anumber(h.outputLen);\\n anumber(h.blockLen);\\n}\\n\\n/** Asserts a hash instance has not been destroyed / finished */\\nexport function aexists(instance: any, checkFinished = true): void {\\n if (instance.destroyed) throw new Error('Hash instance has been destroyed');\\n if (checkFinished && instance.finished) throw new Error('Hash#digest() has already been called');\\n}\\n\\n/** Asserts output is properly-sized byte array */\\nexport function aoutput(out: any, instance: any): void {\\n abytes(out);\\n const min = instance.outputLen;\\n if (out.length < min) {\\n throw new Error('digestInto() expects output buffer of length at least ' + min);\\n }\\n}\\n\\n/** Generic type encompassing 8/16/32-byte arrays - but not 64-byte. */\\n// prettier-ignore\\nexport type TypedArray = Int8Array | Uint8ClampedArray | Uint8Array |\\n Uint16Array | Int16Array | Uint32Array | Int32Array;\\n\\n/** Cast u8 / u16 / u32 to u8. */\\nexport function u8(arr: TypedArray): Uint8Array {\\n return new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength);\\n}\\n\\n/** Cast u8 / u16 / u32 to u32. */\\nexport function u32(arr: TypedArray): Uint32Array {\\n return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4));\\n}\\n\\n/** Zeroize a byte array. Warning: JS provides no guarantees. */\\nexport function clean(...arrays: TypedArray[]): void {\\n for (let i = 0; i < arrays.length; i++) {\\n arrays[i].fill(0);\\n }\\n}\\n\\n/** Create DataView of an array for easy byte-level manipulation. */\\nexport function createView(arr: TypedArray): DataView {\\n return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);\\n}\\n\\n/** The rotate right (circular right shift) operation for uint32 */\\nexport function rotr(word: number, shift: number): number {\\n return (word << (32 - shift)) | (word >>> shift);\\n}\\n\\n/** The rotate left (circular left shift) operation for uint32 */\\nexport function rotl(word: number, shift: number): number {\\n return (word << shift) | ((word >>> (32 - shift)) >>> 0);\\n}\\n\\n/** Is current platform little-endian? Most are. Big-Endian platform: IBM */\\nexport const isLE: boolean = /* @__PURE__ */ (() =>\\n new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x44)();\\n\\n/** The byte swap operation for uint32 */\\nexport function byteSwap(word: number): number {\\n return (\\n ((word << 24) & 0xff000000) |\\n ((word << 8) & 0xff0000) |\\n ((word >>> 8) & 0xff00) |\\n ((word >>> 24) & 0xff)\\n );\\n}\\n/** Conditionally byte swap if on a big-endian platform */\\nexport const swap8IfBE: (n: number) => number = isLE\\n ? (n: number) => n\\n : (n: number) => byteSwap(n);\\n\\n/** @deprecated */\\nexport const byteSwapIfBE: typeof swap8IfBE = swap8IfBE;\\n/** In place byte swap for Uint32Array */\\nexport function byteSwap32(arr: Uint32Array): Uint32Array {\\n for (let i = 0; i < arr.length; i++) {\\n arr[i] = byteSwap(arr[i]);\\n }\\n return arr;\\n}\\n\\nexport const swap32IfBE: (u: Uint32Array) => Uint32Array = isLE\\n ? (u: Uint32Array) => u\\n : byteSwap32;\\n\\n// Built-in hex conversion https://caniuse.com/mdn-javascript_builtins_uint8array_fromhex\\nconst hasHexBuiltin: boolean = /* @__PURE__ */ (() =>\\n // @ts-ignore\\n typeof Uint8Array.from([]).toHex === 'function' && typeof Uint8Array.fromHex === 'function')();\\n\\n// Array where index 0xf0 (240) is mapped to string 'f0'\\nconst hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) =>\\n i.toString(16).padStart(2, '0')\\n);\\n\\n/**\\n * Convert byte array to hex string. Uses built-in function, when available.\\n * @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'\\n */\\nexport function bytesToHex(bytes: Uint8Array): string {\\n abytes(bytes);\\n // @ts-ignore\\n if (hasHexBuiltin) return bytes.toHex();\\n // pre-caching improves the speed 6x\\n let hex = '';\\n for (let i = 0; i < bytes.length; i++) {\\n hex += hexes[bytes[i]];\\n }\\n return hex;\\n}\\n\\n// We use optimized technique to convert hex string to byte array\\nconst asciis = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 } as const;\\nfunction asciiToBase16(ch: number): number | undefined {\\n if (ch >= asciis._0 && ch <= asciis._9) return ch - asciis._0; // '2' => 50-48\\n if (ch >= asciis.A && ch <= asciis.F) return ch - (asciis.A - 10); // 'B' => 66-(65-10)\\n if (ch >= asciis.a && ch <= asciis.f) return ch - (asciis.a - 10); // 'b' => 98-(97-10)\\n return;\\n}\\n\\n/**\\n * Convert hex string to byte array. Uses built-in function, when available.\\n * @example hexToBytes('cafe0123') // Uint8Array.from([0xca, 0xfe, 0x01, 0x23])\\n */\\nexport function hexToBytes(hex: string): Uint8Array {\\n if (typeof hex !== 'string') throw new Error('hex string expected, got ' + typeof hex);\\n // @ts-ignore\\n if (hasHexBuiltin) return Uint8Array.fromHex(hex);\\n const hl = hex.length;\\n const al = hl / 2;\\n if (hl % 2) throw new Error('hex string expected, got unpadded hex of length ' + hl);\\n const array = new Uint8Array(al);\\n for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {\\n const n1 = asciiToBase16(hex.charCodeAt(hi));\\n const n2 = asciiToBase16(hex.charCodeAt(hi + 1));\\n if (n1 === undefined || n2 === undefined) {\\n const char = hex[hi] + hex[hi + 1];\\n throw new Error('hex string expected, got non-hex character \\\"' + char + '\\\" at index ' + hi);\\n }\\n array[ai] = n1 * 16 + n2; // multiply first octet, e.g. 'a3' => 10*16+3 => 160 + 3 => 163\\n }\\n return array;\\n}\\n\\n/**\\n * There is no setImmediate in browser and setTimeout is slow.\\n * Call of async fn will return Promise, which will be fullfiled only on\\n * next scheduler queue processing step and this is exactly what we need.\\n */\\nexport const nextTick = async (): Promise => {};\\n\\n/** Returns control to thread each 'tick' ms to avoid blocking. */\\nexport async function asyncLoop(\\n iters: number,\\n tick: number,\\n cb: (i: number) => void\\n): Promise {\\n let ts = Date.now();\\n for (let i = 0; i < iters; i++) {\\n cb(i);\\n // Date.now() is not monotonic, so in case if clock goes backwards we return return control too\\n const diff = Date.now() - ts;\\n if (diff >= 0 && diff < tick) continue;\\n await nextTick();\\n ts += diff;\\n }\\n}\\n\\n// Global symbols, but ts doesn't see them: https://github.com/microsoft/TypeScript/issues/31535\\ndeclare const TextEncoder: any;\\ndeclare const TextDecoder: any;\\n\\n/**\\n * Converts string to bytes using UTF8 encoding.\\n * @example utf8ToBytes('abc') // Uint8Array.from([97, 98, 99])\\n */\\nexport function utf8ToBytes(str: string): Uint8Array {\\n if (typeof str !== 'string') throw new Error('string expected');\\n return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809\\n}\\n\\n/**\\n * Converts bytes to string using UTF8 encoding.\\n * @example bytesToUtf8(Uint8Array.from([97, 98, 99])) // 'abc'\\n */\\nexport function bytesToUtf8(bytes: Uint8Array): string {\\n return new TextDecoder().decode(bytes);\\n}\\n\\n/** Accepted input of hash functions. Strings are converted to byte arrays. */\\nexport type Input = string | Uint8Array;\\n/**\\n * Normalizes (non-hex) string or Uint8Array to Uint8Array.\\n * Warning: when Uint8Array is passed, it would NOT get copied.\\n * Keep in mind for future mutable operations.\\n */\\nexport function toBytes(data: Input): Uint8Array {\\n if (typeof data === 'string') data = utf8ToBytes(data);\\n abytes(data);\\n return data;\\n}\\n\\n/** KDFs can accept string or Uint8Array for user convenience. */\\nexport type KDFInput = string | Uint8Array;\\n/**\\n * Helper for KDFs: consumes uint8array or string.\\n * When string is passed, does utf8 decoding, using TextDecoder.\\n */\\nexport function kdfInputToBytes(data: KDFInput): Uint8Array {\\n if (typeof data === 'string') data = utf8ToBytes(data);\\n abytes(data);\\n return data;\\n}\\n\\n/** Copies several Uint8Arrays into one. */\\nexport function concatBytes(...arrays: Uint8Array[]): Uint8Array {\\n let sum = 0;\\n for (let i = 0; i < arrays.length; i++) {\\n const a = arrays[i];\\n abytes(a);\\n sum += a.length;\\n }\\n const res = new Uint8Array(sum);\\n for (let i = 0, pad = 0; i < arrays.length; i++) {\\n const a = arrays[i];\\n res.set(a, pad);\\n pad += a.length;\\n }\\n return res;\\n}\\n\\ntype EmptyObj = {};\\nexport function checkOpts(\\n defaults: T1,\\n opts?: T2\\n): T1 & T2 {\\n if (opts !== undefined && {}.toString.call(opts) !== '[object Object]')\\n throw new Error('options should be object or undefined');\\n const merged = Object.assign(defaults, opts);\\n return merged as T1 & T2;\\n}\\n\\n/** Hash interface. */\\nexport type IHash = {\\n (data: Uint8Array): Uint8Array;\\n blockLen: number;\\n outputLen: number;\\n create: any;\\n};\\n\\n/** For runtime check if class implements interface */\\nexport abstract class Hash> {\\n abstract blockLen: number; // Bytes per block\\n abstract outputLen: number; // Bytes in output\\n abstract update(buf: Input): this;\\n // Writes digest into buf\\n abstract digestInto(buf: Uint8Array): void;\\n abstract digest(): Uint8Array;\\n /**\\n * Resets internal state. Makes Hash instance unusable.\\n * Reset is impossible for keyed hashes if key is consumed into state. If digest is not consumed\\n * by user, they will need to manually call `destroy()` when zeroing is necessary.\\n */\\n abstract destroy(): void;\\n /**\\n * Clones hash instance. Unsafe: doesn't check whether `to` is valid. Can be used as `clone()`\\n * when no options are passed.\\n * Reasons to use `_cloneInto` instead of clone: 1) performance 2) reuse instance => all internal\\n * buffers are overwritten => causes buffer overwrite which is used for digest in some cases.\\n * There are no guarantees for clean-up because it's impossible in JS.\\n */\\n abstract _cloneInto(to?: T): T;\\n // Safe version that clones internal state\\n abstract clone(): T;\\n}\\n\\n/**\\n * XOF: streaming API to read digest in chunks.\\n * Same as 'squeeze' in keccak/k12 and 'seek' in blake3, but more generic name.\\n * When hash used in XOF mode it is up to user to call '.destroy' afterwards, since we cannot\\n * destroy state, next call can require more bytes.\\n */\\nexport type HashXOF> = Hash & {\\n xof(bytes: number): Uint8Array; // Read 'bytes' bytes from digest stream\\n xofInto(buf: Uint8Array): Uint8Array; // read buf.length bytes from digest stream into buf\\n};\\n\\n/** Hash function */\\nexport type CHash = ReturnType;\\n/** Hash function with output */\\nexport type CHashO = ReturnType;\\n/** XOF with output */\\nexport type CHashXO = ReturnType;\\n\\n/** Wraps hash function, creating an interface on top of it */\\nexport function createHasher>(\\n hashCons: () => Hash\\n): {\\n (msg: Input): Uint8Array;\\n outputLen: number;\\n blockLen: number;\\n create(): Hash;\\n} {\\n const hashC = (msg: Input): Uint8Array => hashCons().update(toBytes(msg)).digest();\\n const tmp = hashCons();\\n hashC.outputLen = tmp.outputLen;\\n hashC.blockLen = tmp.blockLen;\\n hashC.create = () => hashCons();\\n return hashC;\\n}\\n\\nexport function createOptHasher, T extends Object>(\\n hashCons: (opts?: T) => Hash\\n): {\\n (msg: Input, opts?: T): Uint8Array;\\n outputLen: number;\\n blockLen: number;\\n create(opts?: T): Hash;\\n} {\\n const hashC = (msg: Input, opts?: T): Uint8Array => hashCons(opts).update(toBytes(msg)).digest();\\n const tmp = hashCons({} as T);\\n hashC.outputLen = tmp.outputLen;\\n hashC.blockLen = tmp.blockLen;\\n hashC.create = (opts?: T) => hashCons(opts);\\n return hashC;\\n}\\n\\nexport function createXOFer, T extends Object>(\\n hashCons: (opts?: T) => HashXOF\\n): {\\n (msg: Input, opts?: T): Uint8Array;\\n outputLen: number;\\n blockLen: number;\\n create(opts?: T): HashXOF;\\n} {\\n const hashC = (msg: Input, opts?: T): Uint8Array => hashCons(opts).update(toBytes(msg)).digest();\\n const tmp = hashCons({} as T);\\n hashC.outputLen = tmp.outputLen;\\n hashC.blockLen = tmp.blockLen;\\n hashC.create = (opts?: T) => hashCons(opts);\\n return hashC;\\n}\\nexport const wrapConstructor: typeof createHasher = createHasher;\\nexport const wrapConstructorWithOpts: typeof createOptHasher = createOptHasher;\\nexport const wrapXOFConstructorWithOpts: typeof createXOFer = createXOFer;\\n\\n/** Cryptographically secure PRNG. Uses internal OS-level `crypto.getRandomValues`. */\\nexport function randomBytes(bytesLength = 32): Uint8Array {\\n if (crypto && typeof crypto.getRandomValues === 'function') {\\n return crypto.getRandomValues(new Uint8Array(bytesLength));\\n }\\n // Legacy Node.js compatibility\\n if (crypto && typeof crypto.randomBytes === 'function') {\\n return Uint8Array.from(crypto.randomBytes(bytesLength));\\n }\\n throw new Error('crypto.getRandomValues must be defined');\\n}\\n\",\"/**\\n * Internal Merkle-Damgard hash utils.\\n * @module\\n */\\nimport { type Input, Hash, abytes, aexists, aoutput, clean, createView, toBytes } from './utils.ts';\\n\\n/** Polyfill for Safari 14. https://caniuse.com/mdn-javascript_builtins_dataview_setbiguint64 */\\nexport function setBigUint64(\\n view: DataView,\\n byteOffset: number,\\n value: bigint,\\n isLE: boolean\\n): void {\\n if (typeof view.setBigUint64 === 'function') return view.setBigUint64(byteOffset, value, isLE);\\n const _32n = BigInt(32);\\n const _u32_max = BigInt(0xffffffff);\\n const wh = Number((value >> _32n) & _u32_max);\\n const wl = Number(value & _u32_max);\\n const h = isLE ? 4 : 0;\\n const l = isLE ? 0 : 4;\\n view.setUint32(byteOffset + h, wh, isLE);\\n view.setUint32(byteOffset + l, wl, isLE);\\n}\\n\\n/** Choice: a ? b : c */\\nexport function Chi(a: number, b: number, c: number): number {\\n return (a & b) ^ (~a & c);\\n}\\n\\n/** Majority function, true if any two inputs is true. */\\nexport function Maj(a: number, b: number, c: number): number {\\n return (a & b) ^ (a & c) ^ (b & c);\\n}\\n\\n/**\\n * Merkle-Damgard hash construction base class.\\n * Could be used to create MD5, RIPEMD, SHA1, SHA2.\\n */\\nexport abstract class HashMD> extends Hash {\\n protected abstract process(buf: DataView, offset: number): void;\\n protected abstract get(): number[];\\n protected abstract set(...args: number[]): void;\\n abstract destroy(): void;\\n protected abstract roundClean(): void;\\n\\n readonly blockLen: number;\\n readonly outputLen: number;\\n readonly padOffset: number;\\n readonly isLE: boolean;\\n\\n // For partial updates less than block size\\n protected buffer: Uint8Array;\\n protected view: DataView;\\n protected finished = false;\\n protected length = 0;\\n protected pos = 0;\\n protected destroyed = false;\\n\\n constructor(blockLen: number, outputLen: number, padOffset: number, isLE: boolean) {\\n super();\\n this.blockLen = blockLen;\\n this.outputLen = outputLen;\\n this.padOffset = padOffset;\\n this.isLE = isLE;\\n this.buffer = new Uint8Array(blockLen);\\n this.view = createView(this.buffer);\\n }\\n update(data: Input): this {\\n aexists(this);\\n data = toBytes(data);\\n abytes(data);\\n const { view, buffer, blockLen } = this;\\n const len = data.length;\\n for (let pos = 0; pos < len; ) {\\n const take = Math.min(blockLen - this.pos, len - pos);\\n // Fast path: we have at least one block in input, cast it to view and process\\n if (take === blockLen) {\\n const dataView = createView(data);\\n for (; blockLen <= len - pos; pos += blockLen) this.process(dataView, pos);\\n continue;\\n }\\n buffer.set(data.subarray(pos, pos + take), this.pos);\\n this.pos += take;\\n pos += take;\\n if (this.pos === blockLen) {\\n this.process(view, 0);\\n this.pos = 0;\\n }\\n }\\n this.length += data.length;\\n this.roundClean();\\n return this;\\n }\\n digestInto(out: Uint8Array): void {\\n aexists(this);\\n aoutput(out, this);\\n this.finished = true;\\n // Padding\\n // We can avoid allocation of buffer for padding completely if it\\n // was previously not allocated here. But it won't change performance.\\n const { buffer, view, blockLen, isLE } = this;\\n let { pos } = this;\\n // append the bit '1' to the message\\n buffer[pos++] = 0b10000000;\\n clean(this.buffer.subarray(pos));\\n // we have less than padOffset left in buffer, so we cannot put length in\\n // current block, need process it and pad again\\n if (this.padOffset > blockLen - pos) {\\n this.process(view, 0);\\n pos = 0;\\n }\\n // Pad until full block byte with zeros\\n for (let i = pos; i < blockLen; i++) buffer[i] = 0;\\n // Note: sha512 requires length to be 128bit integer, but length in JS will overflow before that\\n // You need to write around 2 exabytes (u64_max / 8 / (1024**6)) for this to happen.\\n // So we just write lowest 64 bits of that value.\\n setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE);\\n this.process(view, 0);\\n const oview = createView(out);\\n const len = this.outputLen;\\n // NOTE: we do division by 4 later, which should be fused in single op with modulo by JIT\\n if (len % 4) throw new Error('_sha2: outputLen should be aligned to 32bit');\\n const outLen = len / 4;\\n const state = this.get();\\n if (outLen > state.length) throw new Error('_sha2: outputLen bigger than state');\\n for (let i = 0; i < outLen; i++) oview.setUint32(4 * i, state[i], isLE);\\n }\\n digest(): Uint8Array {\\n const { buffer, outputLen } = this;\\n this.digestInto(buffer);\\n const res = buffer.slice(0, outputLen);\\n this.destroy();\\n return res;\\n }\\n _cloneInto(to?: T): T {\\n to ||= new (this.constructor as any)() as T;\\n to.set(...this.get());\\n const { blockLen, buffer, length, finished, destroyed, pos } = this;\\n to.destroyed = destroyed;\\n to.finished = finished;\\n to.length = length;\\n to.pos = pos;\\n if (length % blockLen) to.buffer.set(buffer);\\n return to;\\n }\\n clone(): T {\\n return this._cloneInto();\\n }\\n}\\n\\n/**\\n * Initial SHA-2 state: fractional parts of square roots of first 16 primes 2..53.\\n * Check out `test/misc/sha2-gen-iv.js` for recomputation guide.\\n */\\n\\n/** Initial SHA256 state. Bits 0..32 of frac part of sqrt of primes 2..19 */\\nexport const SHA256_IV: Uint32Array = /* @__PURE__ */ Uint32Array.from([\\n 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,\\n]);\\n\\n/** Initial SHA224 state. Bits 32..64 of frac part of sqrt of primes 23..53 */\\nexport const SHA224_IV: Uint32Array = /* @__PURE__ */ Uint32Array.from([\\n 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4,\\n]);\\n\\n/** Initial SHA384 state. Bits 0..64 of frac part of sqrt of primes 23..53 */\\nexport const SHA384_IV: Uint32Array = /* @__PURE__ */ Uint32Array.from([\\n 0xcbbb9d5d, 0xc1059ed8, 0x629a292a, 0x367cd507, 0x9159015a, 0x3070dd17, 0x152fecd8, 0xf70e5939,\\n 0x67332667, 0xffc00b31, 0x8eb44a87, 0x68581511, 0xdb0c2e0d, 0x64f98fa7, 0x47b5481d, 0xbefa4fa4,\\n]);\\n\\n/** Initial SHA512 state. Bits 0..64 of frac part of sqrt of primes 2..19 */\\nexport const SHA512_IV: Uint32Array = /* @__PURE__ */ Uint32Array.from([\\n 0x6a09e667, 0xf3bcc908, 0xbb67ae85, 0x84caa73b, 0x3c6ef372, 0xfe94f82b, 0xa54ff53a, 0x5f1d36f1,\\n 0x510e527f, 0xade682d1, 0x9b05688c, 0x2b3e6c1f, 0x1f83d9ab, 0xfb41bd6b, 0x5be0cd19, 0x137e2179,\\n]);\\n\",\"/**\\n * SHA2 hash function. A.k.a. sha256, sha384, sha512, sha512_224, sha512_256.\\n * SHA256 is the fastest hash implementable in JS, even faster than Blake3.\\n * Check out [RFC 4634](https://datatracker.ietf.org/doc/html/rfc4634) and\\n * [FIPS 180-4](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf).\\n * @module\\n */\\nimport { Chi, HashMD, Maj, SHA224_IV, SHA256_IV, SHA384_IV, SHA512_IV } from './_md.ts';\\nimport * as u64 from './_u64.ts';\\nimport { type CHash, clean, createHasher, rotr } from './utils.ts';\\n\\n/**\\n * Round constants:\\n * First 32 bits of fractional parts of the cube roots of the first 64 primes 2..311)\\n */\\n// prettier-ignore\\nconst SHA256_K = /* @__PURE__ */ Uint32Array.from([\\n 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,\\n 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,\\n 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,\\n 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,\\n 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,\\n 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,\\n 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,\\n 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2\\n]);\\n\\n/** Reusable temporary buffer. \\\"W\\\" comes straight from spec. */\\nconst SHA256_W = /* @__PURE__ */ new Uint32Array(64);\\nexport class SHA256 extends HashMD {\\n // We cannot use array here since array allows indexing by variable\\n // which means optimizer/compiler cannot use registers.\\n protected A: number = SHA256_IV[0] | 0;\\n protected B: number = SHA256_IV[1] | 0;\\n protected C: number = SHA256_IV[2] | 0;\\n protected D: number = SHA256_IV[3] | 0;\\n protected E: number = SHA256_IV[4] | 0;\\n protected F: number = SHA256_IV[5] | 0;\\n protected G: number = SHA256_IV[6] | 0;\\n protected H: number = SHA256_IV[7] | 0;\\n\\n constructor(outputLen: number = 32) {\\n super(64, outputLen, 8, false);\\n }\\n protected get(): [number, number, number, number, number, number, number, number] {\\n const { A, B, C, D, E, F, G, H } = this;\\n return [A, B, C, D, E, F, G, H];\\n }\\n // prettier-ignore\\n protected set(\\n A: number, B: number, C: number, D: number, E: number, F: number, G: number, H: number\\n ): void {\\n this.A = A | 0;\\n this.B = B | 0;\\n this.C = C | 0;\\n this.D = D | 0;\\n this.E = E | 0;\\n this.F = F | 0;\\n this.G = G | 0;\\n this.H = H | 0;\\n }\\n protected process(view: DataView, offset: number): void {\\n // Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array\\n for (let i = 0; i < 16; i++, offset += 4) SHA256_W[i] = view.getUint32(offset, false);\\n for (let i = 16; i < 64; i++) {\\n const W15 = SHA256_W[i - 15];\\n const W2 = SHA256_W[i - 2];\\n const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ (W15 >>> 3);\\n const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ (W2 >>> 10);\\n SHA256_W[i] = (s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16]) | 0;\\n }\\n // Compression function main loop, 64 rounds\\n let { A, B, C, D, E, F, G, H } = this;\\n for (let i = 0; i < 64; i++) {\\n const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);\\n const T1 = (H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i]) | 0;\\n const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22);\\n const T2 = (sigma0 + Maj(A, B, C)) | 0;\\n H = G;\\n G = F;\\n F = E;\\n E = (D + T1) | 0;\\n D = C;\\n C = B;\\n B = A;\\n A = (T1 + T2) | 0;\\n }\\n // Add the compressed chunk to the current hash value\\n A = (A + this.A) | 0;\\n B = (B + this.B) | 0;\\n C = (C + this.C) | 0;\\n D = (D + this.D) | 0;\\n E = (E + this.E) | 0;\\n F = (F + this.F) | 0;\\n G = (G + this.G) | 0;\\n H = (H + this.H) | 0;\\n this.set(A, B, C, D, E, F, G, H);\\n }\\n protected roundClean(): void {\\n clean(SHA256_W);\\n }\\n destroy(): void {\\n this.set(0, 0, 0, 0, 0, 0, 0, 0);\\n clean(this.buffer);\\n }\\n}\\n\\nexport class SHA224 extends SHA256 {\\n protected A: number = SHA224_IV[0] | 0;\\n protected B: number = SHA224_IV[1] | 0;\\n protected C: number = SHA224_IV[2] | 0;\\n protected D: number = SHA224_IV[3] | 0;\\n protected E: number = SHA224_IV[4] | 0;\\n protected F: number = SHA224_IV[5] | 0;\\n protected G: number = SHA224_IV[6] | 0;\\n protected H: number = SHA224_IV[7] | 0;\\n constructor() {\\n super(28);\\n }\\n}\\n\\n// SHA2-512 is slower than sha256 in js because u64 operations are slow.\\n\\n// Round contants\\n// First 32 bits of the fractional parts of the cube roots of the first 80 primes 2..409\\n// prettier-ignore\\nconst K512 = /* @__PURE__ */ (() => u64.split([\\n '0x428a2f98d728ae22', '0x7137449123ef65cd', '0xb5c0fbcfec4d3b2f', '0xe9b5dba58189dbbc',\\n '0x3956c25bf348b538', '0x59f111f1b605d019', '0x923f82a4af194f9b', '0xab1c5ed5da6d8118',\\n '0xd807aa98a3030242', '0x12835b0145706fbe', '0x243185be4ee4b28c', '0x550c7dc3d5ffb4e2',\\n '0x72be5d74f27b896f', '0x80deb1fe3b1696b1', '0x9bdc06a725c71235', '0xc19bf174cf692694',\\n '0xe49b69c19ef14ad2', '0xefbe4786384f25e3', '0x0fc19dc68b8cd5b5', '0x240ca1cc77ac9c65',\\n '0x2de92c6f592b0275', '0x4a7484aa6ea6e483', '0x5cb0a9dcbd41fbd4', '0x76f988da831153b5',\\n '0x983e5152ee66dfab', '0xa831c66d2db43210', '0xb00327c898fb213f', '0xbf597fc7beef0ee4',\\n '0xc6e00bf33da88fc2', '0xd5a79147930aa725', '0x06ca6351e003826f', '0x142929670a0e6e70',\\n '0x27b70a8546d22ffc', '0x2e1b21385c26c926', '0x4d2c6dfc5ac42aed', '0x53380d139d95b3df',\\n '0x650a73548baf63de', '0x766a0abb3c77b2a8', '0x81c2c92e47edaee6', '0x92722c851482353b',\\n '0xa2bfe8a14cf10364', '0xa81a664bbc423001', '0xc24b8b70d0f89791', '0xc76c51a30654be30',\\n '0xd192e819d6ef5218', '0xd69906245565a910', '0xf40e35855771202a', '0x106aa07032bbd1b8',\\n '0x19a4c116b8d2d0c8', '0x1e376c085141ab53', '0x2748774cdf8eeb99', '0x34b0bcb5e19b48a8',\\n '0x391c0cb3c5c95a63', '0x4ed8aa4ae3418acb', '0x5b9cca4f7763e373', '0x682e6ff3d6b2b8a3',\\n '0x748f82ee5defb2fc', '0x78a5636f43172f60', '0x84c87814a1f0ab72', '0x8cc702081a6439ec',\\n '0x90befffa23631e28', '0xa4506cebde82bde9', '0xbef9a3f7b2c67915', '0xc67178f2e372532b',\\n '0xca273eceea26619c', '0xd186b8c721c0c207', '0xeada7dd6cde0eb1e', '0xf57d4f7fee6ed178',\\n '0x06f067aa72176fba', '0x0a637dc5a2c898a6', '0x113f9804bef90dae', '0x1b710b35131c471b',\\n '0x28db77f523047d84', '0x32caab7b40c72493', '0x3c9ebe0a15c9bebc', '0x431d67c49c100d4c',\\n '0x4cc5d4becb3e42b6', '0x597f299cfc657e2a', '0x5fcb6fab3ad6faec', '0x6c44198c4a475817'\\n].map(n => BigInt(n))))();\\nconst SHA512_Kh = /* @__PURE__ */ (() => K512[0])();\\nconst SHA512_Kl = /* @__PURE__ */ (() => K512[1])();\\n\\n// Reusable temporary buffers\\nconst SHA512_W_H = /* @__PURE__ */ new Uint32Array(80);\\nconst SHA512_W_L = /* @__PURE__ */ new Uint32Array(80);\\n\\nexport class SHA512 extends HashMD {\\n // We cannot use array here since array allows indexing by variable\\n // which means optimizer/compiler cannot use registers.\\n // h -- high 32 bits, l -- low 32 bits\\n protected Ah: number = SHA512_IV[0] | 0;\\n protected Al: number = SHA512_IV[1] | 0;\\n protected Bh: number = SHA512_IV[2] | 0;\\n protected Bl: number = SHA512_IV[3] | 0;\\n protected Ch: number = SHA512_IV[4] | 0;\\n protected Cl: number = SHA512_IV[5] | 0;\\n protected Dh: number = SHA512_IV[6] | 0;\\n protected Dl: number = SHA512_IV[7] | 0;\\n protected Eh: number = SHA512_IV[8] | 0;\\n protected El: number = SHA512_IV[9] | 0;\\n protected Fh: number = SHA512_IV[10] | 0;\\n protected Fl: number = SHA512_IV[11] | 0;\\n protected Gh: number = SHA512_IV[12] | 0;\\n protected Gl: number = SHA512_IV[13] | 0;\\n protected Hh: number = SHA512_IV[14] | 0;\\n protected Hl: number = SHA512_IV[15] | 0;\\n\\n constructor(outputLen: number = 64) {\\n super(128, outputLen, 16, false);\\n }\\n // prettier-ignore\\n protected get(): [\\n number, number, number, number, number, number, number, number,\\n number, number, number, number, number, number, number, number\\n ] {\\n const { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this;\\n return [Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl];\\n }\\n // prettier-ignore\\n protected set(\\n Ah: number, Al: number, Bh: number, Bl: number, Ch: number, Cl: number, Dh: number, Dl: number,\\n Eh: number, El: number, Fh: number, Fl: number, Gh: number, Gl: number, Hh: number, Hl: number\\n ): void {\\n this.Ah = Ah | 0;\\n this.Al = Al | 0;\\n this.Bh = Bh | 0;\\n this.Bl = Bl | 0;\\n this.Ch = Ch | 0;\\n this.Cl = Cl | 0;\\n this.Dh = Dh | 0;\\n this.Dl = Dl | 0;\\n this.Eh = Eh | 0;\\n this.El = El | 0;\\n this.Fh = Fh | 0;\\n this.Fl = Fl | 0;\\n this.Gh = Gh | 0;\\n this.Gl = Gl | 0;\\n this.Hh = Hh | 0;\\n this.Hl = Hl | 0;\\n }\\n protected process(view: DataView, offset: number): void {\\n // Extend the first 16 words into the remaining 64 words w[16..79] of the message schedule array\\n for (let i = 0; i < 16; i++, offset += 4) {\\n SHA512_W_H[i] = view.getUint32(offset);\\n SHA512_W_L[i] = view.getUint32((offset += 4));\\n }\\n for (let i = 16; i < 80; i++) {\\n // s0 := (w[i-15] rightrotate 1) xor (w[i-15] rightrotate 8) xor (w[i-15] rightshift 7)\\n const W15h = SHA512_W_H[i - 15] | 0;\\n const W15l = SHA512_W_L[i - 15] | 0;\\n const s0h = u64.rotrSH(W15h, W15l, 1) ^ u64.rotrSH(W15h, W15l, 8) ^ u64.shrSH(W15h, W15l, 7);\\n const s0l = u64.rotrSL(W15h, W15l, 1) ^ u64.rotrSL(W15h, W15l, 8) ^ u64.shrSL(W15h, W15l, 7);\\n // s1 := (w[i-2] rightrotate 19) xor (w[i-2] rightrotate 61) xor (w[i-2] rightshift 6)\\n const W2h = SHA512_W_H[i - 2] | 0;\\n const W2l = SHA512_W_L[i - 2] | 0;\\n const s1h = u64.rotrSH(W2h, W2l, 19) ^ u64.rotrBH(W2h, W2l, 61) ^ u64.shrSH(W2h, W2l, 6);\\n const s1l = u64.rotrSL(W2h, W2l, 19) ^ u64.rotrBL(W2h, W2l, 61) ^ u64.shrSL(W2h, W2l, 6);\\n // SHA256_W[i] = s0 + s1 + SHA256_W[i - 7] + SHA256_W[i - 16];\\n const SUMl = u64.add4L(s0l, s1l, SHA512_W_L[i - 7], SHA512_W_L[i - 16]);\\n const SUMh = u64.add4H(SUMl, s0h, s1h, SHA512_W_H[i - 7], SHA512_W_H[i - 16]);\\n SHA512_W_H[i] = SUMh | 0;\\n SHA512_W_L[i] = SUMl | 0;\\n }\\n let { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this;\\n // Compression function main loop, 80 rounds\\n for (let i = 0; i < 80; i++) {\\n // S1 := (e rightrotate 14) xor (e rightrotate 18) xor (e rightrotate 41)\\n const sigma1h = u64.rotrSH(Eh, El, 14) ^ u64.rotrSH(Eh, El, 18) ^ u64.rotrBH(Eh, El, 41);\\n const sigma1l = u64.rotrSL(Eh, El, 14) ^ u64.rotrSL(Eh, El, 18) ^ u64.rotrBL(Eh, El, 41);\\n //const T1 = (H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i]) | 0;\\n const CHIh = (Eh & Fh) ^ (~Eh & Gh);\\n const CHIl = (El & Fl) ^ (~El & Gl);\\n // T1 = H + sigma1 + Chi(E, F, G) + SHA512_K[i] + SHA512_W[i]\\n // prettier-ignore\\n const T1ll = u64.add5L(Hl, sigma1l, CHIl, SHA512_Kl[i], SHA512_W_L[i]);\\n const T1h = u64.add5H(T1ll, Hh, sigma1h, CHIh, SHA512_Kh[i], SHA512_W_H[i]);\\n const T1l = T1ll | 0;\\n // S0 := (a rightrotate 28) xor (a rightrotate 34) xor (a rightrotate 39)\\n const sigma0h = u64.rotrSH(Ah, Al, 28) ^ u64.rotrBH(Ah, Al, 34) ^ u64.rotrBH(Ah, Al, 39);\\n const sigma0l = u64.rotrSL(Ah, Al, 28) ^ u64.rotrBL(Ah, Al, 34) ^ u64.rotrBL(Ah, Al, 39);\\n const MAJh = (Ah & Bh) ^ (Ah & Ch) ^ (Bh & Ch);\\n const MAJl = (Al & Bl) ^ (Al & Cl) ^ (Bl & Cl);\\n Hh = Gh | 0;\\n Hl = Gl | 0;\\n Gh = Fh | 0;\\n Gl = Fl | 0;\\n Fh = Eh | 0;\\n Fl = El | 0;\\n ({ h: Eh, l: El } = u64.add(Dh | 0, Dl | 0, T1h | 0, T1l | 0));\\n Dh = Ch | 0;\\n Dl = Cl | 0;\\n Ch = Bh | 0;\\n Cl = Bl | 0;\\n Bh = Ah | 0;\\n Bl = Al | 0;\\n const All = u64.add3L(T1l, sigma0l, MAJl);\\n Ah = u64.add3H(All, T1h, sigma0h, MAJh);\\n Al = All | 0;\\n }\\n // Add the compressed chunk to the current hash value\\n ({ h: Ah, l: Al } = u64.add(this.Ah | 0, this.Al | 0, Ah | 0, Al | 0));\\n ({ h: Bh, l: Bl } = u64.add(this.Bh | 0, this.Bl | 0, Bh | 0, Bl | 0));\\n ({ h: Ch, l: Cl } = u64.add(this.Ch | 0, this.Cl | 0, Ch | 0, Cl | 0));\\n ({ h: Dh, l: Dl } = u64.add(this.Dh | 0, this.Dl | 0, Dh | 0, Dl | 0));\\n ({ h: Eh, l: El } = u64.add(this.Eh | 0, this.El | 0, Eh | 0, El | 0));\\n ({ h: Fh, l: Fl } = u64.add(this.Fh | 0, this.Fl | 0, Fh | 0, Fl | 0));\\n ({ h: Gh, l: Gl } = u64.add(this.Gh | 0, this.Gl | 0, Gh | 0, Gl | 0));\\n ({ h: Hh, l: Hl } = u64.add(this.Hh | 0, this.Hl | 0, Hh | 0, Hl | 0));\\n this.set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl);\\n }\\n protected roundClean(): void {\\n clean(SHA512_W_H, SHA512_W_L);\\n }\\n destroy(): void {\\n clean(this.buffer);\\n this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\\n }\\n}\\n\\nexport class SHA384 extends SHA512 {\\n protected Ah: number = SHA384_IV[0] | 0;\\n protected Al: number = SHA384_IV[1] | 0;\\n protected Bh: number = SHA384_IV[2] | 0;\\n protected Bl: number = SHA384_IV[3] | 0;\\n protected Ch: number = SHA384_IV[4] | 0;\\n protected Cl: number = SHA384_IV[5] | 0;\\n protected Dh: number = SHA384_IV[6] | 0;\\n protected Dl: number = SHA384_IV[7] | 0;\\n protected Eh: number = SHA384_IV[8] | 0;\\n protected El: number = SHA384_IV[9] | 0;\\n protected Fh: number = SHA384_IV[10] | 0;\\n protected Fl: number = SHA384_IV[11] | 0;\\n protected Gh: number = SHA384_IV[12] | 0;\\n protected Gl: number = SHA384_IV[13] | 0;\\n protected Hh: number = SHA384_IV[14] | 0;\\n protected Hl: number = SHA384_IV[15] | 0;\\n\\n constructor() {\\n super(48);\\n }\\n}\\n\\n/**\\n * Truncated SHA512/256 and SHA512/224.\\n * SHA512_IV is XORed with 0xa5a5a5a5a5a5a5a5, then used as \\\"intermediary\\\" IV of SHA512/t.\\n * Then t hashes string to produce result IV.\\n * See `test/misc/sha2-gen-iv.js`.\\n */\\n\\n/** SHA512/224 IV */\\nconst T224_IV = /* @__PURE__ */ Uint32Array.from([\\n 0x8c3d37c8, 0x19544da2, 0x73e19966, 0x89dcd4d6, 0x1dfab7ae, 0x32ff9c82, 0x679dd514, 0x582f9fcf,\\n 0x0f6d2b69, 0x7bd44da8, 0x77e36f73, 0x04c48942, 0x3f9d85a8, 0x6a1d36c8, 0x1112e6ad, 0x91d692a1,\\n]);\\n\\n/** SHA512/256 IV */\\nconst T256_IV = /* @__PURE__ */ Uint32Array.from([\\n 0x22312194, 0xfc2bf72c, 0x9f555fa3, 0xc84c64c2, 0x2393b86b, 0x6f53b151, 0x96387719, 0x5940eabd,\\n 0x96283ee2, 0xa88effe3, 0xbe5e1e25, 0x53863992, 0x2b0199fc, 0x2c85b8aa, 0x0eb72ddc, 0x81c52ca2,\\n]);\\n\\nexport class SHA512_224 extends SHA512 {\\n protected Ah: number = T224_IV[0] | 0;\\n protected Al: number = T224_IV[1] | 0;\\n protected Bh: number = T224_IV[2] | 0;\\n protected Bl: number = T224_IV[3] | 0;\\n protected Ch: number = T224_IV[4] | 0;\\n protected Cl: number = T224_IV[5] | 0;\\n protected Dh: number = T224_IV[6] | 0;\\n protected Dl: number = T224_IV[7] | 0;\\n protected Eh: number = T224_IV[8] | 0;\\n protected El: number = T224_IV[9] | 0;\\n protected Fh: number = T224_IV[10] | 0;\\n protected Fl: number = T224_IV[11] | 0;\\n protected Gh: number = T224_IV[12] | 0;\\n protected Gl: number = T224_IV[13] | 0;\\n protected Hh: number = T224_IV[14] | 0;\\n protected Hl: number = T224_IV[15] | 0;\\n\\n constructor() {\\n super(28);\\n }\\n}\\n\\nexport class SHA512_256 extends SHA512 {\\n protected Ah: number = T256_IV[0] | 0;\\n protected Al: number = T256_IV[1] | 0;\\n protected Bh: number = T256_IV[2] | 0;\\n protected Bl: number = T256_IV[3] | 0;\\n protected Ch: number = T256_IV[4] | 0;\\n protected Cl: number = T256_IV[5] | 0;\\n protected Dh: number = T256_IV[6] | 0;\\n protected Dl: number = T256_IV[7] | 0;\\n protected Eh: number = T256_IV[8] | 0;\\n protected El: number = T256_IV[9] | 0;\\n protected Fh: number = T256_IV[10] | 0;\\n protected Fl: number = T256_IV[11] | 0;\\n protected Gh: number = T256_IV[12] | 0;\\n protected Gl: number = T256_IV[13] | 0;\\n protected Hh: number = T256_IV[14] | 0;\\n protected Hl: number = T256_IV[15] | 0;\\n\\n constructor() {\\n super(32);\\n }\\n}\\n\\n/**\\n * SHA2-256 hash function from RFC 4634.\\n *\\n * It is the fastest JS hash, even faster than Blake3.\\n * To break sha256 using birthday attack, attackers need to try 2^128 hashes.\\n * BTC network is doing 2^70 hashes/sec (2^95 hashes/year) as per 2025.\\n */\\nexport const sha256: CHash = /* @__PURE__ */ createHasher(() => new SHA256());\\n/** SHA2-224 hash function from RFC 4634 */\\nexport const sha224: CHash = /* @__PURE__ */ createHasher(() => new SHA224());\\n\\n/** SHA2-512 hash function from RFC 4634. */\\nexport const sha512: CHash = /* @__PURE__ */ createHasher(() => new SHA512());\\n/** SHA2-384 hash function from RFC 4634. */\\nexport const sha384: CHash = /* @__PURE__ */ createHasher(() => new SHA384());\\n\\n/**\\n * SHA2-512/256 \\\"truncated\\\" hash function, with improved resistance to length extension attacks.\\n * See the paper on [truncated SHA512](https://eprint.iacr.org/2010/548.pdf).\\n */\\nexport const sha512_256: CHash = /* @__PURE__ */ createHasher(() => new SHA512_256());\\n/**\\n * SHA2-512/224 \\\"truncated\\\" hash function, with improved resistance to length extension attacks.\\n * See the paper on [truncated SHA512](https://eprint.iacr.org/2010/548.pdf).\\n */\\nexport const sha512_224: CHash = /* @__PURE__ */ createHasher(() => new SHA512_224());\\n\",\"/**\\n * SHA2-256 a.k.a. sha256. In JS, it is the fastest hash, even faster than Blake3.\\n *\\n * To break sha256 using birthday attack, attackers need to try 2^128 hashes.\\n * BTC network is doing 2^70 hashes/sec (2^95 hashes/year) as per 2025.\\n *\\n * Check out [FIPS 180-4](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf).\\n * @module\\n * @deprecated\\n */\\nimport {\\n SHA224 as SHA224n,\\n sha224 as sha224n,\\n SHA256 as SHA256n,\\n sha256 as sha256n,\\n} from './sha2.ts';\\n/** @deprecated Use import from `noble/hashes/sha2` module */\\nexport const SHA256: typeof SHA256n = SHA256n;\\n/** @deprecated Use import from `noble/hashes/sha2` module */\\nexport const sha256: typeof sha256n = sha256n;\\n/** @deprecated Use import from `noble/hashes/sha2` module */\\nexport const SHA224: typeof SHA224n = SHA224n;\\n/** @deprecated Use import from `noble/hashes/sha2` module */\\nexport const sha224: typeof sha224n = sha224n;\\n\",\"import { sha256 } from '@noble/hashes/sha256';\\nimport { bytesToHex } from '@noble/hashes/utils';\\n\\nconst digest = sha256(\\n Uint8Array.from([\\n 98, 108, 117, 101, 45, 113, 117, 105, 99, 107, 106, 115, 45, 98, 105, 110,\\n 97, 114, 121, 45, 102, 105, 120, 116, 117, 114, 101,\\n ]),\\n);\\n\\nexport default {\\n hex: bytesToHex(digest),\\n length: digest.length,\\n first: digest[0],\\n last: digest[digest.length - 1],\\n};\\n\"],\"version\":3}", + "originMeta": { + "originalPath": "node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/_md.js", + "packageName": "@noble/hashes", + "packageVersion": "1.8.0", + "integrity": "483aad47a5ae3669a320d313a6ce1be9be705b5c52775cba1b4f45d1fada0562" + } + } + ], + "builderVersion": "deterministic-builder-v1", + "dependencyIntegrity": "483aad47a5ae3669a320d313a6ce1be9be705b5c52775cba1b4f45d1fada0562", + "diagnosticsMeta": { + "entryPath": "/workspace/libs/test-harness/fixtures/library-reuse/binary-sha256-entry.ts", + "modulePaths": [ + "./binary-sha256-entry.js" + ] + }, + "graphHash": "ffab4b727f608149e30ca86a1fb421eb9b44ef62b3136b5aca6057fbd034af12" + } + } + }, + "manifest": { + "abi_id": "Host.v2", + "abi_version": 2, + "functions": [ + { + "fn_id": 1, + "js_path": [ + "document", + "get" + ], + "effect": "READ", + "arity": 1, + "arg_schema": [ + { + "type": "string" + } + ], + "return_schema": { + "type": "dv" + }, + "gas": { + "schedule_id": "doc-read-v1", + "base": 20, + "k_arg_bytes": 1, + "k_ret_bytes": 1, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 4096, + "max_response_bytes": 262144, + "max_units": 1000, + "arg_utf8_max": [ + 2048 + ] + }, + "error_codes": [ + { + "code": "INVALID_PATH", + "tag": "host/invalid_path" + }, + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + }, + { + "code": "NOT_FOUND", + "tag": "host/not_found" + } + ] + }, + { + "fn_id": 2, + "js_path": [ + "document", + "getCanonical" + ], + "effect": "READ", + "arity": 1, + "arg_schema": [ + { + "type": "string" + } + ], + "return_schema": { + "type": "dv" + }, + "gas": { + "schedule_id": "doc-read-v1", + "base": 20, + "k_arg_bytes": 1, + "k_ret_bytes": 1, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 4096, + "max_response_bytes": 262144, + "max_units": 1000, + "arg_utf8_max": [ + 2048 + ] + }, + "error_codes": [ + { + "code": "INVALID_PATH", + "tag": "host/invalid_path" + }, + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + }, + { + "code": "NOT_FOUND", + "tag": "host/not_found" + } + ] + }, + { + "fn_id": 3, + "js_path": [ + "emit" + ], + "effect": "EMIT", + "arity": 1, + "arg_schema": [ + { + "type": "dv" + } + ], + "return_schema": { + "type": "null" + }, + "gas": { + "schedule_id": "emit-v1", + "base": 5, + "k_arg_bytes": 1, + "k_ret_bytes": 0, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 32768, + "max_response_bytes": 64, + "max_units": 1024 + }, + "error_codes": [ + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + } + ] + } + ] + } + }, + { + "id": "flagship-knowledge-pack", + "title": "Flagship knowledge/compliance pack processor", + "kind": "flagship", + "badge": "Flagship workload", + "description": "A browsable flagship deterministic workload that mixes static imports, Promise jobs, text and binary host data, and certification-ready evidence.", + "certified": true, + "executionProfile": "compat-binary-v1", + "sourceKind": "module-pack", + "abiId": "Host.v2", + "gasLimit": "8000000", + "sourcePaths": [ + "apps/ecosystem-certifier/fixtures/flagship/knowledge-pack-entry.ts" + ], + "sourceText": "import { toByteArray, fromByteArray } from 'base64-js';\nimport { inflateSync } from 'fflate';\nimport deepEqual from 'fast-deep-equal';\nimport stableStringify from 'fast-json-stable-stringify';\nimport he from 'he';\nimport jsonLogic from 'json-logic-js';\nimport LinkifyIt from 'linkify-it';\nimport MarkdownIt from 'markdown-it';\nimport { sha256 } from '@noble/hashes/sha256';\nimport { bytesToHex } from '@noble/hashes/utils';\nimport { match as pathMatch } from 'path-to-regexp';\nimport semver from 'semver';\nimport TinyQueue from 'tinyqueue';\nimport CRC32 from 'crc-32';\n\nlet summary;\ntry {\n const metadataText = Host.v2.document.get('pack/metadata.json');\n const ruleText = Host.v2.document.get('rules/findings.json');\n const compressedAttachment = Host.v2.document.get('pack/attachment.deflated');\n const payload = Host.v2.document.get('bytes/payload');\n const extraPayload = Host.v2.document.get('bytes/flagship-extra');\n\n const metadata = JSON.parse(metadataText);\n const docPaths = metadata.links ?? ['docs/a.md', 'docs/b.md'];\n const docs = docPaths.map((docPath) => ({\n docPath,\n text: Host.v2.document.get(docPath),\n }));\n const markdown = new MarkdownIt({ linkify: true });\n const linkify = new LinkifyIt();\n const markdownSource = docs.map((doc) => doc.text).join('\\n');\n const markdownTokens = markdown.parse(markdownSource, {});\n const linkMatches = docs\n .flatMap((doc) => linkify.match(doc.text) ?? [])\n .map((item) => item.url);\n\n const releaseChecks = (metadata.requires ?? []).map((range) =>\n semver.satisfies(metadata.release, range),\n );\n const rules = JSON.parse(ruleText);\n const findingInput = {\n linkCount: linkMatches.length,\n releaseOk: releaseChecks.every(Boolean),\n };\n const ruleInputStable = deepEqual(\n findingInput,\n JSON.parse(stableStringify(findingInput)),\n );\n const rulePasses = Boolean(jsonLogic.apply(rules, findingInput));\n\n const queue = new TinyQueue(\n [],\n (left, right) => left.priority - right.priority,\n );\n for (const link of linkMatches) {\n queue.push({ link, priority: link.length });\n }\n const orderedLinks = [];\n while (queue.length > 0) {\n orderedLinks.push(queue.pop().link);\n }\n\n const decompressed = inflateSync(compressedAttachment);\n const attachmentRoundTrip = toByteArray(fromByteArray(decompressed));\n const mergedBinary = new Uint8Array(\n attachmentRoundTrip.length + payload.length + extraPayload.length,\n );\n mergedBinary.set(attachmentRoundTrip, 0);\n mergedBinary.set(payload, attachmentRoundTrip.length);\n mergedBinary.set(extraPayload, attachmentRoundTrip.length + payload.length);\n const digestHex = bytesToHex(sha256(mergedBinary));\n const crc32 = (CRC32.buf(mergedBinary) >>> 0).toString(16).padStart(8, '0');\n\n const decodedEntities = he.decode('<b>safe</b>');\n const versionCapture = pathMatch('/document/:id/version/:version')(\n '/document/42/version/1.2.3',\n );\n const orderedFindings = [\n { id: 'links', value: linkMatches.length },\n { id: 'rules', value: Number(rulePasses) },\n { id: 'tokens', value: markdownTokens.length },\n ].sort((left, right) => left.id.localeCompare(right.id));\n\n Promise.resolve('scheduled').then(() => undefined);\n queueMicrotask(() => undefined);\n\n for (const doc of docs) {\n Host.v2.emit({\n type: 'knowledge-pack-doc',\n docPath: doc.docPath,\n length: doc.text.length,\n });\n }\n\n summary = {\n status: 'ok',\n packId: metadata.packId,\n release: metadata.release,\n checks: releaseChecks,\n docTokenCount: markdownTokens.length,\n linkCount: linkMatches.length,\n uniqueLinks: [...new Set(orderedLinks)],\n binary: {\n byteLength: mergedBinary.length,\n digestHex,\n crc32,\n },\n decodedEntities,\n versionCapture,\n findings: orderedFindings,\n ruleInputStable,\n rulePasses,\n };\n} catch (error) {\n summary = {\n status: 'error',\n message: String(error instanceof Error ? error.message : error),\n };\n}\n\nHost.v2.emit({\n type: 'knowledge-pack-summary',\n summaryHash: bytesToHex(\n sha256(\n toByteArray(\n fromByteArray(\n new Uint8Array([\n ...Host.v2.document.get('bytes/payload'),\n ...Host.v2.document.get('bytes/flagship-extra'),\n ]),\n ),\n ),\n ),\n ),\n status: summary.status,\n});\n\nexport default summary;\n", + "hostPreset": "certification", + "hostSummary": { + "label": "Certification host", + "description": "Provides the ecosystem-certifier text and binary documents used for workload certification.", + "documents": [ + "pack/metadata.json", + "pack/metadata.yaml", + "docs/a.md", + "docs/b.md", + "docs/c.md", + "docs/d.md", + "bytes/payload", + "bytes/flagship-extra", + "pack/attachment.deflated" + ] + }, + "docsLinks": [ + { + "label": "Workload certification", + "href": "/docs/workload-certification.md" + }, + { + "label": "Compatibility report", + "href": "/docs/ecosystem-compatibility-report.md" + }, + { + "label": "Architecture overview", + "href": "/docs/architecture-overview.md" + } + ], + "supportsOogSearch": false, + "program": { + "version": 2, + "abiId": "Host.v2", + "abiVersion": 2, + "abiManifestHash": "ec5c3df99a1b0ab84b692996193707ae6c931382e75c96c7c14b4f8baaae5af2", + "engineBuildHash": "f91091cb7feb788df340305a877a9cadb0c6f4d13aea8a7da4040b6367d178ea", + "gasVersion": 8, + "executionProfile": "compat-binary-v1", + "sourceKind": "module-pack", + "source": { + "modulePack": { + "version": 1, + "entrySpecifier": "./knowledge-pack-entry.js", + "entryExport": "default", + "modules": [ + { + "specifier": "./knowledge-pack-entry.js", + "source": "var __create = Object.create;\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __getProtoOf = Object.getPrototypeOf;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __commonJS = (cb, mod) => function __require() {\n return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;\n};\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(\n // If the importer is in node compatibility mode or this is not an ESM\n // file that has been converted to a CommonJS file using a Babel-\n // compatible transform (i.e. \"__esModule\" has not been set), then set\n // \"default\" to the CommonJS \"module.exports\" for node compatibility.\n isNodeMode || !mod || !mod.__esModule ? __defProp(target, \"default\", { value: mod, enumerable: true }) : target,\n mod\n));\n\n// node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.js\nvar require_base64_js = __commonJS({\n \"node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.js\"(exports) {\n \"use strict\";\n exports.byteLength = byteLength;\n exports.toByteArray = toByteArray2;\n exports.fromByteArray = fromByteArray2;\n var lookup = [];\n var revLookup = [];\n var Arr = typeof Uint8Array !== \"undefined\" ? Uint8Array : Array;\n var code2 = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n for (i = 0, len = code2.length; i < len; ++i) {\n lookup[i] = code2[i];\n revLookup[code2.charCodeAt(i)] = i;\n }\n var i;\n var len;\n revLookup[\"-\".charCodeAt(0)] = 62;\n revLookup[\"_\".charCodeAt(0)] = 63;\n function getLens(b64) {\n var len2 = b64.length;\n if (len2 % 4 > 0) {\n throw new Error(\"Invalid string. Length must be a multiple of 4\");\n }\n var validLen = b64.indexOf(\"=\");\n if (validLen === -1) validLen = len2;\n var placeHoldersLen = validLen === len2 ? 0 : 4 - validLen % 4;\n return [validLen, placeHoldersLen];\n }\n function byteLength(b64) {\n var lens = getLens(b64);\n var validLen = lens[0];\n var placeHoldersLen = lens[1];\n return (validLen + placeHoldersLen) * 3 / 4 - placeHoldersLen;\n }\n function _byteLength(b64, validLen, placeHoldersLen) {\n return (validLen + placeHoldersLen) * 3 / 4 - placeHoldersLen;\n }\n function toByteArray2(b64) {\n var tmp;\n var lens = getLens(b64);\n var validLen = lens[0];\n var placeHoldersLen = lens[1];\n var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen));\n var curByte = 0;\n var len2 = placeHoldersLen > 0 ? validLen - 4 : validLen;\n var i2;\n for (i2 = 0; i2 < len2; i2 += 4) {\n tmp = revLookup[b64.charCodeAt(i2)] << 18 | revLookup[b64.charCodeAt(i2 + 1)] << 12 | revLookup[b64.charCodeAt(i2 + 2)] << 6 | revLookup[b64.charCodeAt(i2 + 3)];\n arr[curByte++] = tmp >> 16 & 255;\n arr[curByte++] = tmp >> 8 & 255;\n arr[curByte++] = tmp & 255;\n }\n if (placeHoldersLen === 2) {\n tmp = revLookup[b64.charCodeAt(i2)] << 2 | revLookup[b64.charCodeAt(i2 + 1)] >> 4;\n arr[curByte++] = tmp & 255;\n }\n if (placeHoldersLen === 1) {\n tmp = revLookup[b64.charCodeAt(i2)] << 10 | revLookup[b64.charCodeAt(i2 + 1)] << 4 | revLookup[b64.charCodeAt(i2 + 2)] >> 2;\n arr[curByte++] = tmp >> 8 & 255;\n arr[curByte++] = tmp & 255;\n }\n return arr;\n }\n function tripletToBase64(num) {\n return lookup[num >> 18 & 63] + lookup[num >> 12 & 63] + lookup[num >> 6 & 63] + lookup[num & 63];\n }\n function encodeChunk(uint8, start, end) {\n var tmp;\n var output = [];\n for (var i2 = start; i2 < end; i2 += 3) {\n tmp = (uint8[i2] << 16 & 16711680) + (uint8[i2 + 1] << 8 & 65280) + (uint8[i2 + 2] & 255);\n output.push(tripletToBase64(tmp));\n }\n return output.join(\"\");\n }\n function fromByteArray2(uint8) {\n var tmp;\n var len2 = uint8.length;\n var extraBytes = len2 % 3;\n var parts = [];\n var maxChunkLength = 16383;\n for (var i2 = 0, len22 = len2 - extraBytes; i2 < len22; i2 += maxChunkLength) {\n parts.push(encodeChunk(uint8, i2, i2 + maxChunkLength > len22 ? len22 : i2 + maxChunkLength));\n }\n if (extraBytes === 1) {\n tmp = uint8[len2 - 1];\n parts.push(\n lookup[tmp >> 2] + lookup[tmp << 4 & 63] + \"==\"\n );\n } else if (extraBytes === 2) {\n tmp = (uint8[len2 - 2] << 8) + uint8[len2 - 1];\n parts.push(\n lookup[tmp >> 10] + lookup[tmp >> 4 & 63] + lookup[tmp << 2 & 63] + \"=\"\n );\n }\n return parts.join(\"\");\n }\n }\n});\n\n// node_modules/.pnpm/fast-deep-equal@3.1.3/node_modules/fast-deep-equal/index.js\nvar require_fast_deep_equal = __commonJS({\n \"node_modules/.pnpm/fast-deep-equal@3.1.3/node_modules/fast-deep-equal/index.js\"(exports, module) {\n \"use strict\";\n module.exports = function equal(a, b) {\n if (a === b) return true;\n if (a && b && typeof a == \"object\" && typeof b == \"object\") {\n if (a.constructor !== b.constructor) return false;\n var length, i, keys;\n if (Array.isArray(a)) {\n length = a.length;\n if (length != b.length) return false;\n for (i = length; i-- !== 0; )\n if (!equal(a[i], b[i])) return false;\n return true;\n }\n if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;\n if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();\n if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();\n keys = Object.keys(a);\n length = keys.length;\n if (length !== Object.keys(b).length) return false;\n for (i = length; i-- !== 0; )\n if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;\n for (i = length; i-- !== 0; ) {\n var key = keys[i];\n if (!equal(a[key], b[key])) return false;\n }\n return true;\n }\n return a !== a && b !== b;\n };\n }\n});\n\n// node_modules/.pnpm/fast-json-stable-stringify@2.1.0/node_modules/fast-json-stable-stringify/index.js\nvar require_fast_json_stable_stringify = __commonJS({\n \"node_modules/.pnpm/fast-json-stable-stringify@2.1.0/node_modules/fast-json-stable-stringify/index.js\"(exports, module) {\n \"use strict\";\n module.exports = function(data, opts) {\n if (!opts) opts = {};\n if (typeof opts === \"function\") opts = { cmp: opts };\n var cycles = typeof opts.cycles === \"boolean\" ? opts.cycles : false;\n var cmp = opts.cmp && /* @__PURE__ */ (function(f) {\n return function(node) {\n return function(a, b) {\n var aobj = { key: a, value: node[a] };\n var bobj = { key: b, value: node[b] };\n return f(aobj, bobj);\n };\n };\n })(opts.cmp);\n var seen = [];\n return (function stringify(node) {\n if (node && node.toJSON && typeof node.toJSON === \"function\") {\n node = node.toJSON();\n }\n if (node === void 0) return;\n if (typeof node == \"number\") return isFinite(node) ? \"\" + node : \"null\";\n if (typeof node !== \"object\") return JSON.stringify(node);\n var i, out;\n if (Array.isArray(node)) {\n out = \"[\";\n for (i = 0; i < node.length; i++) {\n if (i) out += \",\";\n out += stringify(node[i]) || \"null\";\n }\n return out + \"]\";\n }\n if (node === null) return \"null\";\n if (seen.indexOf(node) !== -1) {\n if (cycles) return JSON.stringify(\"__cycle__\");\n throw new TypeError(\"Converting circular structure to JSON\");\n }\n var seenIndex = seen.push(node) - 1;\n var keys = Object.keys(node).sort(cmp && cmp(node));\n out = \"\";\n for (i = 0; i < keys.length; i++) {\n var key = keys[i];\n var value = stringify(node[key]);\n if (!value) continue;\n if (out) out += \",\";\n out += JSON.stringify(key) + \":\" + value;\n }\n seen.splice(seenIndex, 1);\n return \"{\" + out + \"}\";\n })(data);\n };\n }\n});\n\n// node_modules/.pnpm/he@1.2.0/node_modules/he/he.js\nvar require_he = __commonJS({\n \"node_modules/.pnpm/he@1.2.0/node_modules/he/he.js\"(exports, module) {\n (function(root) {\n var freeExports = typeof exports == \"object\" && exports;\n var freeModule = typeof module == \"object\" && module && module.exports == freeExports && module;\n var freeGlobal = typeof global == \"object\" && global;\n if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {\n root = freeGlobal;\n }\n var regexAstralSymbols = /[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]/g;\n var regexAsciiWhitelist = /[\\x01-\\x7F]/g;\n var regexBmpWhitelist = /[\\x01-\\t\\x0B\\f\\x0E-\\x1F\\x7F\\x81\\x8D\\x8F\\x90\\x9D\\xA0-\\uFFFF]/g;\n var regexEncodeNonAscii = /<\\u20D2|=\\u20E5|>\\u20D2|\\u205F\\u200A|\\u219D\\u0338|\\u2202\\u0338|\\u2220\\u20D2|\\u2229\\uFE00|\\u222A\\uFE00|\\u223C\\u20D2|\\u223D\\u0331|\\u223E\\u0333|\\u2242\\u0338|\\u224B\\u0338|\\u224D\\u20D2|\\u224E\\u0338|\\u224F\\u0338|\\u2250\\u0338|\\u2261\\u20E5|\\u2264\\u20D2|\\u2265\\u20D2|\\u2266\\u0338|\\u2267\\u0338|\\u2268\\uFE00|\\u2269\\uFE00|\\u226A\\u0338|\\u226A\\u20D2|\\u226B\\u0338|\\u226B\\u20D2|\\u227F\\u0338|\\u2282\\u20D2|\\u2283\\u20D2|\\u228A\\uFE00|\\u228B\\uFE00|\\u228F\\u0338|\\u2290\\u0338|\\u2293\\uFE00|\\u2294\\uFE00|\\u22B4\\u20D2|\\u22B5\\u20D2|\\u22D8\\u0338|\\u22D9\\u0338|\\u22DA\\uFE00|\\u22DB\\uFE00|\\u22F5\\u0338|\\u22F9\\u0338|\\u2933\\u0338|\\u29CF\\u0338|\\u29D0\\u0338|\\u2A6D\\u0338|\\u2A70\\u0338|\\u2A7D\\u0338|\\u2A7E\\u0338|\\u2AA1\\u0338|\\u2AA2\\u0338|\\u2AAC\\uFE00|\\u2AAD\\uFE00|\\u2AAF\\u0338|\\u2AB0\\u0338|\\u2AC5\\u0338|\\u2AC6\\u0338|\\u2ACB\\uFE00|\\u2ACC\\uFE00|\\u2AFD\\u20E5|[\\xA0-\\u0113\\u0116-\\u0122\\u0124-\\u012B\\u012E-\\u014D\\u0150-\\u017E\\u0192\\u01B5\\u01F5\\u0237\\u02C6\\u02C7\\u02D8-\\u02DD\\u0311\\u0391-\\u03A1\\u03A3-\\u03A9\\u03B1-\\u03C9\\u03D1\\u03D2\\u03D5\\u03D6\\u03DC\\u03DD\\u03F0\\u03F1\\u03F5\\u03F6\\u0401-\\u040C\\u040E-\\u044F\\u0451-\\u045C\\u045E\\u045F\\u2002-\\u2005\\u2007-\\u2010\\u2013-\\u2016\\u2018-\\u201A\\u201C-\\u201E\\u2020-\\u2022\\u2025\\u2026\\u2030-\\u2035\\u2039\\u203A\\u203E\\u2041\\u2043\\u2044\\u204F\\u2057\\u205F-\\u2063\\u20AC\\u20DB\\u20DC\\u2102\\u2105\\u210A-\\u2113\\u2115-\\u211E\\u2122\\u2124\\u2127-\\u2129\\u212C\\u212D\\u212F-\\u2131\\u2133-\\u2138\\u2145-\\u2148\\u2153-\\u215E\\u2190-\\u219B\\u219D-\\u21A7\\u21A9-\\u21AE\\u21B0-\\u21B3\\u21B5-\\u21B7\\u21BA-\\u21DB\\u21DD\\u21E4\\u21E5\\u21F5\\u21FD-\\u2205\\u2207-\\u2209\\u220B\\u220C\\u220F-\\u2214\\u2216-\\u2218\\u221A\\u221D-\\u2238\\u223A-\\u2257\\u2259\\u225A\\u225C\\u225F-\\u2262\\u2264-\\u228B\\u228D-\\u229B\\u229D-\\u22A5\\u22A7-\\u22B0\\u22B2-\\u22BB\\u22BD-\\u22DB\\u22DE-\\u22E3\\u22E6-\\u22F7\\u22F9-\\u22FE\\u2305\\u2306\\u2308-\\u2310\\u2312\\u2313\\u2315\\u2316\\u231C-\\u231F\\u2322\\u2323\\u232D\\u232E\\u2336\\u233D\\u233F\\u237C\\u23B0\\u23B1\\u23B4-\\u23B6\\u23DC-\\u23DF\\u23E2\\u23E7\\u2423\\u24C8\\u2500\\u2502\\u250C\\u2510\\u2514\\u2518\\u251C\\u2524\\u252C\\u2534\\u253C\\u2550-\\u256C\\u2580\\u2584\\u2588\\u2591-\\u2593\\u25A1\\u25AA\\u25AB\\u25AD\\u25AE\\u25B1\\u25B3-\\u25B5\\u25B8\\u25B9\\u25BD-\\u25BF\\u25C2\\u25C3\\u25CA\\u25CB\\u25EC\\u25EF\\u25F8-\\u25FC\\u2605\\u2606\\u260E\\u2640\\u2642\\u2660\\u2663\\u2665\\u2666\\u266A\\u266D-\\u266F\\u2713\\u2717\\u2720\\u2736\\u2758\\u2772\\u2773\\u27C8\\u27C9\\u27E6-\\u27ED\\u27F5-\\u27FA\\u27FC\\u27FF\\u2902-\\u2905\\u290C-\\u2913\\u2916\\u2919-\\u2920\\u2923-\\u292A\\u2933\\u2935-\\u2939\\u293C\\u293D\\u2945\\u2948-\\u294B\\u294E-\\u2976\\u2978\\u2979\\u297B-\\u297F\\u2985\\u2986\\u298B-\\u2996\\u299A\\u299C\\u299D\\u29A4-\\u29B7\\u29B9\\u29BB\\u29BC\\u29BE-\\u29C5\\u29C9\\u29CD-\\u29D0\\u29DC-\\u29DE\\u29E3-\\u29E5\\u29EB\\u29F4\\u29F6\\u2A00-\\u2A02\\u2A04\\u2A06\\u2A0C\\u2A0D\\u2A10-\\u2A17\\u2A22-\\u2A27\\u2A29\\u2A2A\\u2A2D-\\u2A31\\u2A33-\\u2A3C\\u2A3F\\u2A40\\u2A42-\\u2A4D\\u2A50\\u2A53-\\u2A58\\u2A5A-\\u2A5D\\u2A5F\\u2A66\\u2A6A\\u2A6D-\\u2A75\\u2A77-\\u2A9A\\u2A9D-\\u2AA2\\u2AA4-\\u2AB0\\u2AB3-\\u2AC8\\u2ACB\\u2ACC\\u2ACF-\\u2ADB\\u2AE4\\u2AE6-\\u2AE9\\u2AEB-\\u2AF3\\u2AFD\\uFB00-\\uFB04]|\\uD835[\\uDC9C\\uDC9E\\uDC9F\\uDCA2\\uDCA5\\uDCA6\\uDCA9-\\uDCAC\\uDCAE-\\uDCB9\\uDCBB\\uDCBD-\\uDCC3\\uDCC5-\\uDCCF\\uDD04\\uDD05\\uDD07-\\uDD0A\\uDD0D-\\uDD14\\uDD16-\\uDD1C\\uDD1E-\\uDD39\\uDD3B-\\uDD3E\\uDD40-\\uDD44\\uDD46\\uDD4A-\\uDD50\\uDD52-\\uDD6B]/g;\n var encodeMap = { \"­\": \"shy\", \"‌\": \"zwnj\", \"‍\": \"zwj\", \"‎\": \"lrm\", \"⁣\": \"ic\", \"⁢\": \"it\", \"⁡\": \"af\", \"‏\": \"rlm\", \"​\": \"ZeroWidthSpace\", \"⁠\": \"NoBreak\", \"̑\": \"DownBreve\", \"⃛\": \"tdot\", \"⃜\": \"DotDot\", \"\t\": \"Tab\", \"\\n\": \"NewLine\", \" \": \"puncsp\", \" \": \"MediumSpace\", \" \": \"thinsp\", \" \": \"hairsp\", \" \": \"emsp13\", \" \": \"ensp\", \" \": \"emsp14\", \" \": \"emsp\", \" \": \"numsp\", \" \": \"nbsp\", \"  \": \"ThickSpace\", \"‾\": \"oline\", \"_\": \"lowbar\", \"‐\": \"dash\", \"–\": \"ndash\", \"—\": \"mdash\", \"―\": \"horbar\", \",\": \"comma\", \";\": \"semi\", \"⁏\": \"bsemi\", \":\": \"colon\", \"⩴\": \"Colone\", \"!\": \"excl\", \"¡\": \"iexcl\", \"?\": \"quest\", \"¿\": \"iquest\", \".\": \"period\", \"‥\": \"nldr\", \"…\": \"mldr\", \"·\": \"middot\", \"'\": \"apos\", \"‘\": \"lsquo\", \"’\": \"rsquo\", \"‚\": \"sbquo\", \"‹\": \"lsaquo\", \"›\": \"rsaquo\", '\"': \"quot\", \"“\": \"ldquo\", \"”\": \"rdquo\", \"„\": \"bdquo\", \"«\": \"laquo\", \"»\": \"raquo\", \"(\": \"lpar\", \")\": \"rpar\", \"[\": \"lsqb\", \"]\": \"rsqb\", \"{\": \"lcub\", \"}\": \"rcub\", \"⌈\": \"lceil\", \"⌉\": \"rceil\", \"⌊\": \"lfloor\", \"⌋\": \"rfloor\", \"⦅\": \"lopar\", \"⦆\": \"ropar\", \"⦋\": \"lbrke\", \"⦌\": \"rbrke\", \"⦍\": \"lbrkslu\", \"⦎\": \"rbrksld\", \"⦏\": \"lbrksld\", \"⦐\": \"rbrkslu\", \"⦑\": \"langd\", \"⦒\": \"rangd\", \"⦓\": \"lparlt\", \"⦔\": \"rpargt\", \"⦕\": \"gtlPar\", \"⦖\": \"ltrPar\", \"⟦\": \"lobrk\", \"⟧\": \"robrk\", \"⟨\": \"lang\", \"⟩\": \"rang\", \"⟪\": \"Lang\", \"⟫\": \"Rang\", \"⟬\": \"loang\", \"⟭\": \"roang\", \"❲\": \"lbbrk\", \"❳\": \"rbbrk\", \"‖\": \"Vert\", \"§\": \"sect\", \"¶\": \"para\", \"@\": \"commat\", \"*\": \"ast\", \"/\": \"sol\", \"undefined\": null, \"&\": \"amp\", \"#\": \"num\", \"%\": \"percnt\", \"‰\": \"permil\", \"‱\": \"pertenk\", \"†\": \"dagger\", \"‡\": \"Dagger\", \"•\": \"bull\", \"⁃\": \"hybull\", \"′\": \"prime\", \"″\": \"Prime\", \"‴\": \"tprime\", \"⁗\": \"qprime\", \"‵\": \"bprime\", \"⁁\": \"caret\", \"`\": \"grave\", \"´\": \"acute\", \"˜\": \"tilde\", \"^\": \"Hat\", \"¯\": \"macr\", \"˘\": \"breve\", \"˙\": \"dot\", \"¨\": \"die\", \"˚\": \"ring\", \"˝\": \"dblac\", \"¸\": \"cedil\", \"˛\": \"ogon\", \"ˆ\": \"circ\", \"ˇ\": \"caron\", \"°\": \"deg\", \"©\": \"copy\", \"®\": \"reg\", \"℗\": \"copysr\", \"℘\": \"wp\", \"℞\": \"rx\", \"℧\": \"mho\", \"℩\": \"iiota\", \"←\": \"larr\", \"↚\": \"nlarr\", \"→\": \"rarr\", \"↛\": \"nrarr\", \"↑\": \"uarr\", \"↓\": \"darr\", \"↔\": \"harr\", \"↮\": \"nharr\", \"↕\": \"varr\", \"↖\": \"nwarr\", \"↗\": \"nearr\", \"↘\": \"searr\", \"↙\": \"swarr\", \"↝\": \"rarrw\", \"↝̸\": \"nrarrw\", \"↞\": \"Larr\", \"↟\": \"Uarr\", \"↠\": \"Rarr\", \"↡\": \"Darr\", \"↢\": \"larrtl\", \"↣\": \"rarrtl\", \"↤\": \"mapstoleft\", \"↥\": \"mapstoup\", \"↦\": \"map\", \"↧\": \"mapstodown\", \"↩\": \"larrhk\", \"↪\": \"rarrhk\", \"↫\": \"larrlp\", \"↬\": \"rarrlp\", \"↭\": \"harrw\", \"↰\": \"lsh\", \"↱\": \"rsh\", \"↲\": \"ldsh\", \"↳\": \"rdsh\", \"↵\": \"crarr\", \"↶\": \"cularr\", \"↷\": \"curarr\", \"↺\": \"olarr\", \"↻\": \"orarr\", \"↼\": \"lharu\", \"↽\": \"lhard\", \"↾\": \"uharr\", \"↿\": \"uharl\", \"⇀\": \"rharu\", \"⇁\": \"rhard\", \"⇂\": \"dharr\", \"⇃\": \"dharl\", \"⇄\": \"rlarr\", \"⇅\": \"udarr\", \"⇆\": \"lrarr\", \"⇇\": \"llarr\", \"⇈\": \"uuarr\", \"⇉\": \"rrarr\", \"⇊\": \"ddarr\", \"⇋\": \"lrhar\", \"⇌\": \"rlhar\", \"⇐\": \"lArr\", \"⇍\": \"nlArr\", \"⇑\": \"uArr\", \"⇒\": \"rArr\", \"⇏\": \"nrArr\", \"⇓\": \"dArr\", \"⇔\": \"iff\", \"⇎\": \"nhArr\", \"⇕\": \"vArr\", \"⇖\": \"nwArr\", \"⇗\": \"neArr\", \"⇘\": \"seArr\", \"⇙\": \"swArr\", \"⇚\": \"lAarr\", \"⇛\": \"rAarr\", \"⇝\": \"zigrarr\", \"⇤\": \"larrb\", \"⇥\": \"rarrb\", \"⇵\": \"duarr\", \"⇽\": \"loarr\", \"⇾\": \"roarr\", \"⇿\": \"hoarr\", \"∀\": \"forall\", \"∁\": \"comp\", \"∂\": \"part\", \"∂̸\": \"npart\", \"∃\": \"exist\", \"∄\": \"nexist\", \"∅\": \"empty\", \"∇\": \"Del\", \"∈\": \"in\", \"∉\": \"notin\", \"∋\": \"ni\", \"∌\": \"notni\", \"϶\": \"bepsi\", \"∏\": \"prod\", \"∐\": \"coprod\", \"∑\": \"sum\", \"+\": \"plus\", \"±\": \"pm\", \"÷\": \"div\", \"×\": \"times\", \"<\": \"lt\", \"≮\": \"nlt\", \"<⃒\": \"nvlt\", \"=\": \"equals\", \"≠\": \"ne\", \"=⃥\": \"bne\", \"⩵\": \"Equal\", \">\": \"gt\", \"≯\": \"ngt\", \">⃒\": \"nvgt\", \"¬\": \"not\", \"|\": \"vert\", \"¦\": \"brvbar\", \"−\": \"minus\", \"∓\": \"mp\", \"∔\": \"plusdo\", \"⁄\": \"frasl\", \"∖\": \"setmn\", \"∗\": \"lowast\", \"∘\": \"compfn\", \"√\": \"Sqrt\", \"∝\": \"prop\", \"∞\": \"infin\", \"∟\": \"angrt\", \"∠\": \"ang\", \"∠⃒\": \"nang\", \"∡\": \"angmsd\", \"∢\": \"angsph\", \"∣\": \"mid\", \"∤\": \"nmid\", \"∥\": \"par\", \"∦\": \"npar\", \"∧\": \"and\", \"∨\": \"or\", \"∩\": \"cap\", \"∩︀\": \"caps\", \"∪\": \"cup\", \"∪︀\": \"cups\", \"∫\": \"int\", \"∬\": \"Int\", \"∭\": \"tint\", \"⨌\": \"qint\", \"∮\": \"oint\", \"∯\": \"Conint\", \"∰\": \"Cconint\", \"∱\": \"cwint\", \"∲\": \"cwconint\", \"∳\": \"awconint\", \"∴\": \"there4\", \"∵\": \"becaus\", \"∶\": \"ratio\", \"∷\": \"Colon\", \"∸\": \"minusd\", \"∺\": \"mDDot\", \"∻\": \"homtht\", \"∼\": \"sim\", \"≁\": \"nsim\", \"∼⃒\": \"nvsim\", \"∽\": \"bsim\", \"∽̱\": \"race\", \"∾\": \"ac\", \"∾̳\": \"acE\", \"∿\": \"acd\", \"≀\": \"wr\", \"≂\": \"esim\", \"≂̸\": \"nesim\", \"≃\": \"sime\", \"≄\": \"nsime\", \"≅\": \"cong\", \"≇\": \"ncong\", \"≆\": \"simne\", \"≈\": \"ap\", \"≉\": \"nap\", \"≊\": \"ape\", \"≋\": \"apid\", \"≋̸\": \"napid\", \"≌\": \"bcong\", \"≍\": \"CupCap\", \"≭\": \"NotCupCap\", \"≍⃒\": \"nvap\", \"≎\": \"bump\", \"≎̸\": \"nbump\", \"≏\": \"bumpe\", \"≏̸\": \"nbumpe\", \"≐\": \"doteq\", \"≐̸\": \"nedot\", \"≑\": \"eDot\", \"≒\": \"efDot\", \"≓\": \"erDot\", \"≔\": \"colone\", \"≕\": \"ecolon\", \"≖\": \"ecir\", \"≗\": \"cire\", \"≙\": \"wedgeq\", \"≚\": \"veeeq\", \"≜\": \"trie\", \"≟\": \"equest\", \"≡\": \"equiv\", \"≢\": \"nequiv\", \"≡⃥\": \"bnequiv\", \"≤\": \"le\", \"≰\": \"nle\", \"≤⃒\": \"nvle\", \"≥\": \"ge\", \"≱\": \"nge\", \"≥⃒\": \"nvge\", \"≦\": \"lE\", \"≦̸\": \"nlE\", \"≧\": \"gE\", \"≧̸\": \"ngE\", \"≨︀\": \"lvnE\", \"≨\": \"lnE\", \"≩\": \"gnE\", \"≩︀\": \"gvnE\", \"≪\": \"ll\", \"≪̸\": \"nLtv\", \"≪⃒\": \"nLt\", \"≫\": \"gg\", \"≫̸\": \"nGtv\", \"≫⃒\": \"nGt\", \"≬\": \"twixt\", \"≲\": \"lsim\", \"≴\": \"nlsim\", \"≳\": \"gsim\", \"≵\": \"ngsim\", \"≶\": \"lg\", \"≸\": \"ntlg\", \"≷\": \"gl\", \"≹\": \"ntgl\", \"≺\": \"pr\", \"⊀\": \"npr\", \"≻\": \"sc\", \"⊁\": \"nsc\", \"≼\": \"prcue\", \"⋠\": \"nprcue\", \"≽\": \"sccue\", \"⋡\": \"nsccue\", \"≾\": \"prsim\", \"≿\": \"scsim\", \"≿̸\": \"NotSucceedsTilde\", \"⊂\": \"sub\", \"⊄\": \"nsub\", \"⊂⃒\": \"vnsub\", \"⊃\": \"sup\", \"⊅\": \"nsup\", \"⊃⃒\": \"vnsup\", \"⊆\": \"sube\", \"⊈\": \"nsube\", \"⊇\": \"supe\", \"⊉\": \"nsupe\", \"⊊︀\": \"vsubne\", \"⊊\": \"subne\", \"⊋︀\": \"vsupne\", \"⊋\": \"supne\", \"⊍\": \"cupdot\", \"⊎\": \"uplus\", \"⊏\": \"sqsub\", \"⊏̸\": \"NotSquareSubset\", \"⊐\": \"sqsup\", \"⊐̸\": \"NotSquareSuperset\", \"⊑\": \"sqsube\", \"⋢\": \"nsqsube\", \"⊒\": \"sqsupe\", \"⋣\": \"nsqsupe\", \"⊓\": \"sqcap\", \"⊓︀\": \"sqcaps\", \"⊔\": \"sqcup\", \"⊔︀\": \"sqcups\", \"⊕\": \"oplus\", \"⊖\": \"ominus\", \"⊗\": \"otimes\", \"⊘\": \"osol\", \"⊙\": \"odot\", \"⊚\": \"ocir\", \"⊛\": \"oast\", \"⊝\": \"odash\", \"⊞\": \"plusb\", \"⊟\": \"minusb\", \"⊠\": \"timesb\", \"⊡\": \"sdotb\", \"⊢\": \"vdash\", \"⊬\": \"nvdash\", \"⊣\": \"dashv\", \"⊤\": \"top\", \"⊥\": \"bot\", \"⊧\": \"models\", \"⊨\": \"vDash\", \"⊭\": \"nvDash\", \"⊩\": \"Vdash\", \"⊮\": \"nVdash\", \"⊪\": \"Vvdash\", \"⊫\": \"VDash\", \"⊯\": \"nVDash\", \"⊰\": \"prurel\", \"⊲\": \"vltri\", \"⋪\": \"nltri\", \"⊳\": \"vrtri\", \"⋫\": \"nrtri\", \"⊴\": \"ltrie\", \"⋬\": \"nltrie\", \"⊴⃒\": \"nvltrie\", \"⊵\": \"rtrie\", \"⋭\": \"nrtrie\", \"⊵⃒\": \"nvrtrie\", \"⊶\": \"origof\", \"⊷\": \"imof\", \"⊸\": \"mumap\", \"⊹\": \"hercon\", \"⊺\": \"intcal\", \"⊻\": \"veebar\", \"⊽\": \"barvee\", \"⊾\": \"angrtvb\", \"⊿\": \"lrtri\", \"⋀\": \"Wedge\", \"⋁\": \"Vee\", \"⋂\": \"xcap\", \"⋃\": \"xcup\", \"⋄\": \"diam\", \"⋅\": \"sdot\", \"⋆\": \"Star\", \"⋇\": \"divonx\", \"⋈\": \"bowtie\", \"⋉\": \"ltimes\", \"⋊\": \"rtimes\", \"⋋\": \"lthree\", \"⋌\": \"rthree\", \"⋍\": \"bsime\", \"⋎\": \"cuvee\", \"⋏\": \"cuwed\", \"⋐\": \"Sub\", \"⋑\": \"Sup\", \"⋒\": \"Cap\", \"⋓\": \"Cup\", \"⋔\": \"fork\", \"⋕\": \"epar\", \"⋖\": \"ltdot\", \"⋗\": \"gtdot\", \"⋘\": \"Ll\", \"⋘̸\": \"nLl\", \"⋙\": \"Gg\", \"⋙̸\": \"nGg\", \"⋚︀\": \"lesg\", \"⋚\": \"leg\", \"⋛\": \"gel\", \"⋛︀\": \"gesl\", \"⋞\": \"cuepr\", \"⋟\": \"cuesc\", \"⋦\": \"lnsim\", \"⋧\": \"gnsim\", \"⋨\": \"prnsim\", \"⋩\": \"scnsim\", \"⋮\": \"vellip\", \"⋯\": \"ctdot\", \"⋰\": \"utdot\", \"⋱\": \"dtdot\", \"⋲\": \"disin\", \"⋳\": \"isinsv\", \"⋴\": \"isins\", \"⋵\": \"isindot\", \"⋵̸\": \"notindot\", \"⋶\": \"notinvc\", \"⋷\": \"notinvb\", \"⋹\": \"isinE\", \"⋹̸\": \"notinE\", \"⋺\": \"nisd\", \"⋻\": \"xnis\", \"⋼\": \"nis\", \"⋽\": \"notnivc\", \"⋾\": \"notnivb\", \"⌅\": \"barwed\", \"⌆\": \"Barwed\", \"⌌\": \"drcrop\", \"⌍\": \"dlcrop\", \"⌎\": \"urcrop\", \"⌏\": \"ulcrop\", \"⌐\": \"bnot\", \"⌒\": \"profline\", \"⌓\": \"profsurf\", \"⌕\": \"telrec\", \"⌖\": \"target\", \"⌜\": \"ulcorn\", \"⌝\": \"urcorn\", \"⌞\": \"dlcorn\", \"⌟\": \"drcorn\", \"⌢\": \"frown\", \"⌣\": \"smile\", \"⌭\": \"cylcty\", \"⌮\": \"profalar\", \"⌶\": \"topbot\", \"⌽\": \"ovbar\", \"⌿\": \"solbar\", \"⍼\": \"angzarr\", \"⎰\": \"lmoust\", \"⎱\": \"rmoust\", \"⎴\": \"tbrk\", \"⎵\": \"bbrk\", \"⎶\": \"bbrktbrk\", \"⏜\": \"OverParenthesis\", \"⏝\": \"UnderParenthesis\", \"⏞\": \"OverBrace\", \"⏟\": \"UnderBrace\", \"⏢\": \"trpezium\", \"⏧\": \"elinters\", \"␣\": \"blank\", \"─\": \"boxh\", \"│\": \"boxv\", \"┌\": \"boxdr\", \"┐\": \"boxdl\", \"└\": \"boxur\", \"┘\": \"boxul\", \"├\": \"boxvr\", \"┤\": \"boxvl\", \"┬\": \"boxhd\", \"┴\": \"boxhu\", \"┼\": \"boxvh\", \"═\": \"boxH\", \"║\": \"boxV\", \"╒\": \"boxdR\", \"╓\": \"boxDr\", \"╔\": \"boxDR\", \"╕\": \"boxdL\", \"╖\": \"boxDl\", \"╗\": \"boxDL\", \"╘\": \"boxuR\", \"╙\": \"boxUr\", \"╚\": \"boxUR\", \"╛\": \"boxuL\", \"╜\": \"boxUl\", \"╝\": \"boxUL\", \"╞\": \"boxvR\", \"╟\": \"boxVr\", \"╠\": \"boxVR\", \"╡\": \"boxvL\", \"╢\": \"boxVl\", \"╣\": \"boxVL\", \"╤\": \"boxHd\", \"╥\": \"boxhD\", \"╦\": \"boxHD\", \"╧\": \"boxHu\", \"╨\": \"boxhU\", \"╩\": \"boxHU\", \"╪\": \"boxvH\", \"╫\": \"boxVh\", \"╬\": \"boxVH\", \"▀\": \"uhblk\", \"▄\": \"lhblk\", \"█\": \"block\", \"░\": \"blk14\", \"▒\": \"blk12\", \"▓\": \"blk34\", \"□\": \"squ\", \"▪\": \"squf\", \"▫\": \"EmptyVerySmallSquare\", \"▭\": \"rect\", \"▮\": \"marker\", \"▱\": \"fltns\", \"△\": \"xutri\", \"▴\": \"utrif\", \"▵\": \"utri\", \"▸\": \"rtrif\", \"▹\": \"rtri\", \"▽\": \"xdtri\", \"▾\": \"dtrif\", \"▿\": \"dtri\", \"◂\": \"ltrif\", \"◃\": \"ltri\", \"◊\": \"loz\", \"○\": \"cir\", \"◬\": \"tridot\", \"◯\": \"xcirc\", \"◸\": \"ultri\", \"◹\": \"urtri\", \"◺\": \"lltri\", \"◻\": \"EmptySmallSquare\", \"◼\": \"FilledSmallSquare\", \"★\": \"starf\", \"☆\": \"star\", \"☎\": \"phone\", \"♀\": \"female\", \"♂\": \"male\", \"♠\": \"spades\", \"♣\": \"clubs\", \"♥\": \"hearts\", \"♦\": \"diams\", \"♪\": \"sung\", \"✓\": \"check\", \"✗\": \"cross\", \"✠\": \"malt\", \"✶\": \"sext\", \"❘\": \"VerticalSeparator\", \"⟈\": \"bsolhsub\", \"⟉\": \"suphsol\", \"⟵\": \"xlarr\", \"⟶\": \"xrarr\", \"⟷\": \"xharr\", \"⟸\": \"xlArr\", \"⟹\": \"xrArr\", \"⟺\": \"xhArr\", \"⟼\": \"xmap\", \"⟿\": \"dzigrarr\", \"⤂\": \"nvlArr\", \"⤃\": \"nvrArr\", \"⤄\": \"nvHarr\", \"⤅\": \"Map\", \"⤌\": \"lbarr\", \"⤍\": \"rbarr\", \"⤎\": \"lBarr\", \"⤏\": \"rBarr\", \"⤐\": \"RBarr\", \"⤑\": \"DDotrahd\", \"⤒\": \"UpArrowBar\", \"⤓\": \"DownArrowBar\", \"⤖\": \"Rarrtl\", \"⤙\": \"latail\", \"⤚\": \"ratail\", \"⤛\": \"lAtail\", \"⤜\": \"rAtail\", \"⤝\": \"larrfs\", \"⤞\": \"rarrfs\", \"⤟\": \"larrbfs\", \"⤠\": \"rarrbfs\", \"⤣\": \"nwarhk\", \"⤤\": \"nearhk\", \"⤥\": \"searhk\", \"⤦\": \"swarhk\", \"⤧\": \"nwnear\", \"⤨\": \"toea\", \"⤩\": \"tosa\", \"⤪\": \"swnwar\", \"⤳\": \"rarrc\", \"⤳̸\": \"nrarrc\", \"⤵\": \"cudarrr\", \"⤶\": \"ldca\", \"⤷\": \"rdca\", \"⤸\": \"cudarrl\", \"⤹\": \"larrpl\", \"⤼\": \"curarrm\", \"⤽\": \"cularrp\", \"⥅\": \"rarrpl\", \"⥈\": \"harrcir\", \"⥉\": \"Uarrocir\", \"⥊\": \"lurdshar\", \"⥋\": \"ldrushar\", \"⥎\": \"LeftRightVector\", \"⥏\": \"RightUpDownVector\", \"⥐\": \"DownLeftRightVector\", \"⥑\": \"LeftUpDownVector\", \"⥒\": \"LeftVectorBar\", \"⥓\": \"RightVectorBar\", \"⥔\": \"RightUpVectorBar\", \"⥕\": \"RightDownVectorBar\", \"⥖\": \"DownLeftVectorBar\", \"⥗\": \"DownRightVectorBar\", \"⥘\": \"LeftUpVectorBar\", \"⥙\": \"LeftDownVectorBar\", \"⥚\": \"LeftTeeVector\", \"⥛\": \"RightTeeVector\", \"⥜\": \"RightUpTeeVector\", \"⥝\": \"RightDownTeeVector\", \"⥞\": \"DownLeftTeeVector\", \"⥟\": \"DownRightTeeVector\", \"⥠\": \"LeftUpTeeVector\", \"⥡\": \"LeftDownTeeVector\", \"⥢\": \"lHar\", \"⥣\": \"uHar\", \"⥤\": \"rHar\", \"⥥\": \"dHar\", \"⥦\": \"luruhar\", \"⥧\": \"ldrdhar\", \"⥨\": \"ruluhar\", \"⥩\": \"rdldhar\", \"⥪\": \"lharul\", \"⥫\": \"llhard\", \"⥬\": \"rharul\", \"⥭\": \"lrhard\", \"⥮\": \"udhar\", \"⥯\": \"duhar\", \"⥰\": \"RoundImplies\", \"⥱\": \"erarr\", \"⥲\": \"simrarr\", \"⥳\": \"larrsim\", \"⥴\": \"rarrsim\", \"⥵\": \"rarrap\", \"⥶\": \"ltlarr\", \"⥸\": \"gtrarr\", \"⥹\": \"subrarr\", \"⥻\": \"suplarr\", \"⥼\": \"lfisht\", \"⥽\": \"rfisht\", \"⥾\": \"ufisht\", \"⥿\": \"dfisht\", \"⦚\": \"vzigzag\", \"⦜\": \"vangrt\", \"⦝\": \"angrtvbd\", \"⦤\": \"ange\", \"⦥\": \"range\", \"⦦\": \"dwangle\", \"⦧\": \"uwangle\", \"⦨\": \"angmsdaa\", \"⦩\": \"angmsdab\", \"⦪\": \"angmsdac\", \"⦫\": \"angmsdad\", \"⦬\": \"angmsdae\", \"⦭\": \"angmsdaf\", \"⦮\": \"angmsdag\", \"⦯\": \"angmsdah\", \"⦰\": \"bemptyv\", \"⦱\": \"demptyv\", \"⦲\": \"cemptyv\", \"⦳\": \"raemptyv\", \"⦴\": \"laemptyv\", \"⦵\": \"ohbar\", \"⦶\": \"omid\", \"⦷\": \"opar\", \"⦹\": \"operp\", \"⦻\": \"olcross\", \"⦼\": \"odsold\", \"⦾\": \"olcir\", \"⦿\": \"ofcir\", \"⧀\": \"olt\", \"⧁\": \"ogt\", \"⧂\": \"cirscir\", \"⧃\": \"cirE\", \"⧄\": \"solb\", \"⧅\": \"bsolb\", \"⧉\": \"boxbox\", \"⧍\": \"trisb\", \"⧎\": \"rtriltri\", \"⧏\": \"LeftTriangleBar\", \"⧏̸\": \"NotLeftTriangleBar\", \"⧐\": \"RightTriangleBar\", \"⧐̸\": \"NotRightTriangleBar\", \"⧜\": \"iinfin\", \"⧝\": \"infintie\", \"⧞\": \"nvinfin\", \"⧣\": \"eparsl\", \"⧤\": \"smeparsl\", \"⧥\": \"eqvparsl\", \"⧫\": \"lozf\", \"⧴\": \"RuleDelayed\", \"⧶\": \"dsol\", \"⨀\": \"xodot\", \"⨁\": \"xoplus\", \"⨂\": \"xotime\", \"⨄\": \"xuplus\", \"⨆\": \"xsqcup\", \"⨍\": \"fpartint\", \"⨐\": \"cirfnint\", \"⨑\": \"awint\", \"⨒\": \"rppolint\", \"⨓\": \"scpolint\", \"⨔\": \"npolint\", \"⨕\": \"pointint\", \"⨖\": \"quatint\", \"⨗\": \"intlarhk\", \"⨢\": \"pluscir\", \"⨣\": \"plusacir\", \"⨤\": \"simplus\", \"⨥\": \"plusdu\", \"⨦\": \"plussim\", \"⨧\": \"plustwo\", \"⨩\": \"mcomma\", \"⨪\": \"minusdu\", \"⨭\": \"loplus\", \"⨮\": \"roplus\", \"⨯\": \"Cross\", \"⨰\": \"timesd\", \"⨱\": \"timesbar\", \"⨳\": \"smashp\", \"⨴\": \"lotimes\", \"⨵\": \"rotimes\", \"⨶\": \"otimesas\", \"⨷\": \"Otimes\", \"⨸\": \"odiv\", \"⨹\": \"triplus\", \"⨺\": \"triminus\", \"⨻\": \"tritime\", \"⨼\": \"iprod\", \"⨿\": \"amalg\", \"⩀\": \"capdot\", \"⩂\": \"ncup\", \"⩃\": \"ncap\", \"⩄\": \"capand\", \"⩅\": \"cupor\", \"⩆\": \"cupcap\", \"⩇\": \"capcup\", \"⩈\": \"cupbrcap\", \"⩉\": \"capbrcup\", \"⩊\": \"cupcup\", \"⩋\": \"capcap\", \"⩌\": \"ccups\", \"⩍\": \"ccaps\", \"⩐\": \"ccupssm\", \"⩓\": \"And\", \"⩔\": \"Or\", \"⩕\": \"andand\", \"⩖\": \"oror\", \"⩗\": \"orslope\", \"⩘\": \"andslope\", \"⩚\": \"andv\", \"⩛\": \"orv\", \"⩜\": \"andd\", \"⩝\": \"ord\", \"⩟\": \"wedbar\", \"⩦\": \"sdote\", \"⩪\": \"simdot\", \"⩭\": \"congdot\", \"⩭̸\": \"ncongdot\", \"⩮\": \"easter\", \"⩯\": \"apacir\", \"⩰\": \"apE\", \"⩰̸\": \"napE\", \"⩱\": \"eplus\", \"⩲\": \"pluse\", \"⩳\": \"Esim\", \"⩷\": \"eDDot\", \"⩸\": \"equivDD\", \"⩹\": \"ltcir\", \"⩺\": \"gtcir\", \"⩻\": \"ltquest\", \"⩼\": \"gtquest\", \"⩽\": \"les\", \"⩽̸\": \"nles\", \"⩾\": \"ges\", \"⩾̸\": \"nges\", \"⩿\": \"lesdot\", \"⪀\": \"gesdot\", \"⪁\": \"lesdoto\", \"⪂\": \"gesdoto\", \"⪃\": \"lesdotor\", \"⪄\": \"gesdotol\", \"⪅\": \"lap\", \"⪆\": \"gap\", \"⪇\": \"lne\", \"⪈\": \"gne\", \"⪉\": \"lnap\", \"⪊\": \"gnap\", \"⪋\": \"lEg\", \"⪌\": \"gEl\", \"⪍\": \"lsime\", \"⪎\": \"gsime\", \"⪏\": \"lsimg\", \"⪐\": \"gsiml\", \"⪑\": \"lgE\", \"⪒\": \"glE\", \"⪓\": \"lesges\", \"⪔\": \"gesles\", \"⪕\": \"els\", \"⪖\": \"egs\", \"⪗\": \"elsdot\", \"⪘\": \"egsdot\", \"⪙\": \"el\", \"⪚\": \"eg\", \"⪝\": \"siml\", \"⪞\": \"simg\", \"⪟\": \"simlE\", \"⪠\": \"simgE\", \"⪡\": \"LessLess\", \"⪡̸\": \"NotNestedLessLess\", \"⪢\": \"GreaterGreater\", \"⪢̸\": \"NotNestedGreaterGreater\", \"⪤\": \"glj\", \"⪥\": \"gla\", \"⪦\": \"ltcc\", \"⪧\": \"gtcc\", \"⪨\": \"lescc\", \"⪩\": \"gescc\", \"⪪\": \"smt\", \"⪫\": \"lat\", \"⪬\": \"smte\", \"⪬︀\": \"smtes\", \"⪭\": \"late\", \"⪭︀\": \"lates\", \"⪮\": \"bumpE\", \"⪯\": \"pre\", \"⪯̸\": \"npre\", \"⪰\": \"sce\", \"⪰̸\": \"nsce\", \"⪳\": \"prE\", \"⪴\": \"scE\", \"⪵\": \"prnE\", \"⪶\": \"scnE\", \"⪷\": \"prap\", \"⪸\": \"scap\", \"⪹\": \"prnap\", \"⪺\": \"scnap\", \"⪻\": \"Pr\", \"⪼\": \"Sc\", \"⪽\": \"subdot\", \"⪾\": \"supdot\", \"⪿\": \"subplus\", \"⫀\": \"supplus\", \"⫁\": \"submult\", \"⫂\": \"supmult\", \"⫃\": \"subedot\", \"⫄\": \"supedot\", \"⫅\": \"subE\", \"⫅̸\": \"nsubE\", \"⫆\": \"supE\", \"⫆̸\": \"nsupE\", \"⫇\": \"subsim\", \"⫈\": \"supsim\", \"⫋︀\": \"vsubnE\", \"⫋\": \"subnE\", \"⫌︀\": \"vsupnE\", \"⫌\": \"supnE\", \"⫏\": \"csub\", \"⫐\": \"csup\", \"⫑\": \"csube\", \"⫒\": \"csupe\", \"⫓\": \"subsup\", \"⫔\": \"supsub\", \"⫕\": \"subsub\", \"⫖\": \"supsup\", \"⫗\": \"suphsub\", \"⫘\": \"supdsub\", \"⫙\": \"forkv\", \"⫚\": \"topfork\", \"⫛\": \"mlcp\", \"⫤\": \"Dashv\", \"⫦\": \"Vdashl\", \"⫧\": \"Barv\", \"⫨\": \"vBar\", \"⫩\": \"vBarv\", \"⫫\": \"Vbar\", \"⫬\": \"Not\", \"⫭\": \"bNot\", \"⫮\": \"rnmid\", \"⫯\": \"cirmid\", \"⫰\": \"midcir\", \"⫱\": \"topcir\", \"⫲\": \"nhpar\", \"⫳\": \"parsim\", \"⫽\": \"parsl\", \"⫽⃥\": \"nparsl\", \"♭\": \"flat\", \"♮\": \"natur\", \"♯\": \"sharp\", \"¤\": \"curren\", \"¢\": \"cent\", \"$\": \"dollar\", \"£\": \"pound\", \"¥\": \"yen\", \"€\": \"euro\", \"¹\": \"sup1\", \"½\": \"half\", \"⅓\": \"frac13\", \"¼\": \"frac14\", \"⅕\": \"frac15\", \"⅙\": \"frac16\", \"⅛\": \"frac18\", \"²\": \"sup2\", \"⅔\": \"frac23\", \"⅖\": \"frac25\", \"³\": \"sup3\", \"¾\": \"frac34\", \"⅗\": \"frac35\", \"⅜\": \"frac38\", \"⅘\": \"frac45\", \"⅚\": \"frac56\", \"⅝\": \"frac58\", \"⅞\": \"frac78\", \"𝒶\": \"ascr\", \"𝕒\": \"aopf\", \"𝔞\": \"afr\", \"𝔸\": \"Aopf\", \"𝔄\": \"Afr\", \"𝒜\": \"Ascr\", \"ª\": \"ordf\", \"á\": \"aacute\", \"Á\": \"Aacute\", \"à\": \"agrave\", \"À\": \"Agrave\", \"ă\": \"abreve\", \"Ă\": \"Abreve\", \"â\": \"acirc\", \"Â\": \"Acirc\", \"å\": \"aring\", \"Å\": \"angst\", \"ä\": \"auml\", \"Ä\": \"Auml\", \"ã\": \"atilde\", \"Ã\": \"Atilde\", \"ą\": \"aogon\", \"Ą\": \"Aogon\", \"ā\": \"amacr\", \"Ā\": \"Amacr\", \"æ\": \"aelig\", \"Æ\": \"AElig\", \"𝒷\": \"bscr\", \"𝕓\": \"bopf\", \"𝔟\": \"bfr\", \"𝔹\": \"Bopf\", \"ℬ\": \"Bscr\", \"𝔅\": \"Bfr\", \"𝔠\": \"cfr\", \"𝒸\": \"cscr\", \"𝕔\": \"copf\", \"ℭ\": \"Cfr\", \"𝒞\": \"Cscr\", \"ℂ\": \"Copf\", \"ć\": \"cacute\", \"Ć\": \"Cacute\", \"ĉ\": \"ccirc\", \"Ĉ\": \"Ccirc\", \"č\": \"ccaron\", \"Č\": \"Ccaron\", \"ċ\": \"cdot\", \"Ċ\": \"Cdot\", \"ç\": \"ccedil\", \"Ç\": \"Ccedil\", \"℅\": \"incare\", \"𝔡\": \"dfr\", \"ⅆ\": \"dd\", \"𝕕\": \"dopf\", \"𝒹\": \"dscr\", \"𝒟\": \"Dscr\", \"𝔇\": \"Dfr\", \"ⅅ\": \"DD\", \"𝔻\": \"Dopf\", \"ď\": \"dcaron\", \"Ď\": \"Dcaron\", \"đ\": \"dstrok\", \"Đ\": \"Dstrok\", \"ð\": \"eth\", \"Ð\": \"ETH\", \"ⅇ\": \"ee\", \"ℯ\": \"escr\", \"𝔢\": \"efr\", \"𝕖\": \"eopf\", \"ℰ\": \"Escr\", \"𝔈\": \"Efr\", \"𝔼\": \"Eopf\", \"é\": \"eacute\", \"É\": \"Eacute\", \"è\": \"egrave\", \"È\": \"Egrave\", \"ê\": \"ecirc\", \"Ê\": \"Ecirc\", \"ě\": \"ecaron\", \"Ě\": \"Ecaron\", \"ë\": \"euml\", \"Ë\": \"Euml\", \"ė\": \"edot\", \"Ė\": \"Edot\", \"ę\": \"eogon\", \"Ę\": \"Eogon\", \"ē\": \"emacr\", \"Ē\": \"Emacr\", \"𝔣\": \"ffr\", \"𝕗\": \"fopf\", \"𝒻\": \"fscr\", \"𝔉\": \"Ffr\", \"𝔽\": \"Fopf\", \"ℱ\": \"Fscr\", \"ff\": \"fflig\", \"ffi\": \"ffilig\", \"ffl\": \"ffllig\", \"fi\": \"filig\", \"fj\": \"fjlig\", \"fl\": \"fllig\", \"ƒ\": \"fnof\", \"ℊ\": \"gscr\", \"𝕘\": \"gopf\", \"𝔤\": \"gfr\", \"𝒢\": \"Gscr\", \"𝔾\": \"Gopf\", \"𝔊\": \"Gfr\", \"ǵ\": \"gacute\", \"ğ\": \"gbreve\", \"Ğ\": \"Gbreve\", \"ĝ\": \"gcirc\", \"Ĝ\": \"Gcirc\", \"ġ\": \"gdot\", \"Ġ\": \"Gdot\", \"Ģ\": \"Gcedil\", \"𝔥\": \"hfr\", \"ℎ\": \"planckh\", \"𝒽\": \"hscr\", \"𝕙\": \"hopf\", \"ℋ\": \"Hscr\", \"ℌ\": \"Hfr\", \"ℍ\": \"Hopf\", \"ĥ\": \"hcirc\", \"Ĥ\": \"Hcirc\", \"ℏ\": \"hbar\", \"ħ\": \"hstrok\", \"Ħ\": \"Hstrok\", \"𝕚\": \"iopf\", \"𝔦\": \"ifr\", \"𝒾\": \"iscr\", \"ⅈ\": \"ii\", \"𝕀\": \"Iopf\", \"ℐ\": \"Iscr\", \"ℑ\": \"Im\", \"í\": \"iacute\", \"Í\": \"Iacute\", \"ì\": \"igrave\", \"Ì\": \"Igrave\", \"î\": \"icirc\", \"Î\": \"Icirc\", \"ï\": \"iuml\", \"Ï\": \"Iuml\", \"ĩ\": \"itilde\", \"Ĩ\": \"Itilde\", \"İ\": \"Idot\", \"į\": \"iogon\", \"Į\": \"Iogon\", \"ī\": \"imacr\", \"Ī\": \"Imacr\", \"ij\": \"ijlig\", \"IJ\": \"IJlig\", \"ı\": \"imath\", \"𝒿\": \"jscr\", \"𝕛\": \"jopf\", \"𝔧\": \"jfr\", \"𝒥\": \"Jscr\", \"𝔍\": \"Jfr\", \"𝕁\": \"Jopf\", \"ĵ\": \"jcirc\", \"Ĵ\": \"Jcirc\", \"ȷ\": \"jmath\", \"𝕜\": \"kopf\", \"𝓀\": \"kscr\", \"𝔨\": \"kfr\", \"𝒦\": \"Kscr\", \"𝕂\": \"Kopf\", \"𝔎\": \"Kfr\", \"ķ\": \"kcedil\", \"Ķ\": \"Kcedil\", \"𝔩\": \"lfr\", \"𝓁\": \"lscr\", \"ℓ\": \"ell\", \"𝕝\": \"lopf\", \"ℒ\": \"Lscr\", \"𝔏\": \"Lfr\", \"𝕃\": \"Lopf\", \"ĺ\": \"lacute\", \"Ĺ\": \"Lacute\", \"ľ\": \"lcaron\", \"Ľ\": \"Lcaron\", \"ļ\": \"lcedil\", \"Ļ\": \"Lcedil\", \"ł\": \"lstrok\", \"Ł\": \"Lstrok\", \"ŀ\": \"lmidot\", \"Ŀ\": \"Lmidot\", \"𝔪\": \"mfr\", \"𝕞\": \"mopf\", \"𝓂\": \"mscr\", \"𝔐\": \"Mfr\", \"𝕄\": \"Mopf\", \"ℳ\": \"Mscr\", \"𝔫\": \"nfr\", \"𝕟\": \"nopf\", \"𝓃\": \"nscr\", \"ℕ\": \"Nopf\", \"𝒩\": \"Nscr\", \"𝔑\": \"Nfr\", \"ń\": \"nacute\", \"Ń\": \"Nacute\", \"ň\": \"ncaron\", \"Ň\": \"Ncaron\", \"ñ\": \"ntilde\", \"Ñ\": \"Ntilde\", \"ņ\": \"ncedil\", \"Ņ\": \"Ncedil\", \"№\": \"numero\", \"ŋ\": \"eng\", \"Ŋ\": \"ENG\", \"𝕠\": \"oopf\", \"𝔬\": \"ofr\", \"ℴ\": \"oscr\", \"𝒪\": \"Oscr\", \"𝔒\": \"Ofr\", \"𝕆\": \"Oopf\", \"º\": \"ordm\", \"ó\": \"oacute\", \"Ó\": \"Oacute\", \"ò\": \"ograve\", \"Ò\": \"Ograve\", \"ô\": \"ocirc\", \"Ô\": \"Ocirc\", \"ö\": \"ouml\", \"Ö\": \"Ouml\", \"ő\": \"odblac\", \"Ő\": \"Odblac\", \"õ\": \"otilde\", \"Õ\": \"Otilde\", \"ø\": \"oslash\", \"Ø\": \"Oslash\", \"ō\": \"omacr\", \"Ō\": \"Omacr\", \"œ\": \"oelig\", \"Œ\": \"OElig\", \"𝔭\": \"pfr\", \"𝓅\": \"pscr\", \"𝕡\": \"popf\", \"ℙ\": \"Popf\", \"𝔓\": \"Pfr\", \"𝒫\": \"Pscr\", \"𝕢\": \"qopf\", \"𝔮\": \"qfr\", \"𝓆\": \"qscr\", \"𝒬\": \"Qscr\", \"𝔔\": \"Qfr\", \"ℚ\": \"Qopf\", \"ĸ\": \"kgreen\", \"𝔯\": \"rfr\", \"𝕣\": \"ropf\", \"𝓇\": \"rscr\", \"ℛ\": \"Rscr\", \"ℜ\": \"Re\", \"ℝ\": \"Ropf\", \"ŕ\": \"racute\", \"Ŕ\": \"Racute\", \"ř\": \"rcaron\", \"Ř\": \"Rcaron\", \"ŗ\": \"rcedil\", \"Ŗ\": \"Rcedil\", \"𝕤\": \"sopf\", \"𝓈\": \"sscr\", \"𝔰\": \"sfr\", \"𝕊\": \"Sopf\", \"𝔖\": \"Sfr\", \"𝒮\": \"Sscr\", \"Ⓢ\": \"oS\", \"ś\": \"sacute\", \"Ś\": \"Sacute\", \"ŝ\": \"scirc\", \"Ŝ\": \"Scirc\", \"š\": \"scaron\", \"Š\": \"Scaron\", \"ş\": \"scedil\", \"Ş\": \"Scedil\", \"ß\": \"szlig\", \"𝔱\": \"tfr\", \"𝓉\": \"tscr\", \"𝕥\": \"topf\", \"𝒯\": \"Tscr\", \"𝔗\": \"Tfr\", \"𝕋\": \"Topf\", \"ť\": \"tcaron\", \"Ť\": \"Tcaron\", \"ţ\": \"tcedil\", \"Ţ\": \"Tcedil\", \"™\": \"trade\", \"ŧ\": \"tstrok\", \"Ŧ\": \"Tstrok\", \"𝓊\": \"uscr\", \"𝕦\": \"uopf\", \"𝔲\": \"ufr\", \"𝕌\": \"Uopf\", \"𝔘\": \"Ufr\", \"𝒰\": \"Uscr\", \"ú\": \"uacute\", \"Ú\": \"Uacute\", \"ù\": \"ugrave\", \"Ù\": \"Ugrave\", \"ŭ\": \"ubreve\", \"Ŭ\": \"Ubreve\", \"û\": \"ucirc\", \"Û\": \"Ucirc\", \"ů\": \"uring\", \"Ů\": \"Uring\", \"ü\": \"uuml\", \"Ü\": \"Uuml\", \"ű\": \"udblac\", \"Ű\": \"Udblac\", \"ũ\": \"utilde\", \"Ũ\": \"Utilde\", \"ų\": \"uogon\", \"Ų\": \"Uogon\", \"ū\": \"umacr\", \"Ū\": \"Umacr\", \"𝔳\": \"vfr\", \"𝕧\": \"vopf\", \"𝓋\": \"vscr\", \"𝔙\": \"Vfr\", \"𝕍\": \"Vopf\", \"𝒱\": \"Vscr\", \"𝕨\": \"wopf\", \"𝓌\": \"wscr\", \"𝔴\": \"wfr\", \"𝒲\": \"Wscr\", \"𝕎\": \"Wopf\", \"𝔚\": \"Wfr\", \"ŵ\": \"wcirc\", \"Ŵ\": \"Wcirc\", \"𝔵\": \"xfr\", \"𝓍\": \"xscr\", \"𝕩\": \"xopf\", \"𝕏\": \"Xopf\", \"𝔛\": \"Xfr\", \"𝒳\": \"Xscr\", \"𝔶\": \"yfr\", \"𝓎\": \"yscr\", \"𝕪\": \"yopf\", \"𝒴\": \"Yscr\", \"𝔜\": \"Yfr\", \"𝕐\": \"Yopf\", \"ý\": \"yacute\", \"Ý\": \"Yacute\", \"ŷ\": \"ycirc\", \"Ŷ\": \"Ycirc\", \"ÿ\": \"yuml\", \"Ÿ\": \"Yuml\", \"𝓏\": \"zscr\", \"𝔷\": \"zfr\", \"𝕫\": \"zopf\", \"ℨ\": \"Zfr\", \"ℤ\": \"Zopf\", \"𝒵\": \"Zscr\", \"ź\": \"zacute\", \"Ź\": \"Zacute\", \"ž\": \"zcaron\", \"Ž\": \"Zcaron\", \"ż\": \"zdot\", \"Ż\": \"Zdot\", \"Ƶ\": \"imped\", \"þ\": \"thorn\", \"Þ\": \"THORN\", \"ʼn\": \"napos\", \"α\": \"alpha\", \"Α\": \"Alpha\", \"β\": \"beta\", \"Β\": \"Beta\", \"γ\": \"gamma\", \"Γ\": \"Gamma\", \"δ\": \"delta\", \"Δ\": \"Delta\", \"ε\": \"epsi\", \"ϵ\": \"epsiv\", \"Ε\": \"Epsilon\", \"ϝ\": \"gammad\", \"Ϝ\": \"Gammad\", \"ζ\": \"zeta\", \"Ζ\": \"Zeta\", \"η\": \"eta\", \"Η\": \"Eta\", \"θ\": \"theta\", \"ϑ\": \"thetav\", \"Θ\": \"Theta\", \"ι\": \"iota\", \"Ι\": \"Iota\", \"κ\": \"kappa\", \"ϰ\": \"kappav\", \"Κ\": \"Kappa\", \"λ\": \"lambda\", \"Λ\": \"Lambda\", \"μ\": \"mu\", \"µ\": \"micro\", \"Μ\": \"Mu\", \"ν\": \"nu\", \"Ν\": \"Nu\", \"ξ\": \"xi\", \"Ξ\": \"Xi\", \"ο\": \"omicron\", \"Ο\": \"Omicron\", \"π\": \"pi\", \"ϖ\": \"piv\", \"Π\": \"Pi\", \"ρ\": \"rho\", \"ϱ\": \"rhov\", \"Ρ\": \"Rho\", \"σ\": \"sigma\", \"Σ\": \"Sigma\", \"ς\": \"sigmaf\", \"τ\": \"tau\", \"Τ\": \"Tau\", \"υ\": \"upsi\", \"Υ\": \"Upsilon\", \"ϒ\": \"Upsi\", \"φ\": \"phi\", \"ϕ\": \"phiv\", \"Φ\": \"Phi\", \"χ\": \"chi\", \"Χ\": \"Chi\", \"ψ\": \"psi\", \"Ψ\": \"Psi\", \"ω\": \"omega\", \"Ω\": \"ohm\", \"а\": \"acy\", \"А\": \"Acy\", \"б\": \"bcy\", \"Б\": \"Bcy\", \"в\": \"vcy\", \"В\": \"Vcy\", \"г\": \"gcy\", \"Г\": \"Gcy\", \"ѓ\": \"gjcy\", \"Ѓ\": \"GJcy\", \"д\": \"dcy\", \"Д\": \"Dcy\", \"ђ\": \"djcy\", \"Ђ\": \"DJcy\", \"е\": \"iecy\", \"Е\": \"IEcy\", \"ё\": \"iocy\", \"Ё\": \"IOcy\", \"є\": \"jukcy\", \"Є\": \"Jukcy\", \"ж\": \"zhcy\", \"Ж\": \"ZHcy\", \"з\": \"zcy\", \"З\": \"Zcy\", \"ѕ\": \"dscy\", \"Ѕ\": \"DScy\", \"и\": \"icy\", \"И\": \"Icy\", \"і\": \"iukcy\", \"І\": \"Iukcy\", \"ї\": \"yicy\", \"Ї\": \"YIcy\", \"й\": \"jcy\", \"Й\": \"Jcy\", \"ј\": \"jsercy\", \"Ј\": \"Jsercy\", \"к\": \"kcy\", \"К\": \"Kcy\", \"ќ\": \"kjcy\", \"Ќ\": \"KJcy\", \"л\": \"lcy\", \"Л\": \"Lcy\", \"љ\": \"ljcy\", \"Љ\": \"LJcy\", \"м\": \"mcy\", \"М\": \"Mcy\", \"н\": \"ncy\", \"Н\": \"Ncy\", \"њ\": \"njcy\", \"Њ\": \"NJcy\", \"о\": \"ocy\", \"О\": \"Ocy\", \"п\": \"pcy\", \"П\": \"Pcy\", \"р\": \"rcy\", \"Р\": \"Rcy\", \"с\": \"scy\", \"С\": \"Scy\", \"т\": \"tcy\", \"Т\": \"Tcy\", \"ћ\": \"tshcy\", \"Ћ\": \"TSHcy\", \"у\": \"ucy\", \"У\": \"Ucy\", \"ў\": \"ubrcy\", \"Ў\": \"Ubrcy\", \"ф\": \"fcy\", \"Ф\": \"Fcy\", \"х\": \"khcy\", \"Х\": \"KHcy\", \"ц\": \"tscy\", \"Ц\": \"TScy\", \"ч\": \"chcy\", \"Ч\": \"CHcy\", \"џ\": \"dzcy\", \"Џ\": \"DZcy\", \"ш\": \"shcy\", \"Ш\": \"SHcy\", \"щ\": \"shchcy\", \"Щ\": \"SHCHcy\", \"ъ\": \"hardcy\", \"Ъ\": \"HARDcy\", \"ы\": \"ycy\", \"Ы\": \"Ycy\", \"ь\": \"softcy\", \"Ь\": \"SOFTcy\", \"э\": \"ecy\", \"Э\": \"Ecy\", \"ю\": \"yucy\", \"Ю\": \"YUcy\", \"я\": \"yacy\", \"Я\": \"YAcy\", \"ℵ\": \"aleph\", \"ℶ\": \"beth\", \"ℷ\": \"gimel\", \"ℸ\": \"daleth\" };\n var regexEscape = /[\"&'<>`]/g;\n var escapeMap = {\n '\"': \""\",\n \"&\": \"&\",\n \"'\": \"'\",\n \"<\": \"<\",\n // See https://mathiasbynens.be/notes/ambiguous-ampersands: in HTML, the\n // following is not strictly necessary unless it’s part of a tag or an\n // unquoted attribute value. We’re only escaping it to support those\n // situations, and for XML support.\n \">\": \">\",\n // In Internet Explorer ≤ 8, the backtick character can be used\n // to break out of (un)quoted attribute values or HTML comments.\n // See http://html5sec.org/#102, http://html5sec.org/#108, and\n // http://html5sec.org/#133.\n \"`\": \"`\"\n };\n var regexInvalidEntity = /&#(?:[xX][^a-fA-F0-9]|[^0-9xX])/;\n var regexInvalidRawCodePoint = /[\\0-\\x08\\x0B\\x0E-\\x1F\\x7F-\\x9F\\uFDD0-\\uFDEF\\uFFFE\\uFFFF]|[\\uD83F\\uD87F\\uD8BF\\uD8FF\\uD93F\\uD97F\\uD9BF\\uD9FF\\uDA3F\\uDA7F\\uDABF\\uDAFF\\uDB3F\\uDB7F\\uDBBF\\uDBFF][\\uDFFE\\uDFFF]|[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?:[^\\uD800-\\uDBFF]|^)[\\uDC00-\\uDFFF]/;\n var regexDecode = /&(CounterClockwiseContourIntegral|DoubleLongLeftRightArrow|ClockwiseContourIntegral|NotNestedGreaterGreater|NotSquareSupersetEqual|DiacriticalDoubleAcute|NotRightTriangleEqual|NotSucceedsSlantEqual|NotPrecedesSlantEqual|CloseCurlyDoubleQuote|NegativeVeryThinSpace|DoubleContourIntegral|FilledVerySmallSquare|CapitalDifferentialD|OpenCurlyDoubleQuote|EmptyVerySmallSquare|NestedGreaterGreater|DoubleLongRightArrow|NotLeftTriangleEqual|NotGreaterSlantEqual|ReverseUpEquilibrium|DoubleLeftRightArrow|NotSquareSubsetEqual|NotDoubleVerticalBar|RightArrowLeftArrow|NotGreaterFullEqual|NotRightTriangleBar|SquareSupersetEqual|DownLeftRightVector|DoubleLongLeftArrow|leftrightsquigarrow|LeftArrowRightArrow|NegativeMediumSpace|blacktriangleright|RightDownVectorBar|PrecedesSlantEqual|RightDoubleBracket|SucceedsSlantEqual|NotLeftTriangleBar|RightTriangleEqual|SquareIntersection|RightDownTeeVector|ReverseEquilibrium|NegativeThickSpace|longleftrightarrow|Longleftrightarrow|LongLeftRightArrow|DownRightTeeVector|DownRightVectorBar|GreaterSlantEqual|SquareSubsetEqual|LeftDownVectorBar|LeftDoubleBracket|VerticalSeparator|rightleftharpoons|NotGreaterGreater|NotSquareSuperset|blacktriangleleft|blacktriangledown|NegativeThinSpace|LeftDownTeeVector|NotLessSlantEqual|leftrightharpoons|DoubleUpDownArrow|DoubleVerticalBar|LeftTriangleEqual|FilledSmallSquare|twoheadrightarrow|NotNestedLessLess|DownLeftTeeVector|DownLeftVectorBar|RightAngleBracket|NotTildeFullEqual|NotReverseElement|RightUpDownVector|DiacriticalTilde|NotSucceedsTilde|circlearrowright|NotPrecedesEqual|rightharpoondown|DoubleRightArrow|NotSucceedsEqual|NonBreakingSpace|NotRightTriangle|LessEqualGreater|RightUpTeeVector|LeftAngleBracket|GreaterFullEqual|DownArrowUpArrow|RightUpVectorBar|twoheadleftarrow|GreaterEqualLess|downharpoonright|RightTriangleBar|ntrianglerighteq|NotSupersetEqual|LeftUpDownVector|DiacriticalAcute|rightrightarrows|vartriangleright|UpArrowDownArrow|DiacriticalGrave|UnderParenthesis|EmptySmallSquare|LeftUpVectorBar|leftrightarrows|DownRightVector|downharpoonleft|trianglerighteq|ShortRightArrow|OverParenthesis|DoubleLeftArrow|DoubleDownArrow|NotSquareSubset|bigtriangledown|ntrianglelefteq|UpperRightArrow|curvearrowright|vartriangleleft|NotLeftTriangle|nleftrightarrow|LowerRightArrow|NotHumpDownHump|NotGreaterTilde|rightthreetimes|LeftUpTeeVector|NotGreaterEqual|straightepsilon|LeftTriangleBar|rightsquigarrow|ContourIntegral|rightleftarrows|CloseCurlyQuote|RightDownVector|LeftRightVector|nLeftrightarrow|leftharpoondown|circlearrowleft|SquareSuperset|OpenCurlyQuote|hookrightarrow|HorizontalLine|DiacriticalDot|NotLessGreater|ntriangleright|DoubleRightTee|InvisibleComma|InvisibleTimes|LowerLeftArrow|DownLeftVector|NotSubsetEqual|curvearrowleft|trianglelefteq|NotVerticalBar|TildeFullEqual|downdownarrows|NotGreaterLess|RightTeeVector|ZeroWidthSpace|looparrowright|LongRightArrow|doublebarwedge|ShortLeftArrow|ShortDownArrow|RightVectorBar|GreaterGreater|ReverseElement|rightharpoonup|LessSlantEqual|leftthreetimes|upharpoonright|rightarrowtail|LeftDownVector|Longrightarrow|NestedLessLess|UpperLeftArrow|nshortparallel|leftleftarrows|leftrightarrow|Leftrightarrow|LeftRightArrow|longrightarrow|upharpoonleft|RightArrowBar|ApplyFunction|LeftTeeVector|leftarrowtail|NotEqualTilde|varsubsetneqq|varsupsetneqq|RightTeeArrow|SucceedsEqual|SucceedsTilde|LeftVectorBar|SupersetEqual|hookleftarrow|DifferentialD|VerticalTilde|VeryThinSpace|blacktriangle|bigtriangleup|LessFullEqual|divideontimes|leftharpoonup|UpEquilibrium|ntriangleleft|RightTriangle|measuredangle|shortparallel|longleftarrow|Longleftarrow|LongLeftArrow|DoubleLeftTee|Poincareplane|PrecedesEqual|triangleright|DoubleUpArrow|RightUpVector|fallingdotseq|looparrowleft|PrecedesTilde|NotTildeEqual|NotTildeTilde|smallsetminus|Proportional|triangleleft|triangledown|UnderBracket|NotHumpEqual|exponentiale|ExponentialE|NotLessTilde|HilbertSpace|RightCeiling|blacklozenge|varsupsetneq|HumpDownHump|GreaterEqual|VerticalLine|LeftTeeArrow|NotLessEqual|DownTeeArrow|LeftTriangle|varsubsetneq|Intersection|NotCongruent|DownArrowBar|LeftUpVector|LeftArrowBar|risingdotseq|GreaterTilde|RoundImplies|SquareSubset|ShortUpArrow|NotSuperset|quaternions|precnapprox|backepsilon|preccurlyeq|OverBracket|blacksquare|MediumSpace|VerticalBar|circledcirc|circleddash|CircleMinus|CircleTimes|LessGreater|curlyeqprec|curlyeqsucc|diamondsuit|UpDownArrow|Updownarrow|RuleDelayed|Rrightarrow|updownarrow|RightVector|nRightarrow|nrightarrow|eqslantless|LeftCeiling|Equilibrium|SmallCircle|expectation|NotSucceeds|thickapprox|GreaterLess|SquareUnion|NotPrecedes|NotLessLess|straightphi|succnapprox|succcurlyeq|SubsetEqual|sqsupseteq|Proportion|Laplacetrf|ImaginaryI|supsetneqq|NotGreater|gtreqqless|NotElement|ThickSpace|TildeEqual|TildeTilde|Fouriertrf|rmoustache|EqualTilde|eqslantgtr|UnderBrace|LeftVector|UpArrowBar|nLeftarrow|nsubseteqq|subsetneqq|nsupseteqq|nleftarrow|succapprox|lessapprox|UpTeeArrow|upuparrows|curlywedge|lesseqqgtr|varepsilon|varnothing|RightFloor|complement|CirclePlus|sqsubseteq|Lleftarrow|circledast|RightArrow|Rightarrow|rightarrow|lmoustache|Bernoullis|precapprox|mapstoleft|mapstodown|longmapsto|dotsquare|downarrow|DoubleDot|nsubseteq|supsetneq|leftarrow|nsupseteq|subsetneq|ThinSpace|ngeqslant|subseteqq|HumpEqual|NotSubset|triangleq|NotCupCap|lesseqgtr|heartsuit|TripleDot|Leftarrow|Coproduct|Congruent|varpropto|complexes|gvertneqq|LeftArrow|LessTilde|supseteqq|MinusPlus|CircleDot|nleqslant|NotExists|gtreqless|nparallel|UnionPlus|LeftFloor|checkmark|CenterDot|centerdot|Mellintrf|gtrapprox|bigotimes|OverBrace|spadesuit|therefore|pitchfork|rationals|PlusMinus|Backslash|Therefore|DownBreve|backsimeq|backprime|DownArrow|nshortmid|Downarrow|lvertneqq|eqvparsl|imagline|imagpart|infintie|integers|Integral|intercal|LessLess|Uarrocir|intlarhk|sqsupset|angmsdaf|sqsubset|llcorner|vartheta|cupbrcap|lnapprox|Superset|SuchThat|succnsim|succneqq|angmsdag|biguplus|curlyvee|trpezium|Succeeds|NotTilde|bigwedge|angmsdah|angrtvbd|triminus|cwconint|fpartint|lrcorner|smeparsl|subseteq|urcorner|lurdshar|laemptyv|DDotrahd|approxeq|ldrushar|awconint|mapstoup|backcong|shortmid|triangle|geqslant|gesdotol|timesbar|circledR|circledS|setminus|multimap|naturals|scpolint|ncongdot|RightTee|boxminus|gnapprox|boxtimes|andslope|thicksim|angmsdaa|varsigma|cirfnint|rtriltri|angmsdab|rppolint|angmsdac|barwedge|drbkarow|clubsuit|thetasym|bsolhsub|capbrcup|dzigrarr|doteqdot|DotEqual|dotminus|UnderBar|NotEqual|realpart|otimesas|ulcorner|hksearow|hkswarow|parallel|PartialD|elinters|emptyset|plusacir|bbrktbrk|angmsdad|pointint|bigoplus|angmsdae|Precedes|bigsqcup|varkappa|notindot|supseteq|precneqq|precnsim|profalar|profline|profsurf|leqslant|lesdotor|raemptyv|subplus|notnivb|notnivc|subrarr|zigrarr|vzigzag|submult|subedot|Element|between|cirscir|larrbfs|larrsim|lotimes|lbrksld|lbrkslu|lozenge|ldrdhar|dbkarow|bigcirc|epsilon|simrarr|simplus|ltquest|Epsilon|luruhar|gtquest|maltese|npolint|eqcolon|npreceq|bigodot|ddagger|gtrless|bnequiv|harrcir|ddotseq|equivDD|backsim|demptyv|nsqsube|nsqsupe|Upsilon|nsubset|upsilon|minusdu|nsucceq|swarrow|nsupset|coloneq|searrow|boxplus|napprox|natural|asympeq|alefsym|congdot|nearrow|bigstar|diamond|supplus|tritime|LeftTee|nvinfin|triplus|NewLine|nvltrie|nvrtrie|nwarrow|nexists|Diamond|ruluhar|Implies|supmult|angzarr|suplarr|suphsub|questeq|because|digamma|Because|olcross|bemptyv|omicron|Omicron|rotimes|NoBreak|intprod|angrtvb|orderof|uwangle|suphsol|lesdoto|orslope|DownTee|realine|cudarrl|rdldhar|OverBar|supedot|lessdot|supdsub|topfork|succsim|rbrkslu|rbrksld|pertenk|cudarrr|isindot|planckh|lessgtr|pluscir|gesdoto|plussim|plustwo|lesssim|cularrp|rarrsim|Cayleys|notinva|notinvb|notinvc|UpArrow|Uparrow|uparrow|NotLess|dwangle|precsim|Product|curarrm|Cconint|dotplus|rarrbfs|ccupssm|Cedilla|cemptyv|notniva|quatint|frac35|frac38|frac45|frac56|frac58|frac78|tridot|xoplus|gacute|gammad|Gammad|lfisht|lfloor|bigcup|sqsupe|gbreve|Gbreve|lharul|sqsube|sqcups|Gcedil|apacir|llhard|lmidot|Lmidot|lmoust|andand|sqcaps|approx|Abreve|spades|circeq|tprime|divide|topcir|Assign|topbot|gesdot|divonx|xuplus|timesd|gesles|atilde|solbar|SOFTcy|loplus|timesb|lowast|lowbar|dlcorn|dlcrop|softcy|dollar|lparlt|thksim|lrhard|Atilde|lsaquo|smashp|bigvee|thinsp|wreath|bkarow|lsquor|lstrok|Lstrok|lthree|ltimes|ltlarr|DotDot|simdot|ltrPar|weierp|xsqcup|angmsd|sigmav|sigmaf|zeetrf|Zcaron|zcaron|mapsto|vsupne|thetav|cirmid|marker|mcomma|Zacute|vsubnE|there4|gtlPar|vsubne|bottom|gtrarr|SHCHcy|shchcy|midast|midcir|middot|minusb|minusd|gtrdot|bowtie|sfrown|mnplus|models|colone|seswar|Colone|mstpos|searhk|gtrsim|nacute|Nacute|boxbox|telrec|hairsp|Tcedil|nbumpe|scnsim|ncaron|Ncaron|ncedil|Ncedil|hamilt|Scedil|nearhk|hardcy|HARDcy|tcedil|Tcaron|commat|nequiv|nesear|tcaron|target|hearts|nexist|varrho|scedil|Scaron|scaron|hellip|Sacute|sacute|hercon|swnwar|compfn|rtimes|rthree|rsquor|rsaquo|zacute|wedgeq|homtht|barvee|barwed|Barwed|rpargt|horbar|conint|swarhk|roplus|nltrie|hslash|hstrok|Hstrok|rmoust|Conint|bprime|hybull|hyphen|iacute|Iacute|supsup|supsub|supsim|varphi|coprod|brvbar|agrave|Supset|supset|igrave|Igrave|notinE|Agrave|iiiint|iinfin|copysr|wedbar|Verbar|vangrt|becaus|incare|verbar|inodot|bullet|drcorn|intcal|drcrop|cularr|vellip|Utilde|bumpeq|cupcap|dstrok|Dstrok|CupCap|cupcup|cupdot|eacute|Eacute|supdot|iquest|easter|ecaron|Ecaron|ecolon|isinsv|utilde|itilde|Itilde|curarr|succeq|Bumpeq|cacute|ulcrop|nparsl|Cacute|nprcue|egrave|Egrave|nrarrc|nrarrw|subsup|subsub|nrtrie|jsercy|nsccue|Jsercy|kappav|kcedil|Kcedil|subsim|ulcorn|nsimeq|egsdot|veebar|kgreen|capand|elsdot|Subset|subset|curren|aacute|lacute|Lacute|emptyv|ntilde|Ntilde|lagran|lambda|Lambda|capcap|Ugrave|langle|subdot|emsp13|numero|emsp14|nvdash|nvDash|nVdash|nVDash|ugrave|ufisht|nvHarr|larrfs|nvlArr|larrhk|larrlp|larrpl|nvrArr|Udblac|nwarhk|larrtl|nwnear|oacute|Oacute|latail|lAtail|sstarf|lbrace|odblac|Odblac|lbrack|udblac|odsold|eparsl|lcaron|Lcaron|ograve|Ograve|lcedil|Lcedil|Aacute|ssmile|ssetmn|squarf|ldquor|capcup|ominus|cylcty|rharul|eqcirc|dagger|rfloor|rfisht|Dagger|daleth|equals|origof|capdot|equest|dcaron|Dcaron|rdquor|oslash|Oslash|otilde|Otilde|otimes|Otimes|urcrop|Ubreve|ubreve|Yacute|Uacute|uacute|Rcedil|rcedil|urcorn|parsim|Rcaron|Vdashl|rcaron|Tstrok|percnt|period|permil|Exists|yacute|rbrack|rbrace|phmmat|ccaron|Ccaron|planck|ccedil|plankv|tstrok|female|plusdo|plusdu|ffilig|plusmn|ffllig|Ccedil|rAtail|dfisht|bernou|ratail|Rarrtl|rarrtl|angsph|rarrpl|rarrlp|rarrhk|xwedge|xotime|forall|ForAll|Vvdash|vsupnE|preceq|bigcap|frac12|frac13|frac14|primes|rarrfs|prnsim|frac15|Square|frac16|square|lesdot|frac18|frac23|propto|prurel|rarrap|rangle|puncsp|frac25|Racute|qprime|racute|lesges|frac34|abreve|AElig|eqsim|utdot|setmn|urtri|Equal|Uring|seArr|uring|searr|dashv|Dashv|mumap|nabla|iogon|Iogon|sdote|sdotb|scsim|napid|napos|equiv|natur|Acirc|dblac|erarr|nbump|iprod|erDot|ucirc|awint|esdot|angrt|ncong|isinE|scnap|Scirc|scirc|ndash|isins|Ubrcy|nearr|neArr|isinv|nedot|ubrcy|acute|Ycirc|iukcy|Iukcy|xutri|nesim|caret|jcirc|Jcirc|caron|twixt|ddarr|sccue|exist|jmath|sbquo|ngeqq|angst|ccaps|lceil|ngsim|UpTee|delta|Delta|rtrif|nharr|nhArr|nhpar|rtrie|jukcy|Jukcy|kappa|rsquo|Kappa|nlarr|nlArr|TSHcy|rrarr|aogon|Aogon|fflig|xrarr|tshcy|ccirc|nleqq|filig|upsih|nless|dharl|nlsim|fjlig|ropar|nltri|dharr|robrk|roarr|fllig|fltns|roang|rnmid|subnE|subne|lAarr|trisb|Ccirc|acirc|ccups|blank|VDash|forkv|Vdash|langd|cedil|blk12|blk14|laquo|strns|diams|notin|vDash|larrb|blk34|block|disin|uplus|vdash|vBarv|aelig|starf|Wedge|check|xrArr|lates|lbarr|lBarr|notni|lbbrk|bcong|frasl|lbrke|frown|vrtri|vprop|vnsup|gamma|Gamma|wedge|xodot|bdquo|srarr|doteq|ldquo|boxdl|boxdL|gcirc|Gcirc|boxDl|boxDL|boxdr|boxdR|boxDr|TRADE|trade|rlhar|boxDR|vnsub|npart|vltri|rlarr|boxhd|boxhD|nprec|gescc|nrarr|nrArr|boxHd|boxHD|boxhu|boxhU|nrtri|boxHu|clubs|boxHU|times|colon|Colon|gimel|xlArr|Tilde|nsime|tilde|nsmid|nspar|THORN|thorn|xlarr|nsube|nsubE|thkap|xhArr|comma|nsucc|boxul|boxuL|nsupe|nsupE|gneqq|gnsim|boxUl|boxUL|grave|boxur|boxuR|boxUr|boxUR|lescc|angle|bepsi|boxvh|varpi|boxvH|numsp|Theta|gsime|gsiml|theta|boxVh|boxVH|boxvl|gtcir|gtdot|boxvL|boxVl|boxVL|crarr|cross|Cross|nvsim|boxvr|nwarr|nwArr|sqsup|dtdot|Uogon|lhard|lharu|dtrif|ocirc|Ocirc|lhblk|duarr|odash|sqsub|Hacek|sqcup|llarr|duhar|oelig|OElig|ofcir|boxvR|uogon|lltri|boxVr|csube|uuarr|ohbar|csupe|ctdot|olarr|olcir|harrw|oline|sqcap|omacr|Omacr|omega|Omega|boxVR|aleph|lneqq|lnsim|loang|loarr|rharu|lobrk|hcirc|operp|oplus|rhard|Hcirc|orarr|Union|order|ecirc|Ecirc|cuepr|szlig|cuesc|breve|reals|eDDot|Breve|hoarr|lopar|utrif|rdquo|Umacr|umacr|efDot|swArr|ultri|alpha|rceil|ovbar|swarr|Wcirc|wcirc|smtes|smile|bsemi|lrarr|aring|parsl|lrhar|bsime|uhblk|lrtri|cupor|Aring|uharr|uharl|slarr|rbrke|bsolb|lsime|rbbrk|RBarr|lsimg|phone|rBarr|rbarr|icirc|lsquo|Icirc|emacr|Emacr|ratio|simne|plusb|simlE|simgE|simeq|pluse|ltcir|ltdot|empty|xharr|xdtri|iexcl|Alpha|ltrie|rarrw|pound|ltrif|xcirc|bumpe|prcue|bumpE|asymp|amacr|cuvee|Sigma|sigma|iiint|udhar|iiota|ijlig|IJlig|supnE|imacr|Imacr|prime|Prime|image|prnap|eogon|Eogon|rarrc|mdash|mDDot|cuwed|imath|supne|imped|Amacr|udarr|prsim|micro|rarrb|cwint|raquo|infin|eplus|range|rangd|Ucirc|radic|minus|amalg|veeeq|rAarr|epsiv|ycirc|quest|sharp|quot|zwnj|Qscr|race|qscr|Qopf|qopf|qint|rang|Rang|Zscr|zscr|Zopf|zopf|rarr|rArr|Rarr|Pscr|pscr|prop|prod|prnE|prec|ZHcy|zhcy|prap|Zeta|zeta|Popf|popf|Zdot|plus|zdot|Yuml|yuml|phiv|YUcy|yucy|Yscr|yscr|perp|Yopf|yopf|part|para|YIcy|Ouml|rcub|yicy|YAcy|rdca|ouml|osol|Oscr|rdsh|yacy|real|oscr|xvee|andd|rect|andv|Xscr|oror|ordm|ordf|xscr|ange|aopf|Aopf|rHar|Xopf|opar|Oopf|xopf|xnis|rhov|oopf|omid|xmap|oint|apid|apos|ogon|ascr|Ascr|odot|odiv|xcup|xcap|ocir|oast|nvlt|nvle|nvgt|nvge|nvap|Wscr|wscr|auml|ntlg|ntgl|nsup|nsub|nsim|Nscr|nscr|nsce|Wopf|ring|npre|wopf|npar|Auml|Barv|bbrk|Nopf|nopf|nmid|nLtv|beta|ropf|Ropf|Beta|beth|nles|rpar|nleq|bnot|bNot|nldr|NJcy|rscr|Rscr|Vscr|vscr|rsqb|njcy|bopf|nisd|Bopf|rtri|Vopf|nGtv|ngtr|vopf|boxh|boxH|boxv|nges|ngeq|boxV|bscr|scap|Bscr|bsim|Vert|vert|bsol|bull|bump|caps|cdot|ncup|scnE|ncap|nbsp|napE|Cdot|cent|sdot|Vbar|nang|vBar|chcy|Mscr|mscr|sect|semi|CHcy|Mopf|mopf|sext|circ|cire|mldr|mlcp|cirE|comp|shcy|SHcy|vArr|varr|cong|copf|Copf|copy|COPY|malt|male|macr|lvnE|cscr|ltri|sime|ltcc|simg|Cscr|siml|csub|Uuml|lsqb|lsim|uuml|csup|Lscr|lscr|utri|smid|lpar|cups|smte|lozf|darr|Lopf|Uscr|solb|lopf|sopf|Sopf|lneq|uscr|spar|dArr|lnap|Darr|dash|Sqrt|LJcy|ljcy|lHar|dHar|Upsi|upsi|diam|lesg|djcy|DJcy|leqq|dopf|Dopf|dscr|Dscr|dscy|ldsh|ldca|squf|DScy|sscr|Sscr|dsol|lcub|late|star|Star|Uopf|Larr|lArr|larr|uopf|dtri|dzcy|sube|subE|Lang|lang|Kscr|kscr|Kopf|kopf|KJcy|kjcy|KHcy|khcy|DZcy|ecir|edot|eDot|Jscr|jscr|succ|Jopf|jopf|Edot|uHar|emsp|ensp|Iuml|iuml|eopf|isin|Iscr|iscr|Eopf|epar|sung|epsi|escr|sup1|sup2|sup3|Iota|iota|supe|supE|Iopf|iopf|IOcy|iocy|Escr|esim|Esim|imof|Uarr|QUOT|uArr|uarr|euml|IEcy|iecy|Idot|Euml|euro|excl|Hscr|hscr|Hopf|hopf|TScy|tscy|Tscr|hbar|tscr|flat|tbrk|fnof|hArr|harr|half|fopf|Fopf|tdot|gvnE|fork|trie|gtcc|fscr|Fscr|gdot|gsim|Gscr|gscr|Gopf|gopf|gneq|Gdot|tosa|gnap|Topf|topf|geqq|toea|GJcy|gjcy|tint|gesl|mid|Sfr|ggg|top|ges|gla|glE|glj|geq|gne|gEl|gel|gnE|Gcy|gcy|gap|Tfr|tfr|Tcy|tcy|Hat|Tau|Ffr|tau|Tab|hfr|Hfr|ffr|Fcy|fcy|icy|Icy|iff|ETH|eth|ifr|Ifr|Eta|eta|int|Int|Sup|sup|ucy|Ucy|Sum|sum|jcy|ENG|ufr|Ufr|eng|Jcy|jfr|els|ell|egs|Efr|efr|Jfr|uml|kcy|Kcy|Ecy|ecy|kfr|Kfr|lap|Sub|sub|lat|lcy|Lcy|leg|Dot|dot|lEg|leq|les|squ|div|die|lfr|Lfr|lgE|Dfr|dfr|Del|deg|Dcy|dcy|lne|lnE|sol|loz|smt|Cup|lrm|cup|lsh|Lsh|sim|shy|map|Map|mcy|Mcy|mfr|Mfr|mho|gfr|Gfr|sfr|cir|Chi|chi|nap|Cfr|vcy|Vcy|cfr|Scy|scy|ncy|Ncy|vee|Vee|Cap|cap|nfr|scE|sce|Nfr|nge|ngE|nGg|vfr|Vfr|ngt|bot|nGt|nis|niv|Rsh|rsh|nle|nlE|bne|Bfr|bfr|nLl|nlt|nLt|Bcy|bcy|not|Not|rlm|wfr|Wfr|npr|nsc|num|ocy|ast|Ocy|ofr|xfr|Xfr|Ofr|ogt|ohm|apE|olt|Rho|ape|rho|Rfr|rfr|ord|REG|ang|reg|orv|And|and|AMP|Rcy|amp|Afr|ycy|Ycy|yen|yfr|Yfr|rcy|par|pcy|Pcy|pfr|Pfr|phi|Phi|afr|Acy|acy|zcy|Zcy|piv|acE|acd|zfr|Zfr|pre|prE|psi|Psi|qfr|Qfr|zwj|Or|ge|Gg|gt|gg|el|oS|lt|Lt|LT|Re|lg|gl|eg|ne|Im|it|le|DD|wp|wr|nu|Nu|dd|lE|Sc|sc|pi|Pi|ee|af|ll|Ll|rx|gE|xi|pm|Xi|ic|pr|Pr|in|ni|mp|mu|ac|Mu|or|ap|Gt|GT|ii);|&(Aacute|Agrave|Atilde|Ccedil|Eacute|Egrave|Iacute|Igrave|Ntilde|Oacute|Ograve|Oslash|Otilde|Uacute|Ugrave|Yacute|aacute|agrave|atilde|brvbar|ccedil|curren|divide|eacute|egrave|frac12|frac14|frac34|iacute|igrave|iquest|middot|ntilde|oacute|ograve|oslash|otilde|plusmn|uacute|ugrave|yacute|AElig|Acirc|Aring|Ecirc|Icirc|Ocirc|THORN|Ucirc|acirc|acute|aelig|aring|cedil|ecirc|icirc|iexcl|laquo|micro|ocirc|pound|raquo|szlig|thorn|times|ucirc|Auml|COPY|Euml|Iuml|Ouml|QUOT|Uuml|auml|cent|copy|euml|iuml|macr|nbsp|ordf|ordm|ouml|para|quot|sect|sup1|sup2|sup3|uuml|yuml|AMP|ETH|REG|amp|deg|eth|not|reg|shy|uml|yen|GT|LT|gt|lt)(?!;)([=a-zA-Z0-9]?)|&#([0-9]+)(;?)|&#[xX]([a-fA-F0-9]+)(;?)|&([0-9a-zA-Z]+)/g;\n var decodeMap2 = { \"aacute\": \"á\", \"Aacute\": \"Á\", \"abreve\": \"ă\", \"Abreve\": \"Ă\", \"ac\": \"∾\", \"acd\": \"∿\", \"acE\": \"∾̳\", \"acirc\": \"â\", \"Acirc\": \"Â\", \"acute\": \"´\", \"acy\": \"а\", \"Acy\": \"А\", \"aelig\": \"æ\", \"AElig\": \"Æ\", \"af\": \"⁡\", \"afr\": \"𝔞\", \"Afr\": \"𝔄\", \"agrave\": \"à\", \"Agrave\": \"À\", \"alefsym\": \"ℵ\", \"aleph\": \"ℵ\", \"alpha\": \"α\", \"Alpha\": \"Α\", \"amacr\": \"ā\", \"Amacr\": \"Ā\", \"amalg\": \"⨿\", \"amp\": \"&\", \"AMP\": \"&\", \"and\": \"∧\", \"And\": \"⩓\", \"andand\": \"⩕\", \"andd\": \"⩜\", \"andslope\": \"⩘\", \"andv\": \"⩚\", \"ang\": \"∠\", \"ange\": \"⦤\", \"angle\": \"∠\", \"angmsd\": \"∡\", \"angmsdaa\": \"⦨\", \"angmsdab\": \"⦩\", \"angmsdac\": \"⦪\", \"angmsdad\": \"⦫\", \"angmsdae\": \"⦬\", \"angmsdaf\": \"⦭\", \"angmsdag\": \"⦮\", \"angmsdah\": \"⦯\", \"angrt\": \"∟\", \"angrtvb\": \"⊾\", \"angrtvbd\": \"⦝\", \"angsph\": \"∢\", \"angst\": \"Å\", \"angzarr\": \"⍼\", \"aogon\": \"ą\", \"Aogon\": \"Ą\", \"aopf\": \"𝕒\", \"Aopf\": \"𝔸\", \"ap\": \"≈\", \"apacir\": \"⩯\", \"ape\": \"≊\", \"apE\": \"⩰\", \"apid\": \"≋\", \"apos\": \"'\", \"ApplyFunction\": \"⁡\", \"approx\": \"≈\", \"approxeq\": \"≊\", \"aring\": \"å\", \"Aring\": \"Å\", \"ascr\": \"𝒶\", \"Ascr\": \"𝒜\", \"Assign\": \"≔\", \"ast\": \"*\", \"asymp\": \"≈\", \"asympeq\": \"≍\", \"atilde\": \"ã\", \"Atilde\": \"Ã\", \"auml\": \"ä\", \"Auml\": \"Ä\", \"awconint\": \"∳\", \"awint\": \"⨑\", \"backcong\": \"≌\", \"backepsilon\": \"϶\", \"backprime\": \"‵\", \"backsim\": \"∽\", \"backsimeq\": \"⋍\", \"Backslash\": \"∖\", \"Barv\": \"⫧\", \"barvee\": \"⊽\", \"barwed\": \"⌅\", \"Barwed\": \"⌆\", \"barwedge\": \"⌅\", \"bbrk\": \"⎵\", \"bbrktbrk\": \"⎶\", \"bcong\": \"≌\", \"bcy\": \"б\", \"Bcy\": \"Б\", \"bdquo\": \"„\", \"becaus\": \"∵\", \"because\": \"∵\", \"Because\": \"∵\", \"bemptyv\": \"⦰\", \"bepsi\": \"϶\", \"bernou\": \"ℬ\", \"Bernoullis\": \"ℬ\", \"beta\": \"β\", \"Beta\": \"Β\", \"beth\": \"ℶ\", \"between\": \"≬\", \"bfr\": \"𝔟\", \"Bfr\": \"𝔅\", \"bigcap\": \"⋂\", \"bigcirc\": \"◯\", \"bigcup\": \"⋃\", \"bigodot\": \"⨀\", \"bigoplus\": \"⨁\", \"bigotimes\": \"⨂\", \"bigsqcup\": \"⨆\", \"bigstar\": \"★\", \"bigtriangledown\": \"▽\", \"bigtriangleup\": \"△\", \"biguplus\": \"⨄\", \"bigvee\": \"⋁\", \"bigwedge\": \"⋀\", \"bkarow\": \"⤍\", \"blacklozenge\": \"⧫\", \"blacksquare\": \"▪\", \"blacktriangle\": \"▴\", \"blacktriangledown\": \"▾\", \"blacktriangleleft\": \"◂\", \"blacktriangleright\": \"▸\", \"blank\": \"␣\", \"blk12\": \"▒\", \"blk14\": \"░\", \"blk34\": \"▓\", \"block\": \"█\", \"bne\": \"=⃥\", \"bnequiv\": \"≡⃥\", \"bnot\": \"⌐\", \"bNot\": \"⫭\", \"bopf\": \"𝕓\", \"Bopf\": \"𝔹\", \"bot\": \"⊥\", \"bottom\": \"⊥\", \"bowtie\": \"⋈\", \"boxbox\": \"⧉\", \"boxdl\": \"┐\", \"boxdL\": \"╕\", \"boxDl\": \"╖\", \"boxDL\": \"╗\", \"boxdr\": \"┌\", \"boxdR\": \"╒\", \"boxDr\": \"╓\", \"boxDR\": \"╔\", \"boxh\": \"─\", \"boxH\": \"═\", \"boxhd\": \"┬\", \"boxhD\": \"╥\", \"boxHd\": \"╤\", \"boxHD\": \"╦\", \"boxhu\": \"┴\", \"boxhU\": \"╨\", \"boxHu\": \"╧\", \"boxHU\": \"╩\", \"boxminus\": \"⊟\", \"boxplus\": \"⊞\", \"boxtimes\": \"⊠\", \"boxul\": \"┘\", \"boxuL\": \"╛\", \"boxUl\": \"╜\", \"boxUL\": \"╝\", \"boxur\": \"└\", \"boxuR\": \"╘\", \"boxUr\": \"╙\", \"boxUR\": \"╚\", \"boxv\": \"│\", \"boxV\": \"║\", \"boxvh\": \"┼\", \"boxvH\": \"╪\", \"boxVh\": \"╫\", \"boxVH\": \"╬\", \"boxvl\": \"┤\", \"boxvL\": \"╡\", \"boxVl\": \"╢\", \"boxVL\": \"╣\", \"boxvr\": \"├\", \"boxvR\": \"╞\", \"boxVr\": \"╟\", \"boxVR\": \"╠\", \"bprime\": \"‵\", \"breve\": \"˘\", \"Breve\": \"˘\", \"brvbar\": \"¦\", \"bscr\": \"𝒷\", \"Bscr\": \"ℬ\", \"bsemi\": \"⁏\", \"bsim\": \"∽\", \"bsime\": \"⋍\", \"bsol\": \"\\\\\", \"bsolb\": \"⧅\", \"bsolhsub\": \"⟈\", \"bull\": \"•\", \"bullet\": \"•\", \"bump\": \"≎\", \"bumpe\": \"≏\", \"bumpE\": \"⪮\", \"bumpeq\": \"≏\", \"Bumpeq\": \"≎\", \"cacute\": \"ć\", \"Cacute\": \"Ć\", \"cap\": \"∩\", \"Cap\": \"⋒\", \"capand\": \"⩄\", \"capbrcup\": \"⩉\", \"capcap\": \"⩋\", \"capcup\": \"⩇\", \"capdot\": \"⩀\", \"CapitalDifferentialD\": \"ⅅ\", \"caps\": \"∩︀\", \"caret\": \"⁁\", \"caron\": \"ˇ\", \"Cayleys\": \"ℭ\", \"ccaps\": \"⩍\", \"ccaron\": \"č\", \"Ccaron\": \"Č\", \"ccedil\": \"ç\", \"Ccedil\": \"Ç\", \"ccirc\": \"ĉ\", \"Ccirc\": \"Ĉ\", \"Cconint\": \"∰\", \"ccups\": \"⩌\", \"ccupssm\": \"⩐\", \"cdot\": \"ċ\", \"Cdot\": \"Ċ\", \"cedil\": \"¸\", \"Cedilla\": \"¸\", \"cemptyv\": \"⦲\", \"cent\": \"¢\", \"centerdot\": \"·\", \"CenterDot\": \"·\", \"cfr\": \"𝔠\", \"Cfr\": \"ℭ\", \"chcy\": \"ч\", \"CHcy\": \"Ч\", \"check\": \"✓\", \"checkmark\": \"✓\", \"chi\": \"χ\", \"Chi\": \"Χ\", \"cir\": \"○\", \"circ\": \"ˆ\", \"circeq\": \"≗\", \"circlearrowleft\": \"↺\", \"circlearrowright\": \"↻\", \"circledast\": \"⊛\", \"circledcirc\": \"⊚\", \"circleddash\": \"⊝\", \"CircleDot\": \"⊙\", \"circledR\": \"®\", \"circledS\": \"Ⓢ\", \"CircleMinus\": \"⊖\", \"CirclePlus\": \"⊕\", \"CircleTimes\": \"⊗\", \"cire\": \"≗\", \"cirE\": \"⧃\", \"cirfnint\": \"⨐\", \"cirmid\": \"⫯\", \"cirscir\": \"⧂\", \"ClockwiseContourIntegral\": \"∲\", \"CloseCurlyDoubleQuote\": \"”\", \"CloseCurlyQuote\": \"’\", \"clubs\": \"♣\", \"clubsuit\": \"♣\", \"colon\": \":\", \"Colon\": \"∷\", \"colone\": \"≔\", \"Colone\": \"⩴\", \"coloneq\": \"≔\", \"comma\": \",\", \"commat\": \"@\", \"comp\": \"∁\", \"compfn\": \"∘\", \"complement\": \"∁\", \"complexes\": \"ℂ\", \"cong\": \"≅\", \"congdot\": \"⩭\", \"Congruent\": \"≡\", \"conint\": \"∮\", \"Conint\": \"∯\", \"ContourIntegral\": \"∮\", \"copf\": \"𝕔\", \"Copf\": \"ℂ\", \"coprod\": \"∐\", \"Coproduct\": \"∐\", \"copy\": \"©\", \"COPY\": \"©\", \"copysr\": \"℗\", \"CounterClockwiseContourIntegral\": \"∳\", \"crarr\": \"↵\", \"cross\": \"✗\", \"Cross\": \"⨯\", \"cscr\": \"𝒸\", \"Cscr\": \"𝒞\", \"csub\": \"⫏\", \"csube\": \"⫑\", \"csup\": \"⫐\", \"csupe\": \"⫒\", \"ctdot\": \"⋯\", \"cudarrl\": \"⤸\", \"cudarrr\": \"⤵\", \"cuepr\": \"⋞\", \"cuesc\": \"⋟\", \"cularr\": \"↶\", \"cularrp\": \"⤽\", \"cup\": \"∪\", \"Cup\": \"⋓\", \"cupbrcap\": \"⩈\", \"cupcap\": \"⩆\", \"CupCap\": \"≍\", \"cupcup\": \"⩊\", \"cupdot\": \"⊍\", \"cupor\": \"⩅\", \"cups\": \"∪︀\", \"curarr\": \"↷\", \"curarrm\": \"⤼\", \"curlyeqprec\": \"⋞\", \"curlyeqsucc\": \"⋟\", \"curlyvee\": \"⋎\", \"curlywedge\": \"⋏\", \"curren\": \"¤\", \"curvearrowleft\": \"↶\", \"curvearrowright\": \"↷\", \"cuvee\": \"⋎\", \"cuwed\": \"⋏\", \"cwconint\": \"∲\", \"cwint\": \"∱\", \"cylcty\": \"⌭\", \"dagger\": \"†\", \"Dagger\": \"‡\", \"daleth\": \"ℸ\", \"darr\": \"↓\", \"dArr\": \"⇓\", \"Darr\": \"↡\", \"dash\": \"‐\", \"dashv\": \"⊣\", \"Dashv\": \"⫤\", \"dbkarow\": \"⤏\", \"dblac\": \"˝\", \"dcaron\": \"ď\", \"Dcaron\": \"Ď\", \"dcy\": \"д\", \"Dcy\": \"Д\", \"dd\": \"ⅆ\", \"DD\": \"ⅅ\", \"ddagger\": \"‡\", \"ddarr\": \"⇊\", \"DDotrahd\": \"⤑\", \"ddotseq\": \"⩷\", \"deg\": \"°\", \"Del\": \"∇\", \"delta\": \"δ\", \"Delta\": \"Δ\", \"demptyv\": \"⦱\", \"dfisht\": \"⥿\", \"dfr\": \"𝔡\", \"Dfr\": \"𝔇\", \"dHar\": \"⥥\", \"dharl\": \"⇃\", \"dharr\": \"⇂\", \"DiacriticalAcute\": \"´\", \"DiacriticalDot\": \"˙\", \"DiacriticalDoubleAcute\": \"˝\", \"DiacriticalGrave\": \"`\", \"DiacriticalTilde\": \"˜\", \"diam\": \"⋄\", \"diamond\": \"⋄\", \"Diamond\": \"⋄\", \"diamondsuit\": \"♦\", \"diams\": \"♦\", \"die\": \"¨\", \"DifferentialD\": \"ⅆ\", \"digamma\": \"ϝ\", \"disin\": \"⋲\", \"div\": \"÷\", \"divide\": \"÷\", \"divideontimes\": \"⋇\", \"divonx\": \"⋇\", \"djcy\": \"ђ\", \"DJcy\": \"Ђ\", \"dlcorn\": \"⌞\", \"dlcrop\": \"⌍\", \"dollar\": \"$\", \"dopf\": \"𝕕\", \"Dopf\": \"𝔻\", \"dot\": \"˙\", \"Dot\": \"¨\", \"DotDot\": \"⃜\", \"doteq\": \"≐\", \"doteqdot\": \"≑\", \"DotEqual\": \"≐\", \"dotminus\": \"∸\", \"dotplus\": \"∔\", \"dotsquare\": \"⊡\", \"doublebarwedge\": \"⌆\", \"DoubleContourIntegral\": \"∯\", \"DoubleDot\": \"¨\", \"DoubleDownArrow\": \"⇓\", \"DoubleLeftArrow\": \"⇐\", \"DoubleLeftRightArrow\": \"⇔\", \"DoubleLeftTee\": \"⫤\", \"DoubleLongLeftArrow\": \"⟸\", \"DoubleLongLeftRightArrow\": \"⟺\", \"DoubleLongRightArrow\": \"⟹\", \"DoubleRightArrow\": \"⇒\", \"DoubleRightTee\": \"⊨\", \"DoubleUpArrow\": \"⇑\", \"DoubleUpDownArrow\": \"⇕\", \"DoubleVerticalBar\": \"∥\", \"downarrow\": \"↓\", \"Downarrow\": \"⇓\", \"DownArrow\": \"↓\", \"DownArrowBar\": \"⤓\", \"DownArrowUpArrow\": \"⇵\", \"DownBreve\": \"̑\", \"downdownarrows\": \"⇊\", \"downharpoonleft\": \"⇃\", \"downharpoonright\": \"⇂\", \"DownLeftRightVector\": \"⥐\", \"DownLeftTeeVector\": \"⥞\", \"DownLeftVector\": \"↽\", \"DownLeftVectorBar\": \"⥖\", \"DownRightTeeVector\": \"⥟\", \"DownRightVector\": \"⇁\", \"DownRightVectorBar\": \"⥗\", \"DownTee\": \"⊤\", \"DownTeeArrow\": \"↧\", \"drbkarow\": \"⤐\", \"drcorn\": \"⌟\", \"drcrop\": \"⌌\", \"dscr\": \"𝒹\", \"Dscr\": \"𝒟\", \"dscy\": \"ѕ\", \"DScy\": \"Ѕ\", \"dsol\": \"⧶\", \"dstrok\": \"đ\", \"Dstrok\": \"Đ\", \"dtdot\": \"⋱\", \"dtri\": \"▿\", \"dtrif\": \"▾\", \"duarr\": \"⇵\", \"duhar\": \"⥯\", \"dwangle\": \"⦦\", \"dzcy\": \"џ\", \"DZcy\": \"Џ\", \"dzigrarr\": \"⟿\", \"eacute\": \"é\", \"Eacute\": \"É\", \"easter\": \"⩮\", \"ecaron\": \"ě\", \"Ecaron\": \"Ě\", \"ecir\": \"≖\", \"ecirc\": \"ê\", \"Ecirc\": \"Ê\", \"ecolon\": \"≕\", \"ecy\": \"э\", \"Ecy\": \"Э\", \"eDDot\": \"⩷\", \"edot\": \"ė\", \"eDot\": \"≑\", \"Edot\": \"Ė\", \"ee\": \"ⅇ\", \"efDot\": \"≒\", \"efr\": \"𝔢\", \"Efr\": \"𝔈\", \"eg\": \"⪚\", \"egrave\": \"è\", \"Egrave\": \"È\", \"egs\": \"⪖\", \"egsdot\": \"⪘\", \"el\": \"⪙\", \"Element\": \"∈\", \"elinters\": \"⏧\", \"ell\": \"ℓ\", \"els\": \"⪕\", \"elsdot\": \"⪗\", \"emacr\": \"ē\", \"Emacr\": \"Ē\", \"empty\": \"∅\", \"emptyset\": \"∅\", \"EmptySmallSquare\": \"◻\", \"emptyv\": \"∅\", \"EmptyVerySmallSquare\": \"▫\", \"emsp\": \" \", \"emsp13\": \" \", \"emsp14\": \" \", \"eng\": \"ŋ\", \"ENG\": \"Ŋ\", \"ensp\": \" \", \"eogon\": \"ę\", \"Eogon\": \"Ę\", \"eopf\": \"𝕖\", \"Eopf\": \"𝔼\", \"epar\": \"⋕\", \"eparsl\": \"⧣\", \"eplus\": \"⩱\", \"epsi\": \"ε\", \"epsilon\": \"ε\", \"Epsilon\": \"Ε\", \"epsiv\": \"ϵ\", \"eqcirc\": \"≖\", \"eqcolon\": \"≕\", \"eqsim\": \"≂\", \"eqslantgtr\": \"⪖\", \"eqslantless\": \"⪕\", \"Equal\": \"⩵\", \"equals\": \"=\", \"EqualTilde\": \"≂\", \"equest\": \"≟\", \"Equilibrium\": \"⇌\", \"equiv\": \"≡\", \"equivDD\": \"⩸\", \"eqvparsl\": \"⧥\", \"erarr\": \"⥱\", \"erDot\": \"≓\", \"escr\": \"ℯ\", \"Escr\": \"ℰ\", \"esdot\": \"≐\", \"esim\": \"≂\", \"Esim\": \"⩳\", \"eta\": \"η\", \"Eta\": \"Η\", \"eth\": \"ð\", \"ETH\": \"Ð\", \"euml\": \"ë\", \"Euml\": \"Ë\", \"euro\": \"€\", \"excl\": \"!\", \"exist\": \"∃\", \"Exists\": \"∃\", \"expectation\": \"ℰ\", \"exponentiale\": \"ⅇ\", \"ExponentialE\": \"ⅇ\", \"fallingdotseq\": \"≒\", \"fcy\": \"ф\", \"Fcy\": \"Ф\", \"female\": \"♀\", \"ffilig\": \"ffi\", \"fflig\": \"ff\", \"ffllig\": \"ffl\", \"ffr\": \"𝔣\", \"Ffr\": \"𝔉\", \"filig\": \"fi\", \"FilledSmallSquare\": \"◼\", \"FilledVerySmallSquare\": \"▪\", \"fjlig\": \"fj\", \"flat\": \"♭\", \"fllig\": \"fl\", \"fltns\": \"▱\", \"fnof\": \"ƒ\", \"fopf\": \"𝕗\", \"Fopf\": \"𝔽\", \"forall\": \"∀\", \"ForAll\": \"∀\", \"fork\": \"⋔\", \"forkv\": \"⫙\", \"Fouriertrf\": \"ℱ\", \"fpartint\": \"⨍\", \"frac12\": \"½\", \"frac13\": \"⅓\", \"frac14\": \"¼\", \"frac15\": \"⅕\", \"frac16\": \"⅙\", \"frac18\": \"⅛\", \"frac23\": \"⅔\", \"frac25\": \"⅖\", \"frac34\": \"¾\", \"frac35\": \"⅗\", \"frac38\": \"⅜\", \"frac45\": \"⅘\", \"frac56\": \"⅚\", \"frac58\": \"⅝\", \"frac78\": \"⅞\", \"frasl\": \"⁄\", \"frown\": \"⌢\", \"fscr\": \"𝒻\", \"Fscr\": \"ℱ\", \"gacute\": \"ǵ\", \"gamma\": \"γ\", \"Gamma\": \"Γ\", \"gammad\": \"ϝ\", \"Gammad\": \"Ϝ\", \"gap\": \"⪆\", \"gbreve\": \"ğ\", \"Gbreve\": \"Ğ\", \"Gcedil\": \"Ģ\", \"gcirc\": \"ĝ\", \"Gcirc\": \"Ĝ\", \"gcy\": \"г\", \"Gcy\": \"Г\", \"gdot\": \"ġ\", \"Gdot\": \"Ġ\", \"ge\": \"≥\", \"gE\": \"≧\", \"gel\": \"⋛\", \"gEl\": \"⪌\", \"geq\": \"≥\", \"geqq\": \"≧\", \"geqslant\": \"⩾\", \"ges\": \"⩾\", \"gescc\": \"⪩\", \"gesdot\": \"⪀\", \"gesdoto\": \"⪂\", \"gesdotol\": \"⪄\", \"gesl\": \"⋛︀\", \"gesles\": \"⪔\", \"gfr\": \"𝔤\", \"Gfr\": \"𝔊\", \"gg\": \"≫\", \"Gg\": \"⋙\", \"ggg\": \"⋙\", \"gimel\": \"ℷ\", \"gjcy\": \"ѓ\", \"GJcy\": \"Ѓ\", \"gl\": \"≷\", \"gla\": \"⪥\", \"glE\": \"⪒\", \"glj\": \"⪤\", \"gnap\": \"⪊\", \"gnapprox\": \"⪊\", \"gne\": \"⪈\", \"gnE\": \"≩\", \"gneq\": \"⪈\", \"gneqq\": \"≩\", \"gnsim\": \"⋧\", \"gopf\": \"𝕘\", \"Gopf\": \"𝔾\", \"grave\": \"`\", \"GreaterEqual\": \"≥\", \"GreaterEqualLess\": \"⋛\", \"GreaterFullEqual\": \"≧\", \"GreaterGreater\": \"⪢\", \"GreaterLess\": \"≷\", \"GreaterSlantEqual\": \"⩾\", \"GreaterTilde\": \"≳\", \"gscr\": \"ℊ\", \"Gscr\": \"𝒢\", \"gsim\": \"≳\", \"gsime\": \"⪎\", \"gsiml\": \"⪐\", \"gt\": \">\", \"Gt\": \"≫\", \"GT\": \">\", \"gtcc\": \"⪧\", \"gtcir\": \"⩺\", \"gtdot\": \"⋗\", \"gtlPar\": \"⦕\", \"gtquest\": \"⩼\", \"gtrapprox\": \"⪆\", \"gtrarr\": \"⥸\", \"gtrdot\": \"⋗\", \"gtreqless\": \"⋛\", \"gtreqqless\": \"⪌\", \"gtrless\": \"≷\", \"gtrsim\": \"≳\", \"gvertneqq\": \"≩︀\", \"gvnE\": \"≩︀\", \"Hacek\": \"ˇ\", \"hairsp\": \" \", \"half\": \"½\", \"hamilt\": \"ℋ\", \"hardcy\": \"ъ\", \"HARDcy\": \"Ъ\", \"harr\": \"↔\", \"hArr\": \"⇔\", \"harrcir\": \"⥈\", \"harrw\": \"↭\", \"Hat\": \"^\", \"hbar\": \"ℏ\", \"hcirc\": \"ĥ\", \"Hcirc\": \"Ĥ\", \"hearts\": \"♥\", \"heartsuit\": \"♥\", \"hellip\": \"…\", \"hercon\": \"⊹\", \"hfr\": \"𝔥\", \"Hfr\": \"ℌ\", \"HilbertSpace\": \"ℋ\", \"hksearow\": \"⤥\", \"hkswarow\": \"⤦\", \"hoarr\": \"⇿\", \"homtht\": \"∻\", \"hookleftarrow\": \"↩\", \"hookrightarrow\": \"↪\", \"hopf\": \"𝕙\", \"Hopf\": \"ℍ\", \"horbar\": \"―\", \"HorizontalLine\": \"─\", \"hscr\": \"𝒽\", \"Hscr\": \"ℋ\", \"hslash\": \"ℏ\", \"hstrok\": \"ħ\", \"Hstrok\": \"Ħ\", \"HumpDownHump\": \"≎\", \"HumpEqual\": \"≏\", \"hybull\": \"⁃\", \"hyphen\": \"‐\", \"iacute\": \"í\", \"Iacute\": \"Í\", \"ic\": \"⁣\", \"icirc\": \"î\", \"Icirc\": \"Î\", \"icy\": \"и\", \"Icy\": \"И\", \"Idot\": \"İ\", \"iecy\": \"е\", \"IEcy\": \"Е\", \"iexcl\": \"¡\", \"iff\": \"⇔\", \"ifr\": \"𝔦\", \"Ifr\": \"ℑ\", \"igrave\": \"ì\", \"Igrave\": \"Ì\", \"ii\": \"ⅈ\", \"iiiint\": \"⨌\", \"iiint\": \"∭\", \"iinfin\": \"⧜\", \"iiota\": \"℩\", \"ijlig\": \"ij\", \"IJlig\": \"IJ\", \"Im\": \"ℑ\", \"imacr\": \"ī\", \"Imacr\": \"Ī\", \"image\": \"ℑ\", \"ImaginaryI\": \"ⅈ\", \"imagline\": \"ℐ\", \"imagpart\": \"ℑ\", \"imath\": \"ı\", \"imof\": \"⊷\", \"imped\": \"Ƶ\", \"Implies\": \"⇒\", \"in\": \"∈\", \"incare\": \"℅\", \"infin\": \"∞\", \"infintie\": \"⧝\", \"inodot\": \"ı\", \"int\": \"∫\", \"Int\": \"∬\", \"intcal\": \"⊺\", \"integers\": \"ℤ\", \"Integral\": \"∫\", \"intercal\": \"⊺\", \"Intersection\": \"⋂\", \"intlarhk\": \"⨗\", \"intprod\": \"⨼\", \"InvisibleComma\": \"⁣\", \"InvisibleTimes\": \"⁢\", \"iocy\": \"ё\", \"IOcy\": \"Ё\", \"iogon\": \"į\", \"Iogon\": \"Į\", \"iopf\": \"𝕚\", \"Iopf\": \"𝕀\", \"iota\": \"ι\", \"Iota\": \"Ι\", \"iprod\": \"⨼\", \"iquest\": \"¿\", \"iscr\": \"𝒾\", \"Iscr\": \"ℐ\", \"isin\": \"∈\", \"isindot\": \"⋵\", \"isinE\": \"⋹\", \"isins\": \"⋴\", \"isinsv\": \"⋳\", \"isinv\": \"∈\", \"it\": \"⁢\", \"itilde\": \"ĩ\", \"Itilde\": \"Ĩ\", \"iukcy\": \"і\", \"Iukcy\": \"І\", \"iuml\": \"ï\", \"Iuml\": \"Ï\", \"jcirc\": \"ĵ\", \"Jcirc\": \"Ĵ\", \"jcy\": \"й\", \"Jcy\": \"Й\", \"jfr\": \"𝔧\", \"Jfr\": \"𝔍\", \"jmath\": \"ȷ\", \"jopf\": \"𝕛\", \"Jopf\": \"𝕁\", \"jscr\": \"𝒿\", \"Jscr\": \"𝒥\", \"jsercy\": \"ј\", \"Jsercy\": \"Ј\", \"jukcy\": \"є\", \"Jukcy\": \"Є\", \"kappa\": \"κ\", \"Kappa\": \"Κ\", \"kappav\": \"ϰ\", \"kcedil\": \"ķ\", \"Kcedil\": \"Ķ\", \"kcy\": \"к\", \"Kcy\": \"К\", \"kfr\": \"𝔨\", \"Kfr\": \"𝔎\", \"kgreen\": \"ĸ\", \"khcy\": \"х\", \"KHcy\": \"Х\", \"kjcy\": \"ќ\", \"KJcy\": \"Ќ\", \"kopf\": \"𝕜\", \"Kopf\": \"𝕂\", \"kscr\": \"𝓀\", \"Kscr\": \"𝒦\", \"lAarr\": \"⇚\", \"lacute\": \"ĺ\", \"Lacute\": \"Ĺ\", \"laemptyv\": \"⦴\", \"lagran\": \"ℒ\", \"lambda\": \"λ\", \"Lambda\": \"Λ\", \"lang\": \"⟨\", \"Lang\": \"⟪\", \"langd\": \"⦑\", \"langle\": \"⟨\", \"lap\": \"⪅\", \"Laplacetrf\": \"ℒ\", \"laquo\": \"«\", \"larr\": \"←\", \"lArr\": \"⇐\", \"Larr\": \"↞\", \"larrb\": \"⇤\", \"larrbfs\": \"⤟\", \"larrfs\": \"⤝\", \"larrhk\": \"↩\", \"larrlp\": \"↫\", \"larrpl\": \"⤹\", \"larrsim\": \"⥳\", \"larrtl\": \"↢\", \"lat\": \"⪫\", \"latail\": \"⤙\", \"lAtail\": \"⤛\", \"late\": \"⪭\", \"lates\": \"⪭︀\", \"lbarr\": \"⤌\", \"lBarr\": \"⤎\", \"lbbrk\": \"❲\", \"lbrace\": \"{\", \"lbrack\": \"[\", \"lbrke\": \"⦋\", \"lbrksld\": \"⦏\", \"lbrkslu\": \"⦍\", \"lcaron\": \"ľ\", \"Lcaron\": \"Ľ\", \"lcedil\": \"ļ\", \"Lcedil\": \"Ļ\", \"lceil\": \"⌈\", \"lcub\": \"{\", \"lcy\": \"л\", \"Lcy\": \"Л\", \"ldca\": \"⤶\", \"ldquo\": \"“\", \"ldquor\": \"„\", \"ldrdhar\": \"⥧\", \"ldrushar\": \"⥋\", \"ldsh\": \"↲\", \"le\": \"≤\", \"lE\": \"≦\", \"LeftAngleBracket\": \"⟨\", \"leftarrow\": \"←\", \"Leftarrow\": \"⇐\", \"LeftArrow\": \"←\", \"LeftArrowBar\": \"⇤\", \"LeftArrowRightArrow\": \"⇆\", \"leftarrowtail\": \"↢\", \"LeftCeiling\": \"⌈\", \"LeftDoubleBracket\": \"⟦\", \"LeftDownTeeVector\": \"⥡\", \"LeftDownVector\": \"⇃\", \"LeftDownVectorBar\": \"⥙\", \"LeftFloor\": \"⌊\", \"leftharpoondown\": \"↽\", \"leftharpoonup\": \"↼\", \"leftleftarrows\": \"⇇\", \"leftrightarrow\": \"↔\", \"Leftrightarrow\": \"⇔\", \"LeftRightArrow\": \"↔\", \"leftrightarrows\": \"⇆\", \"leftrightharpoons\": \"⇋\", \"leftrightsquigarrow\": \"↭\", \"LeftRightVector\": \"⥎\", \"LeftTee\": \"⊣\", \"LeftTeeArrow\": \"↤\", \"LeftTeeVector\": \"⥚\", \"leftthreetimes\": \"⋋\", \"LeftTriangle\": \"⊲\", \"LeftTriangleBar\": \"⧏\", \"LeftTriangleEqual\": \"⊴\", \"LeftUpDownVector\": \"⥑\", \"LeftUpTeeVector\": \"⥠\", \"LeftUpVector\": \"↿\", \"LeftUpVectorBar\": \"⥘\", \"LeftVector\": \"↼\", \"LeftVectorBar\": \"⥒\", \"leg\": \"⋚\", \"lEg\": \"⪋\", \"leq\": \"≤\", \"leqq\": \"≦\", \"leqslant\": \"⩽\", \"les\": \"⩽\", \"lescc\": \"⪨\", \"lesdot\": \"⩿\", \"lesdoto\": \"⪁\", \"lesdotor\": \"⪃\", \"lesg\": \"⋚︀\", \"lesges\": \"⪓\", \"lessapprox\": \"⪅\", \"lessdot\": \"⋖\", \"lesseqgtr\": \"⋚\", \"lesseqqgtr\": \"⪋\", \"LessEqualGreater\": \"⋚\", \"LessFullEqual\": \"≦\", \"LessGreater\": \"≶\", \"lessgtr\": \"≶\", \"LessLess\": \"⪡\", \"lesssim\": \"≲\", \"LessSlantEqual\": \"⩽\", \"LessTilde\": \"≲\", \"lfisht\": \"⥼\", \"lfloor\": \"⌊\", \"lfr\": \"𝔩\", \"Lfr\": \"𝔏\", \"lg\": \"≶\", \"lgE\": \"⪑\", \"lHar\": \"⥢\", \"lhard\": \"↽\", \"lharu\": \"↼\", \"lharul\": \"⥪\", \"lhblk\": \"▄\", \"ljcy\": \"љ\", \"LJcy\": \"Љ\", \"ll\": \"≪\", \"Ll\": \"⋘\", \"llarr\": \"⇇\", \"llcorner\": \"⌞\", \"Lleftarrow\": \"⇚\", \"llhard\": \"⥫\", \"lltri\": \"◺\", \"lmidot\": \"ŀ\", \"Lmidot\": \"Ŀ\", \"lmoust\": \"⎰\", \"lmoustache\": \"⎰\", \"lnap\": \"⪉\", \"lnapprox\": \"⪉\", \"lne\": \"⪇\", \"lnE\": \"≨\", \"lneq\": \"⪇\", \"lneqq\": \"≨\", \"lnsim\": \"⋦\", \"loang\": \"⟬\", \"loarr\": \"⇽\", \"lobrk\": \"⟦\", \"longleftarrow\": \"⟵\", \"Longleftarrow\": \"⟸\", \"LongLeftArrow\": \"⟵\", \"longleftrightarrow\": \"⟷\", \"Longleftrightarrow\": \"⟺\", \"LongLeftRightArrow\": \"⟷\", \"longmapsto\": \"⟼\", \"longrightarrow\": \"⟶\", \"Longrightarrow\": \"⟹\", \"LongRightArrow\": \"⟶\", \"looparrowleft\": \"↫\", \"looparrowright\": \"↬\", \"lopar\": \"⦅\", \"lopf\": \"𝕝\", \"Lopf\": \"𝕃\", \"loplus\": \"⨭\", \"lotimes\": \"⨴\", \"lowast\": \"∗\", \"lowbar\": \"_\", \"LowerLeftArrow\": \"↙\", \"LowerRightArrow\": \"↘\", \"loz\": \"◊\", \"lozenge\": \"◊\", \"lozf\": \"⧫\", \"lpar\": \"(\", \"lparlt\": \"⦓\", \"lrarr\": \"⇆\", \"lrcorner\": \"⌟\", \"lrhar\": \"⇋\", \"lrhard\": \"⥭\", \"lrm\": \"‎\", \"lrtri\": \"⊿\", \"lsaquo\": \"‹\", \"lscr\": \"𝓁\", \"Lscr\": \"ℒ\", \"lsh\": \"↰\", \"Lsh\": \"↰\", \"lsim\": \"≲\", \"lsime\": \"⪍\", \"lsimg\": \"⪏\", \"lsqb\": \"[\", \"lsquo\": \"‘\", \"lsquor\": \"‚\", \"lstrok\": \"ł\", \"Lstrok\": \"Ł\", \"lt\": \"<\", \"Lt\": \"≪\", \"LT\": \"<\", \"ltcc\": \"⪦\", \"ltcir\": \"⩹\", \"ltdot\": \"⋖\", \"lthree\": \"⋋\", \"ltimes\": \"⋉\", \"ltlarr\": \"⥶\", \"ltquest\": \"⩻\", \"ltri\": \"◃\", \"ltrie\": \"⊴\", \"ltrif\": \"◂\", \"ltrPar\": \"⦖\", \"lurdshar\": \"⥊\", \"luruhar\": \"⥦\", \"lvertneqq\": \"≨︀\", \"lvnE\": \"≨︀\", \"macr\": \"¯\", \"male\": \"♂\", \"malt\": \"✠\", \"maltese\": \"✠\", \"map\": \"↦\", \"Map\": \"⤅\", \"mapsto\": \"↦\", \"mapstodown\": \"↧\", \"mapstoleft\": \"↤\", \"mapstoup\": \"↥\", \"marker\": \"▮\", \"mcomma\": \"⨩\", \"mcy\": \"м\", \"Mcy\": \"М\", \"mdash\": \"—\", \"mDDot\": \"∺\", \"measuredangle\": \"∡\", \"MediumSpace\": \" \", \"Mellintrf\": \"ℳ\", \"mfr\": \"𝔪\", \"Mfr\": \"𝔐\", \"mho\": \"℧\", \"micro\": \"µ\", \"mid\": \"∣\", \"midast\": \"*\", \"midcir\": \"⫰\", \"middot\": \"·\", \"minus\": \"−\", \"minusb\": \"⊟\", \"minusd\": \"∸\", \"minusdu\": \"⨪\", \"MinusPlus\": \"∓\", \"mlcp\": \"⫛\", \"mldr\": \"…\", \"mnplus\": \"∓\", \"models\": \"⊧\", \"mopf\": \"𝕞\", \"Mopf\": \"𝕄\", \"mp\": \"∓\", \"mscr\": \"𝓂\", \"Mscr\": \"ℳ\", \"mstpos\": \"∾\", \"mu\": \"μ\", \"Mu\": \"Μ\", \"multimap\": \"⊸\", \"mumap\": \"⊸\", \"nabla\": \"∇\", \"nacute\": \"ń\", \"Nacute\": \"Ń\", \"nang\": \"∠⃒\", \"nap\": \"≉\", \"napE\": \"⩰̸\", \"napid\": \"≋̸\", \"napos\": \"ʼn\", \"napprox\": \"≉\", \"natur\": \"♮\", \"natural\": \"♮\", \"naturals\": \"ℕ\", \"nbsp\": \" \", \"nbump\": \"≎̸\", \"nbumpe\": \"≏̸\", \"ncap\": \"⩃\", \"ncaron\": \"ň\", \"Ncaron\": \"Ň\", \"ncedil\": \"ņ\", \"Ncedil\": \"Ņ\", \"ncong\": \"≇\", \"ncongdot\": \"⩭̸\", \"ncup\": \"⩂\", \"ncy\": \"н\", \"Ncy\": \"Н\", \"ndash\": \"–\", \"ne\": \"≠\", \"nearhk\": \"⤤\", \"nearr\": \"↗\", \"neArr\": \"⇗\", \"nearrow\": \"↗\", \"nedot\": \"≐̸\", \"NegativeMediumSpace\": \"​\", \"NegativeThickSpace\": \"​\", \"NegativeThinSpace\": \"​\", \"NegativeVeryThinSpace\": \"​\", \"nequiv\": \"≢\", \"nesear\": \"⤨\", \"nesim\": \"≂̸\", \"NestedGreaterGreater\": \"≫\", \"NestedLessLess\": \"≪\", \"NewLine\": \"\\n\", \"nexist\": \"∄\", \"nexists\": \"∄\", \"nfr\": \"𝔫\", \"Nfr\": \"𝔑\", \"nge\": \"≱\", \"ngE\": \"≧̸\", \"ngeq\": \"≱\", \"ngeqq\": \"≧̸\", \"ngeqslant\": \"⩾̸\", \"nges\": \"⩾̸\", \"nGg\": \"⋙̸\", \"ngsim\": \"≵\", \"ngt\": \"≯\", \"nGt\": \"≫⃒\", \"ngtr\": \"≯\", \"nGtv\": \"≫̸\", \"nharr\": \"↮\", \"nhArr\": \"⇎\", \"nhpar\": \"⫲\", \"ni\": \"∋\", \"nis\": \"⋼\", \"nisd\": \"⋺\", \"niv\": \"∋\", \"njcy\": \"њ\", \"NJcy\": \"Њ\", \"nlarr\": \"↚\", \"nlArr\": \"⇍\", \"nldr\": \"‥\", \"nle\": \"≰\", \"nlE\": \"≦̸\", \"nleftarrow\": \"↚\", \"nLeftarrow\": \"⇍\", \"nleftrightarrow\": \"↮\", \"nLeftrightarrow\": \"⇎\", \"nleq\": \"≰\", \"nleqq\": \"≦̸\", \"nleqslant\": \"⩽̸\", \"nles\": \"⩽̸\", \"nless\": \"≮\", \"nLl\": \"⋘̸\", \"nlsim\": \"≴\", \"nlt\": \"≮\", \"nLt\": \"≪⃒\", \"nltri\": \"⋪\", \"nltrie\": \"⋬\", \"nLtv\": \"≪̸\", \"nmid\": \"∤\", \"NoBreak\": \"⁠\", \"NonBreakingSpace\": \" \", \"nopf\": \"𝕟\", \"Nopf\": \"ℕ\", \"not\": \"¬\", \"Not\": \"⫬\", \"NotCongruent\": \"≢\", \"NotCupCap\": \"≭\", \"NotDoubleVerticalBar\": \"∦\", \"NotElement\": \"∉\", \"NotEqual\": \"≠\", \"NotEqualTilde\": \"≂̸\", \"NotExists\": \"∄\", \"NotGreater\": \"≯\", \"NotGreaterEqual\": \"≱\", \"NotGreaterFullEqual\": \"≧̸\", \"NotGreaterGreater\": \"≫̸\", \"NotGreaterLess\": \"≹\", \"NotGreaterSlantEqual\": \"⩾̸\", \"NotGreaterTilde\": \"≵\", \"NotHumpDownHump\": \"≎̸\", \"NotHumpEqual\": \"≏̸\", \"notin\": \"∉\", \"notindot\": \"⋵̸\", \"notinE\": \"⋹̸\", \"notinva\": \"∉\", \"notinvb\": \"⋷\", \"notinvc\": \"⋶\", \"NotLeftTriangle\": \"⋪\", \"NotLeftTriangleBar\": \"⧏̸\", \"NotLeftTriangleEqual\": \"⋬\", \"NotLess\": \"≮\", \"NotLessEqual\": \"≰\", \"NotLessGreater\": \"≸\", \"NotLessLess\": \"≪̸\", \"NotLessSlantEqual\": \"⩽̸\", \"NotLessTilde\": \"≴\", \"NotNestedGreaterGreater\": \"⪢̸\", \"NotNestedLessLess\": \"⪡̸\", \"notni\": \"∌\", \"notniva\": \"∌\", \"notnivb\": \"⋾\", \"notnivc\": \"⋽\", \"NotPrecedes\": \"⊀\", \"NotPrecedesEqual\": \"⪯̸\", \"NotPrecedesSlantEqual\": \"⋠\", \"NotReverseElement\": \"∌\", \"NotRightTriangle\": \"⋫\", \"NotRightTriangleBar\": \"⧐̸\", \"NotRightTriangleEqual\": \"⋭\", \"NotSquareSubset\": \"⊏̸\", \"NotSquareSubsetEqual\": \"⋢\", \"NotSquareSuperset\": \"⊐̸\", \"NotSquareSupersetEqual\": \"⋣\", \"NotSubset\": \"⊂⃒\", \"NotSubsetEqual\": \"⊈\", \"NotSucceeds\": \"⊁\", \"NotSucceedsEqual\": \"⪰̸\", \"NotSucceedsSlantEqual\": \"⋡\", \"NotSucceedsTilde\": \"≿̸\", \"NotSuperset\": \"⊃⃒\", \"NotSupersetEqual\": \"⊉\", \"NotTilde\": \"≁\", \"NotTildeEqual\": \"≄\", \"NotTildeFullEqual\": \"≇\", \"NotTildeTilde\": \"≉\", \"NotVerticalBar\": \"∤\", \"npar\": \"∦\", \"nparallel\": \"∦\", \"nparsl\": \"⫽⃥\", \"npart\": \"∂̸\", \"npolint\": \"⨔\", \"npr\": \"⊀\", \"nprcue\": \"⋠\", \"npre\": \"⪯̸\", \"nprec\": \"⊀\", \"npreceq\": \"⪯̸\", \"nrarr\": \"↛\", \"nrArr\": \"⇏\", \"nrarrc\": \"⤳̸\", \"nrarrw\": \"↝̸\", \"nrightarrow\": \"↛\", \"nRightarrow\": \"⇏\", \"nrtri\": \"⋫\", \"nrtrie\": \"⋭\", \"nsc\": \"⊁\", \"nsccue\": \"⋡\", \"nsce\": \"⪰̸\", \"nscr\": \"𝓃\", \"Nscr\": \"𝒩\", \"nshortmid\": \"∤\", \"nshortparallel\": \"∦\", \"nsim\": \"≁\", \"nsime\": \"≄\", \"nsimeq\": \"≄\", \"nsmid\": \"∤\", \"nspar\": \"∦\", \"nsqsube\": \"⋢\", \"nsqsupe\": \"⋣\", \"nsub\": \"⊄\", \"nsube\": \"⊈\", \"nsubE\": \"⫅̸\", \"nsubset\": \"⊂⃒\", \"nsubseteq\": \"⊈\", \"nsubseteqq\": \"⫅̸\", \"nsucc\": \"⊁\", \"nsucceq\": \"⪰̸\", \"nsup\": \"⊅\", \"nsupe\": \"⊉\", \"nsupE\": \"⫆̸\", \"nsupset\": \"⊃⃒\", \"nsupseteq\": \"⊉\", \"nsupseteqq\": \"⫆̸\", \"ntgl\": \"≹\", \"ntilde\": \"ñ\", \"Ntilde\": \"Ñ\", \"ntlg\": \"≸\", \"ntriangleleft\": \"⋪\", \"ntrianglelefteq\": \"⋬\", \"ntriangleright\": \"⋫\", \"ntrianglerighteq\": \"⋭\", \"nu\": \"ν\", \"Nu\": \"Ν\", \"num\": \"#\", \"numero\": \"№\", \"numsp\": \" \", \"nvap\": \"≍⃒\", \"nvdash\": \"⊬\", \"nvDash\": \"⊭\", \"nVdash\": \"⊮\", \"nVDash\": \"⊯\", \"nvge\": \"≥⃒\", \"nvgt\": \">⃒\", \"nvHarr\": \"⤄\", \"nvinfin\": \"⧞\", \"nvlArr\": \"⤂\", \"nvle\": \"≤⃒\", \"nvlt\": \"<⃒\", \"nvltrie\": \"⊴⃒\", \"nvrArr\": \"⤃\", \"nvrtrie\": \"⊵⃒\", \"nvsim\": \"∼⃒\", \"nwarhk\": \"⤣\", \"nwarr\": \"↖\", \"nwArr\": \"⇖\", \"nwarrow\": \"↖\", \"nwnear\": \"⤧\", \"oacute\": \"ó\", \"Oacute\": \"Ó\", \"oast\": \"⊛\", \"ocir\": \"⊚\", \"ocirc\": \"ô\", \"Ocirc\": \"Ô\", \"ocy\": \"о\", \"Ocy\": \"О\", \"odash\": \"⊝\", \"odblac\": \"ő\", \"Odblac\": \"Ő\", \"odiv\": \"⨸\", \"odot\": \"⊙\", \"odsold\": \"⦼\", \"oelig\": \"œ\", \"OElig\": \"Œ\", \"ofcir\": \"⦿\", \"ofr\": \"𝔬\", \"Ofr\": \"𝔒\", \"ogon\": \"˛\", \"ograve\": \"ò\", \"Ograve\": \"Ò\", \"ogt\": \"⧁\", \"ohbar\": \"⦵\", \"ohm\": \"Ω\", \"oint\": \"∮\", \"olarr\": \"↺\", \"olcir\": \"⦾\", \"olcross\": \"⦻\", \"oline\": \"‾\", \"olt\": \"⧀\", \"omacr\": \"ō\", \"Omacr\": \"Ō\", \"omega\": \"ω\", \"Omega\": \"Ω\", \"omicron\": \"ο\", \"Omicron\": \"Ο\", \"omid\": \"⦶\", \"ominus\": \"⊖\", \"oopf\": \"𝕠\", \"Oopf\": \"𝕆\", \"opar\": \"⦷\", \"OpenCurlyDoubleQuote\": \"“\", \"OpenCurlyQuote\": \"‘\", \"operp\": \"⦹\", \"oplus\": \"⊕\", \"or\": \"∨\", \"Or\": \"⩔\", \"orarr\": \"↻\", \"ord\": \"⩝\", \"order\": \"ℴ\", \"orderof\": \"ℴ\", \"ordf\": \"ª\", \"ordm\": \"º\", \"origof\": \"⊶\", \"oror\": \"⩖\", \"orslope\": \"⩗\", \"orv\": \"⩛\", \"oS\": \"Ⓢ\", \"oscr\": \"ℴ\", \"Oscr\": \"𝒪\", \"oslash\": \"ø\", \"Oslash\": \"Ø\", \"osol\": \"⊘\", \"otilde\": \"õ\", \"Otilde\": \"Õ\", \"otimes\": \"⊗\", \"Otimes\": \"⨷\", \"otimesas\": \"⨶\", \"ouml\": \"ö\", \"Ouml\": \"Ö\", \"ovbar\": \"⌽\", \"OverBar\": \"‾\", \"OverBrace\": \"⏞\", \"OverBracket\": \"⎴\", \"OverParenthesis\": \"⏜\", \"par\": \"∥\", \"para\": \"¶\", \"parallel\": \"∥\", \"parsim\": \"⫳\", \"parsl\": \"⫽\", \"part\": \"∂\", \"PartialD\": \"∂\", \"pcy\": \"п\", \"Pcy\": \"П\", \"percnt\": \"%\", \"period\": \".\", \"permil\": \"‰\", \"perp\": \"⊥\", \"pertenk\": \"‱\", \"pfr\": \"𝔭\", \"Pfr\": \"𝔓\", \"phi\": \"φ\", \"Phi\": \"Φ\", \"phiv\": \"ϕ\", \"phmmat\": \"ℳ\", \"phone\": \"☎\", \"pi\": \"π\", \"Pi\": \"Π\", \"pitchfork\": \"⋔\", \"piv\": \"ϖ\", \"planck\": \"ℏ\", \"planckh\": \"ℎ\", \"plankv\": \"ℏ\", \"plus\": \"+\", \"plusacir\": \"⨣\", \"plusb\": \"⊞\", \"pluscir\": \"⨢\", \"plusdo\": \"∔\", \"plusdu\": \"⨥\", \"pluse\": \"⩲\", \"PlusMinus\": \"±\", \"plusmn\": \"±\", \"plussim\": \"⨦\", \"plustwo\": \"⨧\", \"pm\": \"±\", \"Poincareplane\": \"ℌ\", \"pointint\": \"⨕\", \"popf\": \"𝕡\", \"Popf\": \"ℙ\", \"pound\": \"£\", \"pr\": \"≺\", \"Pr\": \"⪻\", \"prap\": \"⪷\", \"prcue\": \"≼\", \"pre\": \"⪯\", \"prE\": \"⪳\", \"prec\": \"≺\", \"precapprox\": \"⪷\", \"preccurlyeq\": \"≼\", \"Precedes\": \"≺\", \"PrecedesEqual\": \"⪯\", \"PrecedesSlantEqual\": \"≼\", \"PrecedesTilde\": \"≾\", \"preceq\": \"⪯\", \"precnapprox\": \"⪹\", \"precneqq\": \"⪵\", \"precnsim\": \"⋨\", \"precsim\": \"≾\", \"prime\": \"′\", \"Prime\": \"″\", \"primes\": \"ℙ\", \"prnap\": \"⪹\", \"prnE\": \"⪵\", \"prnsim\": \"⋨\", \"prod\": \"∏\", \"Product\": \"∏\", \"profalar\": \"⌮\", \"profline\": \"⌒\", \"profsurf\": \"⌓\", \"prop\": \"∝\", \"Proportion\": \"∷\", \"Proportional\": \"∝\", \"propto\": \"∝\", \"prsim\": \"≾\", \"prurel\": \"⊰\", \"pscr\": \"𝓅\", \"Pscr\": \"𝒫\", \"psi\": \"ψ\", \"Psi\": \"Ψ\", \"puncsp\": \" \", \"qfr\": \"𝔮\", \"Qfr\": \"𝔔\", \"qint\": \"⨌\", \"qopf\": \"𝕢\", \"Qopf\": \"ℚ\", \"qprime\": \"⁗\", \"qscr\": \"𝓆\", \"Qscr\": \"𝒬\", \"quaternions\": \"ℍ\", \"quatint\": \"⨖\", \"quest\": \"?\", \"questeq\": \"≟\", \"quot\": '\"', \"QUOT\": '\"', \"rAarr\": \"⇛\", \"race\": \"∽̱\", \"racute\": \"ŕ\", \"Racute\": \"Ŕ\", \"radic\": \"√\", \"raemptyv\": \"⦳\", \"rang\": \"⟩\", \"Rang\": \"⟫\", \"rangd\": \"⦒\", \"range\": \"⦥\", \"rangle\": \"⟩\", \"raquo\": \"»\", \"rarr\": \"→\", \"rArr\": \"⇒\", \"Rarr\": \"↠\", \"rarrap\": \"⥵\", \"rarrb\": \"⇥\", \"rarrbfs\": \"⤠\", \"rarrc\": \"⤳\", \"rarrfs\": \"⤞\", \"rarrhk\": \"↪\", \"rarrlp\": \"↬\", \"rarrpl\": \"⥅\", \"rarrsim\": \"⥴\", \"rarrtl\": \"↣\", \"Rarrtl\": \"⤖\", \"rarrw\": \"↝\", \"ratail\": \"⤚\", \"rAtail\": \"⤜\", \"ratio\": \"∶\", \"rationals\": \"ℚ\", \"rbarr\": \"⤍\", \"rBarr\": \"⤏\", \"RBarr\": \"⤐\", \"rbbrk\": \"❳\", \"rbrace\": \"}\", \"rbrack\": \"]\", \"rbrke\": \"⦌\", \"rbrksld\": \"⦎\", \"rbrkslu\": \"⦐\", \"rcaron\": \"ř\", \"Rcaron\": \"Ř\", \"rcedil\": \"ŗ\", \"Rcedil\": \"Ŗ\", \"rceil\": \"⌉\", \"rcub\": \"}\", \"rcy\": \"р\", \"Rcy\": \"Р\", \"rdca\": \"⤷\", \"rdldhar\": \"⥩\", \"rdquo\": \"”\", \"rdquor\": \"”\", \"rdsh\": \"↳\", \"Re\": \"ℜ\", \"real\": \"ℜ\", \"realine\": \"ℛ\", \"realpart\": \"ℜ\", \"reals\": \"ℝ\", \"rect\": \"▭\", \"reg\": \"®\", \"REG\": \"®\", \"ReverseElement\": \"∋\", \"ReverseEquilibrium\": \"⇋\", \"ReverseUpEquilibrium\": \"⥯\", \"rfisht\": \"⥽\", \"rfloor\": \"⌋\", \"rfr\": \"𝔯\", \"Rfr\": \"ℜ\", \"rHar\": \"⥤\", \"rhard\": \"⇁\", \"rharu\": \"⇀\", \"rharul\": \"⥬\", \"rho\": \"ρ\", \"Rho\": \"Ρ\", \"rhov\": \"ϱ\", \"RightAngleBracket\": \"⟩\", \"rightarrow\": \"→\", \"Rightarrow\": \"⇒\", \"RightArrow\": \"→\", \"RightArrowBar\": \"⇥\", \"RightArrowLeftArrow\": \"⇄\", \"rightarrowtail\": \"↣\", \"RightCeiling\": \"⌉\", \"RightDoubleBracket\": \"⟧\", \"RightDownTeeVector\": \"⥝\", \"RightDownVector\": \"⇂\", \"RightDownVectorBar\": \"⥕\", \"RightFloor\": \"⌋\", \"rightharpoondown\": \"⇁\", \"rightharpoonup\": \"⇀\", \"rightleftarrows\": \"⇄\", \"rightleftharpoons\": \"⇌\", \"rightrightarrows\": \"⇉\", \"rightsquigarrow\": \"↝\", \"RightTee\": \"⊢\", \"RightTeeArrow\": \"↦\", \"RightTeeVector\": \"⥛\", \"rightthreetimes\": \"⋌\", \"RightTriangle\": \"⊳\", \"RightTriangleBar\": \"⧐\", \"RightTriangleEqual\": \"⊵\", \"RightUpDownVector\": \"⥏\", \"RightUpTeeVector\": \"⥜\", \"RightUpVector\": \"↾\", \"RightUpVectorBar\": \"⥔\", \"RightVector\": \"⇀\", \"RightVectorBar\": \"⥓\", \"ring\": \"˚\", \"risingdotseq\": \"≓\", \"rlarr\": \"⇄\", \"rlhar\": \"⇌\", \"rlm\": \"‏\", \"rmoust\": \"⎱\", \"rmoustache\": \"⎱\", \"rnmid\": \"⫮\", \"roang\": \"⟭\", \"roarr\": \"⇾\", \"robrk\": \"⟧\", \"ropar\": \"⦆\", \"ropf\": \"𝕣\", \"Ropf\": \"ℝ\", \"roplus\": \"⨮\", \"rotimes\": \"⨵\", \"RoundImplies\": \"⥰\", \"rpar\": \")\", \"rpargt\": \"⦔\", \"rppolint\": \"⨒\", \"rrarr\": \"⇉\", \"Rrightarrow\": \"⇛\", \"rsaquo\": \"›\", \"rscr\": \"𝓇\", \"Rscr\": \"ℛ\", \"rsh\": \"↱\", \"Rsh\": \"↱\", \"rsqb\": \"]\", \"rsquo\": \"’\", \"rsquor\": \"’\", \"rthree\": \"⋌\", \"rtimes\": \"⋊\", \"rtri\": \"▹\", \"rtrie\": \"⊵\", \"rtrif\": \"▸\", \"rtriltri\": \"⧎\", \"RuleDelayed\": \"⧴\", \"ruluhar\": \"⥨\", \"rx\": \"℞\", \"sacute\": \"ś\", \"Sacute\": \"Ś\", \"sbquo\": \"‚\", \"sc\": \"≻\", \"Sc\": \"⪼\", \"scap\": \"⪸\", \"scaron\": \"š\", \"Scaron\": \"Š\", \"sccue\": \"≽\", \"sce\": \"⪰\", \"scE\": \"⪴\", \"scedil\": \"ş\", \"Scedil\": \"Ş\", \"scirc\": \"ŝ\", \"Scirc\": \"Ŝ\", \"scnap\": \"⪺\", \"scnE\": \"⪶\", \"scnsim\": \"⋩\", \"scpolint\": \"⨓\", \"scsim\": \"≿\", \"scy\": \"с\", \"Scy\": \"С\", \"sdot\": \"⋅\", \"sdotb\": \"⊡\", \"sdote\": \"⩦\", \"searhk\": \"⤥\", \"searr\": \"↘\", \"seArr\": \"⇘\", \"searrow\": \"↘\", \"sect\": \"§\", \"semi\": \";\", \"seswar\": \"⤩\", \"setminus\": \"∖\", \"setmn\": \"∖\", \"sext\": \"✶\", \"sfr\": \"𝔰\", \"Sfr\": \"𝔖\", \"sfrown\": \"⌢\", \"sharp\": \"♯\", \"shchcy\": \"щ\", \"SHCHcy\": \"Щ\", \"shcy\": \"ш\", \"SHcy\": \"Ш\", \"ShortDownArrow\": \"↓\", \"ShortLeftArrow\": \"←\", \"shortmid\": \"∣\", \"shortparallel\": \"∥\", \"ShortRightArrow\": \"→\", \"ShortUpArrow\": \"↑\", \"shy\": \"­\", \"sigma\": \"σ\", \"Sigma\": \"Σ\", \"sigmaf\": \"ς\", \"sigmav\": \"ς\", \"sim\": \"∼\", \"simdot\": \"⩪\", \"sime\": \"≃\", \"simeq\": \"≃\", \"simg\": \"⪞\", \"simgE\": \"⪠\", \"siml\": \"⪝\", \"simlE\": \"⪟\", \"simne\": \"≆\", \"simplus\": \"⨤\", \"simrarr\": \"⥲\", \"slarr\": \"←\", \"SmallCircle\": \"∘\", \"smallsetminus\": \"∖\", \"smashp\": \"⨳\", \"smeparsl\": \"⧤\", \"smid\": \"∣\", \"smile\": \"⌣\", \"smt\": \"⪪\", \"smte\": \"⪬\", \"smtes\": \"⪬︀\", \"softcy\": \"ь\", \"SOFTcy\": \"Ь\", \"sol\": \"/\", \"solb\": \"⧄\", \"solbar\": \"⌿\", \"sopf\": \"𝕤\", \"Sopf\": \"𝕊\", \"spades\": \"♠\", \"spadesuit\": \"♠\", \"spar\": \"∥\", \"sqcap\": \"⊓\", \"sqcaps\": \"⊓︀\", \"sqcup\": \"⊔\", \"sqcups\": \"⊔︀\", \"Sqrt\": \"√\", \"sqsub\": \"⊏\", \"sqsube\": \"⊑\", \"sqsubset\": \"⊏\", \"sqsubseteq\": \"⊑\", \"sqsup\": \"⊐\", \"sqsupe\": \"⊒\", \"sqsupset\": \"⊐\", \"sqsupseteq\": \"⊒\", \"squ\": \"□\", \"square\": \"□\", \"Square\": \"□\", \"SquareIntersection\": \"⊓\", \"SquareSubset\": \"⊏\", \"SquareSubsetEqual\": \"⊑\", \"SquareSuperset\": \"⊐\", \"SquareSupersetEqual\": \"⊒\", \"SquareUnion\": \"⊔\", \"squarf\": \"▪\", \"squf\": \"▪\", \"srarr\": \"→\", \"sscr\": \"𝓈\", \"Sscr\": \"𝒮\", \"ssetmn\": \"∖\", \"ssmile\": \"⌣\", \"sstarf\": \"⋆\", \"star\": \"☆\", \"Star\": \"⋆\", \"starf\": \"★\", \"straightepsilon\": \"ϵ\", \"straightphi\": \"ϕ\", \"strns\": \"¯\", \"sub\": \"⊂\", \"Sub\": \"⋐\", \"subdot\": \"⪽\", \"sube\": \"⊆\", \"subE\": \"⫅\", \"subedot\": \"⫃\", \"submult\": \"⫁\", \"subne\": \"⊊\", \"subnE\": \"⫋\", \"subplus\": \"⪿\", \"subrarr\": \"⥹\", \"subset\": \"⊂\", \"Subset\": \"⋐\", \"subseteq\": \"⊆\", \"subseteqq\": \"⫅\", \"SubsetEqual\": \"⊆\", \"subsetneq\": \"⊊\", \"subsetneqq\": \"⫋\", \"subsim\": \"⫇\", \"subsub\": \"⫕\", \"subsup\": \"⫓\", \"succ\": \"≻\", \"succapprox\": \"⪸\", \"succcurlyeq\": \"≽\", \"Succeeds\": \"≻\", \"SucceedsEqual\": \"⪰\", \"SucceedsSlantEqual\": \"≽\", \"SucceedsTilde\": \"≿\", \"succeq\": \"⪰\", \"succnapprox\": \"⪺\", \"succneqq\": \"⪶\", \"succnsim\": \"⋩\", \"succsim\": \"≿\", \"SuchThat\": \"∋\", \"sum\": \"∑\", \"Sum\": \"∑\", \"sung\": \"♪\", \"sup\": \"⊃\", \"Sup\": \"⋑\", \"sup1\": \"¹\", \"sup2\": \"²\", \"sup3\": \"³\", \"supdot\": \"⪾\", \"supdsub\": \"⫘\", \"supe\": \"⊇\", \"supE\": \"⫆\", \"supedot\": \"⫄\", \"Superset\": \"⊃\", \"SupersetEqual\": \"⊇\", \"suphsol\": \"⟉\", \"suphsub\": \"⫗\", \"suplarr\": \"⥻\", \"supmult\": \"⫂\", \"supne\": \"⊋\", \"supnE\": \"⫌\", \"supplus\": \"⫀\", \"supset\": \"⊃\", \"Supset\": \"⋑\", \"supseteq\": \"⊇\", \"supseteqq\": \"⫆\", \"supsetneq\": \"⊋\", \"supsetneqq\": \"⫌\", \"supsim\": \"⫈\", \"supsub\": \"⫔\", \"supsup\": \"⫖\", \"swarhk\": \"⤦\", \"swarr\": \"↙\", \"swArr\": \"⇙\", \"swarrow\": \"↙\", \"swnwar\": \"⤪\", \"szlig\": \"ß\", \"Tab\": \"\t\", \"target\": \"⌖\", \"tau\": \"τ\", \"Tau\": \"Τ\", \"tbrk\": \"⎴\", \"tcaron\": \"ť\", \"Tcaron\": \"Ť\", \"tcedil\": \"ţ\", \"Tcedil\": \"Ţ\", \"tcy\": \"т\", \"Tcy\": \"Т\", \"tdot\": \"⃛\", \"telrec\": \"⌕\", \"tfr\": \"𝔱\", \"Tfr\": \"𝔗\", \"there4\": \"∴\", \"therefore\": \"∴\", \"Therefore\": \"∴\", \"theta\": \"θ\", \"Theta\": \"Θ\", \"thetasym\": \"ϑ\", \"thetav\": \"ϑ\", \"thickapprox\": \"≈\", \"thicksim\": \"∼\", \"ThickSpace\": \"  \", \"thinsp\": \" \", \"ThinSpace\": \" \", \"thkap\": \"≈\", \"thksim\": \"∼\", \"thorn\": \"þ\", \"THORN\": \"Þ\", \"tilde\": \"˜\", \"Tilde\": \"∼\", \"TildeEqual\": \"≃\", \"TildeFullEqual\": \"≅\", \"TildeTilde\": \"≈\", \"times\": \"×\", \"timesb\": \"⊠\", \"timesbar\": \"⨱\", \"timesd\": \"⨰\", \"tint\": \"∭\", \"toea\": \"⤨\", \"top\": \"⊤\", \"topbot\": \"⌶\", \"topcir\": \"⫱\", \"topf\": \"𝕥\", \"Topf\": \"𝕋\", \"topfork\": \"⫚\", \"tosa\": \"⤩\", \"tprime\": \"‴\", \"trade\": \"™\", \"TRADE\": \"™\", \"triangle\": \"▵\", \"triangledown\": \"▿\", \"triangleleft\": \"◃\", \"trianglelefteq\": \"⊴\", \"triangleq\": \"≜\", \"triangleright\": \"▹\", \"trianglerighteq\": \"⊵\", \"tridot\": \"◬\", \"trie\": \"≜\", \"triminus\": \"⨺\", \"TripleDot\": \"⃛\", \"triplus\": \"⨹\", \"trisb\": \"⧍\", \"tritime\": \"⨻\", \"trpezium\": \"⏢\", \"tscr\": \"𝓉\", \"Tscr\": \"𝒯\", \"tscy\": \"ц\", \"TScy\": \"Ц\", \"tshcy\": \"ћ\", \"TSHcy\": \"Ћ\", \"tstrok\": \"ŧ\", \"Tstrok\": \"Ŧ\", \"twixt\": \"≬\", \"twoheadleftarrow\": \"↞\", \"twoheadrightarrow\": \"↠\", \"uacute\": \"ú\", \"Uacute\": \"Ú\", \"uarr\": \"↑\", \"uArr\": \"⇑\", \"Uarr\": \"↟\", \"Uarrocir\": \"⥉\", \"ubrcy\": \"ў\", \"Ubrcy\": \"Ў\", \"ubreve\": \"ŭ\", \"Ubreve\": \"Ŭ\", \"ucirc\": \"û\", \"Ucirc\": \"Û\", \"ucy\": \"у\", \"Ucy\": \"У\", \"udarr\": \"⇅\", \"udblac\": \"ű\", \"Udblac\": \"Ű\", \"udhar\": \"⥮\", \"ufisht\": \"⥾\", \"ufr\": \"𝔲\", \"Ufr\": \"𝔘\", \"ugrave\": \"ù\", \"Ugrave\": \"Ù\", \"uHar\": \"⥣\", \"uharl\": \"↿\", \"uharr\": \"↾\", \"uhblk\": \"▀\", \"ulcorn\": \"⌜\", \"ulcorner\": \"⌜\", \"ulcrop\": \"⌏\", \"ultri\": \"◸\", \"umacr\": \"ū\", \"Umacr\": \"Ū\", \"uml\": \"¨\", \"UnderBar\": \"_\", \"UnderBrace\": \"⏟\", \"UnderBracket\": \"⎵\", \"UnderParenthesis\": \"⏝\", \"Union\": \"⋃\", \"UnionPlus\": \"⊎\", \"uogon\": \"ų\", \"Uogon\": \"Ų\", \"uopf\": \"𝕦\", \"Uopf\": \"𝕌\", \"uparrow\": \"↑\", \"Uparrow\": \"⇑\", \"UpArrow\": \"↑\", \"UpArrowBar\": \"⤒\", \"UpArrowDownArrow\": \"⇅\", \"updownarrow\": \"↕\", \"Updownarrow\": \"⇕\", \"UpDownArrow\": \"↕\", \"UpEquilibrium\": \"⥮\", \"upharpoonleft\": \"↿\", \"upharpoonright\": \"↾\", \"uplus\": \"⊎\", \"UpperLeftArrow\": \"↖\", \"UpperRightArrow\": \"↗\", \"upsi\": \"υ\", \"Upsi\": \"ϒ\", \"upsih\": \"ϒ\", \"upsilon\": \"υ\", \"Upsilon\": \"Υ\", \"UpTee\": \"⊥\", \"UpTeeArrow\": \"↥\", \"upuparrows\": \"⇈\", \"urcorn\": \"⌝\", \"urcorner\": \"⌝\", \"urcrop\": \"⌎\", \"uring\": \"ů\", \"Uring\": \"Ů\", \"urtri\": \"◹\", \"uscr\": \"𝓊\", \"Uscr\": \"𝒰\", \"utdot\": \"⋰\", \"utilde\": \"ũ\", \"Utilde\": \"Ũ\", \"utri\": \"▵\", \"utrif\": \"▴\", \"uuarr\": \"⇈\", \"uuml\": \"ü\", \"Uuml\": \"Ü\", \"uwangle\": \"⦧\", \"vangrt\": \"⦜\", \"varepsilon\": \"ϵ\", \"varkappa\": \"ϰ\", \"varnothing\": \"∅\", \"varphi\": \"ϕ\", \"varpi\": \"ϖ\", \"varpropto\": \"∝\", \"varr\": \"↕\", \"vArr\": \"⇕\", \"varrho\": \"ϱ\", \"varsigma\": \"ς\", \"varsubsetneq\": \"⊊︀\", \"varsubsetneqq\": \"⫋︀\", \"varsupsetneq\": \"⊋︀\", \"varsupsetneqq\": \"⫌︀\", \"vartheta\": \"ϑ\", \"vartriangleleft\": \"⊲\", \"vartriangleright\": \"⊳\", \"vBar\": \"⫨\", \"Vbar\": \"⫫\", \"vBarv\": \"⫩\", \"vcy\": \"в\", \"Vcy\": \"В\", \"vdash\": \"⊢\", \"vDash\": \"⊨\", \"Vdash\": \"⊩\", \"VDash\": \"⊫\", \"Vdashl\": \"⫦\", \"vee\": \"∨\", \"Vee\": \"⋁\", \"veebar\": \"⊻\", \"veeeq\": \"≚\", \"vellip\": \"⋮\", \"verbar\": \"|\", \"Verbar\": \"‖\", \"vert\": \"|\", \"Vert\": \"‖\", \"VerticalBar\": \"∣\", \"VerticalLine\": \"|\", \"VerticalSeparator\": \"❘\", \"VerticalTilde\": \"≀\", \"VeryThinSpace\": \" \", \"vfr\": \"𝔳\", \"Vfr\": \"𝔙\", \"vltri\": \"⊲\", \"vnsub\": \"⊂⃒\", \"vnsup\": \"⊃⃒\", \"vopf\": \"𝕧\", \"Vopf\": \"𝕍\", \"vprop\": \"∝\", \"vrtri\": \"⊳\", \"vscr\": \"𝓋\", \"Vscr\": \"𝒱\", \"vsubne\": \"⊊︀\", \"vsubnE\": \"⫋︀\", \"vsupne\": \"⊋︀\", \"vsupnE\": \"⫌︀\", \"Vvdash\": \"⊪\", \"vzigzag\": \"⦚\", \"wcirc\": \"ŵ\", \"Wcirc\": \"Ŵ\", \"wedbar\": \"⩟\", \"wedge\": \"∧\", \"Wedge\": \"⋀\", \"wedgeq\": \"≙\", \"weierp\": \"℘\", \"wfr\": \"𝔴\", \"Wfr\": \"𝔚\", \"wopf\": \"𝕨\", \"Wopf\": \"𝕎\", \"wp\": \"℘\", \"wr\": \"≀\", \"wreath\": \"≀\", \"wscr\": \"𝓌\", \"Wscr\": \"𝒲\", \"xcap\": \"⋂\", \"xcirc\": \"◯\", \"xcup\": \"⋃\", \"xdtri\": \"▽\", \"xfr\": \"𝔵\", \"Xfr\": \"𝔛\", \"xharr\": \"⟷\", \"xhArr\": \"⟺\", \"xi\": \"ξ\", \"Xi\": \"Ξ\", \"xlarr\": \"⟵\", \"xlArr\": \"⟸\", \"xmap\": \"⟼\", \"xnis\": \"⋻\", \"xodot\": \"⨀\", \"xopf\": \"𝕩\", \"Xopf\": \"𝕏\", \"xoplus\": \"⨁\", \"xotime\": \"⨂\", \"xrarr\": \"⟶\", \"xrArr\": \"⟹\", \"xscr\": \"𝓍\", \"Xscr\": \"𝒳\", \"xsqcup\": \"⨆\", \"xuplus\": \"⨄\", \"xutri\": \"△\", \"xvee\": \"⋁\", \"xwedge\": \"⋀\", \"yacute\": \"ý\", \"Yacute\": \"Ý\", \"yacy\": \"я\", \"YAcy\": \"Я\", \"ycirc\": \"ŷ\", \"Ycirc\": \"Ŷ\", \"ycy\": \"ы\", \"Ycy\": \"Ы\", \"yen\": \"¥\", \"yfr\": \"𝔶\", \"Yfr\": \"𝔜\", \"yicy\": \"ї\", \"YIcy\": \"Ї\", \"yopf\": \"𝕪\", \"Yopf\": \"𝕐\", \"yscr\": \"𝓎\", \"Yscr\": \"𝒴\", \"yucy\": \"ю\", \"YUcy\": \"Ю\", \"yuml\": \"ÿ\", \"Yuml\": \"Ÿ\", \"zacute\": \"ź\", \"Zacute\": \"Ź\", \"zcaron\": \"ž\", \"Zcaron\": \"Ž\", \"zcy\": \"з\", \"Zcy\": \"З\", \"zdot\": \"ż\", \"Zdot\": \"Ż\", \"zeetrf\": \"ℨ\", \"ZeroWidthSpace\": \"​\", \"zeta\": \"ζ\", \"Zeta\": \"Ζ\", \"zfr\": \"𝔷\", \"Zfr\": \"ℨ\", \"zhcy\": \"ж\", \"ZHcy\": \"Ж\", \"zigrarr\": \"⇝\", \"zopf\": \"𝕫\", \"Zopf\": \"ℤ\", \"zscr\": \"𝓏\", \"Zscr\": \"𝒵\", \"zwj\": \"‍\", \"zwnj\": \"‌\" };\n var decodeMapLegacy = { \"aacute\": \"á\", \"Aacute\": \"Á\", \"acirc\": \"â\", \"Acirc\": \"Â\", \"acute\": \"´\", \"aelig\": \"æ\", \"AElig\": \"Æ\", \"agrave\": \"à\", \"Agrave\": \"À\", \"amp\": \"&\", \"AMP\": \"&\", \"aring\": \"å\", \"Aring\": \"Å\", \"atilde\": \"ã\", \"Atilde\": \"Ã\", \"auml\": \"ä\", \"Auml\": \"Ä\", \"brvbar\": \"¦\", \"ccedil\": \"ç\", \"Ccedil\": \"Ç\", \"cedil\": \"¸\", \"cent\": \"¢\", \"copy\": \"©\", \"COPY\": \"©\", \"curren\": \"¤\", \"deg\": \"°\", \"divide\": \"÷\", \"eacute\": \"é\", \"Eacute\": \"É\", \"ecirc\": \"ê\", \"Ecirc\": \"Ê\", \"egrave\": \"è\", \"Egrave\": \"È\", \"eth\": \"ð\", \"ETH\": \"Ð\", \"euml\": \"ë\", \"Euml\": \"Ë\", \"frac12\": \"½\", \"frac14\": \"¼\", \"frac34\": \"¾\", \"gt\": \">\", \"GT\": \">\", \"iacute\": \"í\", \"Iacute\": \"Í\", \"icirc\": \"î\", \"Icirc\": \"Î\", \"iexcl\": \"¡\", \"igrave\": \"ì\", \"Igrave\": \"Ì\", \"iquest\": \"¿\", \"iuml\": \"ï\", \"Iuml\": \"Ï\", \"laquo\": \"«\", \"lt\": \"<\", \"LT\": \"<\", \"macr\": \"¯\", \"micro\": \"µ\", \"middot\": \"·\", \"nbsp\": \" \", \"not\": \"¬\", \"ntilde\": \"ñ\", \"Ntilde\": \"Ñ\", \"oacute\": \"ó\", \"Oacute\": \"Ó\", \"ocirc\": \"ô\", \"Ocirc\": \"Ô\", \"ograve\": \"ò\", \"Ograve\": \"Ò\", \"ordf\": \"ª\", \"ordm\": \"º\", \"oslash\": \"ø\", \"Oslash\": \"Ø\", \"otilde\": \"õ\", \"Otilde\": \"Õ\", \"ouml\": \"ö\", \"Ouml\": \"Ö\", \"para\": \"¶\", \"plusmn\": \"±\", \"pound\": \"£\", \"quot\": '\"', \"QUOT\": '\"', \"raquo\": \"»\", \"reg\": \"®\", \"REG\": \"®\", \"sect\": \"§\", \"shy\": \"­\", \"sup1\": \"¹\", \"sup2\": \"²\", \"sup3\": \"³\", \"szlig\": \"ß\", \"thorn\": \"þ\", \"THORN\": \"Þ\", \"times\": \"×\", \"uacute\": \"ú\", \"Uacute\": \"Ú\", \"ucirc\": \"û\", \"Ucirc\": \"Û\", \"ugrave\": \"ù\", \"Ugrave\": \"Ù\", \"uml\": \"¨\", \"uuml\": \"ü\", \"Uuml\": \"Ü\", \"yacute\": \"ý\", \"Yacute\": \"Ý\", \"yen\": \"¥\", \"yuml\": \"ÿ\" };\n var decodeMapNumeric = { \"0\": \"�\", \"128\": \"€\", \"130\": \"‚\", \"131\": \"ƒ\", \"132\": \"„\", \"133\": \"…\", \"134\": \"†\", \"135\": \"‡\", \"136\": \"ˆ\", \"137\": \"‰\", \"138\": \"Š\", \"139\": \"‹\", \"140\": \"Œ\", \"142\": \"Ž\", \"145\": \"‘\", \"146\": \"’\", \"147\": \"“\", \"148\": \"”\", \"149\": \"•\", \"150\": \"–\", \"151\": \"—\", \"152\": \"˜\", \"153\": \"™\", \"154\": \"š\", \"155\": \"›\", \"156\": \"œ\", \"158\": \"ž\", \"159\": \"Ÿ\" };\n var invalidReferenceCodePoints = [1, 2, 3, 4, 5, 6, 7, 8, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 64976, 64977, 64978, 64979, 64980, 64981, 64982, 64983, 64984, 64985, 64986, 64987, 64988, 64989, 64990, 64991, 64992, 64993, 64994, 64995, 64996, 64997, 64998, 64999, 65e3, 65001, 65002, 65003, 65004, 65005, 65006, 65007, 65534, 65535, 131070, 131071, 196606, 196607, 262142, 262143, 327678, 327679, 393214, 393215, 458750, 458751, 524286, 524287, 589822, 589823, 655358, 655359, 720894, 720895, 786430, 786431, 851966, 851967, 917502, 917503, 983038, 983039, 1048574, 1048575, 1114110, 1114111];\n var stringFromCharCode2 = String.fromCharCode;\n var object = {};\n var hasOwnProperty = object.hasOwnProperty;\n var has2 = function(object2, propertyName) {\n return hasOwnProperty.call(object2, propertyName);\n };\n var contains = function(array, value) {\n var index = -1;\n var length = array.length;\n while (++index < length) {\n if (array[index] == value) {\n return true;\n }\n }\n return false;\n };\n var merge = function(options, defaults) {\n if (!options) {\n return defaults;\n }\n var result = {};\n var key2;\n for (key2 in defaults) {\n result[key2] = has2(options, key2) ? options[key2] : defaults[key2];\n }\n return result;\n };\n var codePointToSymbol = function(codePoint, strict) {\n var output = \"\";\n if (codePoint >= 55296 && codePoint <= 57343 || codePoint > 1114111) {\n if (strict) {\n parseError(\"character reference outside the permissible Unicode range\");\n }\n return \"�\";\n }\n if (has2(decodeMapNumeric, codePoint)) {\n if (strict) {\n parseError(\"disallowed character reference\");\n }\n return decodeMapNumeric[codePoint];\n }\n if (strict && contains(invalidReferenceCodePoints, codePoint)) {\n parseError(\"disallowed character reference\");\n }\n if (codePoint > 65535) {\n codePoint -= 65536;\n output += stringFromCharCode2(codePoint >>> 10 & 1023 | 55296);\n codePoint = 56320 | codePoint & 1023;\n }\n output += stringFromCharCode2(codePoint);\n return output;\n };\n var hexEscape = function(codePoint) {\n return \"&#x\" + codePoint.toString(16).toUpperCase() + \";\";\n };\n var decEscape = function(codePoint) {\n return \"&#\" + codePoint + \";\";\n };\n var parseError = function(message) {\n throw Error(\"Parse error: \" + message);\n };\n var encode3 = function(string, options) {\n options = merge(options, encode3.options);\n var strict = options.strict;\n if (strict && regexInvalidRawCodePoint.test(string)) {\n parseError(\"forbidden code point\");\n }\n var encodeEverything = options.encodeEverything;\n var useNamedReferences = options.useNamedReferences;\n var allowUnsafeSymbols = options.allowUnsafeSymbols;\n var escapeCodePoint = options.decimal ? decEscape : hexEscape;\n var escapeBmpSymbol = function(symbol) {\n return escapeCodePoint(symbol.charCodeAt(0));\n };\n if (encodeEverything) {\n string = string.replace(regexAsciiWhitelist, function(symbol) {\n if (useNamedReferences && has2(encodeMap, symbol)) {\n return \"&\" + encodeMap[symbol] + \";\";\n }\n return escapeBmpSymbol(symbol);\n });\n if (useNamedReferences) {\n string = string.replace(/>\\u20D2/g, \">⃒\").replace(/<\\u20D2/g, \"<⃒\").replace(/fj/g, \"fj\");\n }\n if (useNamedReferences) {\n string = string.replace(regexEncodeNonAscii, function(string2) {\n return \"&\" + encodeMap[string2] + \";\";\n });\n }\n } else if (useNamedReferences) {\n if (!allowUnsafeSymbols) {\n string = string.replace(regexEscape, function(string2) {\n return \"&\" + encodeMap[string2] + \";\";\n });\n }\n string = string.replace(/>\\u20D2/g, \">⃒\").replace(/<\\u20D2/g, \"<⃒\");\n string = string.replace(regexEncodeNonAscii, function(string2) {\n return \"&\" + encodeMap[string2] + \";\";\n });\n } else if (!allowUnsafeSymbols) {\n string = string.replace(regexEscape, escapeBmpSymbol);\n }\n return string.replace(regexAstralSymbols, function($0) {\n var high = $0.charCodeAt(0);\n var low = $0.charCodeAt(1);\n var codePoint = (high - 55296) * 1024 + low - 56320 + 65536;\n return escapeCodePoint(codePoint);\n }).replace(regexBmpWhitelist, escapeBmpSymbol);\n };\n encode3.options = {\n \"allowUnsafeSymbols\": false,\n \"encodeEverything\": false,\n \"strict\": false,\n \"useNamedReferences\": false,\n \"decimal\": false\n };\n var decode3 = function(html, options) {\n options = merge(options, decode3.options);\n var strict = options.strict;\n if (strict && regexInvalidEntity.test(html)) {\n parseError(\"malformed character reference\");\n }\n return html.replace(regexDecode, function($0, $1, $2, $3, $4, $5, $6, $7, $8) {\n var codePoint;\n var semicolon;\n var decDigits;\n var hexDigits;\n var reference2;\n var next;\n if ($1) {\n reference2 = $1;\n return decodeMap2[reference2];\n }\n if ($2) {\n reference2 = $2;\n next = $3;\n if (next && options.isAttributeValue) {\n if (strict && next == \"=\") {\n parseError(\"`&` did not start a character reference\");\n }\n return $0;\n } else {\n if (strict) {\n parseError(\n \"named character reference was not terminated by a semicolon\"\n );\n }\n return decodeMapLegacy[reference2] + (next || \"\");\n }\n }\n if ($4) {\n decDigits = $4;\n semicolon = $5;\n if (strict && !semicolon) {\n parseError(\"character reference was not terminated by a semicolon\");\n }\n codePoint = parseInt(decDigits, 10);\n return codePointToSymbol(codePoint, strict);\n }\n if ($6) {\n hexDigits = $6;\n semicolon = $7;\n if (strict && !semicolon) {\n parseError(\"character reference was not terminated by a semicolon\");\n }\n codePoint = parseInt(hexDigits, 16);\n return codePointToSymbol(codePoint, strict);\n }\n if (strict) {\n parseError(\n \"named character reference was not terminated by a semicolon\"\n );\n }\n return $0;\n });\n };\n decode3.options = {\n \"isAttributeValue\": false,\n \"strict\": false\n };\n var escape3 = function(string) {\n return string.replace(regexEscape, function($0) {\n return escapeMap[$0];\n });\n };\n var he2 = {\n \"version\": \"1.2.0\",\n \"encode\": encode3,\n \"decode\": decode3,\n \"escape\": escape3,\n \"unescape\": decode3\n };\n if (typeof define == \"function\" && typeof define.amd == \"object\" && define.amd) {\n define(function() {\n return he2;\n });\n } else if (freeExports && !freeExports.nodeType) {\n if (freeModule) {\n freeModule.exports = he2;\n } else {\n for (var key in he2) {\n has2(he2, key) && (freeExports[key] = he2[key]);\n }\n }\n } else {\n root.he = he2;\n }\n })(exports);\n }\n});\n\n// node_modules/.pnpm/json-logic-js@2.0.5/node_modules/json-logic-js/logic.js\nvar require_logic = __commonJS({\n \"node_modules/.pnpm/json-logic-js@2.0.5/node_modules/json-logic-js/logic.js\"(exports, module) {\n (function(root, factory) {\n if (typeof define === \"function\" && define.amd) {\n define(factory);\n } else if (typeof exports === \"object\") {\n module.exports = factory();\n } else {\n root.jsonLogic = factory();\n }\n })(exports, function() {\n \"use strict\";\n if (!Array.isArray) {\n Array.isArray = function(arg) {\n return Object.prototype.toString.call(arg) === \"[object Array]\";\n };\n }\n function arrayUnique(array) {\n var a = [];\n for (var i = 0, l = array.length; i < l; i++) {\n if (a.indexOf(array[i]) === -1) {\n a.push(array[i]);\n }\n }\n return a;\n }\n var jsonLogic2 = {};\n var operations = {\n \"==\": function(a, b) {\n return a == b;\n },\n \"===\": function(a, b) {\n return a === b;\n },\n \"!=\": function(a, b) {\n return a != b;\n },\n \"!==\": function(a, b) {\n return a !== b;\n },\n \">\": function(a, b) {\n return a > b;\n },\n \">=\": function(a, b) {\n return a >= b;\n },\n \"<\": function(a, b, c) {\n return c === void 0 ? a < b : a < b && b < c;\n },\n \"<=\": function(a, b, c) {\n return c === void 0 ? a <= b : a <= b && b <= c;\n },\n \"!!\": function(a) {\n return jsonLogic2.truthy(a);\n },\n \"!\": function(a) {\n return !jsonLogic2.truthy(a);\n },\n \"%\": function(a, b) {\n return a % b;\n },\n \"log\": function(a) {\n console.log(a);\n return a;\n },\n \"in\": function(a, b) {\n if (!b || typeof b.indexOf === \"undefined\") return false;\n return b.indexOf(a) !== -1;\n },\n \"cat\": function() {\n return Array.prototype.join.call(arguments, \"\");\n },\n \"substr\": function(source, start, end) {\n if (end < 0) {\n var temp = String(source).substr(start);\n return temp.substr(0, temp.length + end);\n }\n return String(source).substr(start, end);\n },\n \"+\": function() {\n return Array.prototype.reduce.call(arguments, function(a, b) {\n return parseFloat(a, 10) + parseFloat(b, 10);\n }, 0);\n },\n \"*\": function() {\n return Array.prototype.reduce.call(arguments, function(a, b) {\n return parseFloat(a, 10) * parseFloat(b, 10);\n });\n },\n \"-\": function(a, b) {\n if (b === void 0) {\n return -a;\n } else {\n return a - b;\n }\n },\n \"/\": function(a, b) {\n return a / b;\n },\n \"min\": function() {\n return Math.min.apply(this, arguments);\n },\n \"max\": function() {\n return Math.max.apply(this, arguments);\n },\n \"merge\": function() {\n return Array.prototype.reduce.call(arguments, function(a, b) {\n return a.concat(b);\n }, []);\n },\n \"var\": function(a, b) {\n var not_found = b === void 0 ? null : b;\n var data = this;\n if (typeof a === \"undefined\" || a === \"\" || a === null) {\n return data;\n }\n var sub_props = String(a).split(\".\");\n for (var i = 0; i < sub_props.length; i++) {\n if (data === null || data === void 0) {\n return not_found;\n }\n data = data[sub_props[i]];\n if (data === void 0) {\n return not_found;\n }\n }\n return data;\n },\n \"missing\": function() {\n var missing = [];\n var keys = Array.isArray(arguments[0]) ? arguments[0] : arguments;\n for (var i = 0; i < keys.length; i++) {\n var key = keys[i];\n var value = jsonLogic2.apply({ \"var\": key }, this);\n if (value === null || value === \"\") {\n missing.push(key);\n }\n }\n return missing;\n },\n \"missing_some\": function(need_count, options) {\n var are_missing = jsonLogic2.apply({ \"missing\": options }, this);\n if (options.length - are_missing.length >= need_count) {\n return [];\n } else {\n return are_missing;\n }\n }\n };\n jsonLogic2.is_logic = function(logic) {\n return typeof logic === \"object\" && // An object\n logic !== null && // but not null\n !Array.isArray(logic) && // and not an array\n Object.keys(logic).length === 1;\n };\n jsonLogic2.truthy = function(value) {\n if (Array.isArray(value) && value.length === 0) {\n return false;\n }\n return !!value;\n };\n jsonLogic2.get_operator = function(logic) {\n return Object.keys(logic)[0];\n };\n jsonLogic2.get_values = function(logic) {\n return logic[jsonLogic2.get_operator(logic)];\n };\n jsonLogic2.apply = function(logic, data) {\n if (Array.isArray(logic)) {\n return logic.map(function(l) {\n return jsonLogic2.apply(l, data);\n });\n }\n if (!jsonLogic2.is_logic(logic)) {\n return logic;\n }\n var op = jsonLogic2.get_operator(logic);\n var values = logic[op];\n var i;\n var current;\n var scopedLogic;\n var scopedData;\n var initial;\n if (!Array.isArray(values)) {\n values = [values];\n }\n if (op === \"if\" || op == \"?:\") {\n for (i = 0; i < values.length - 1; i += 2) {\n if (jsonLogic2.truthy(jsonLogic2.apply(values[i], data))) {\n return jsonLogic2.apply(values[i + 1], data);\n }\n }\n if (values.length === i + 1) {\n return jsonLogic2.apply(values[i], data);\n }\n return null;\n } else if (op === \"and\") {\n for (i = 0; i < values.length; i += 1) {\n current = jsonLogic2.apply(values[i], data);\n if (!jsonLogic2.truthy(current)) {\n return current;\n }\n }\n return current;\n } else if (op === \"or\") {\n for (i = 0; i < values.length; i += 1) {\n current = jsonLogic2.apply(values[i], data);\n if (jsonLogic2.truthy(current)) {\n return current;\n }\n }\n return current;\n } else if (op === \"filter\") {\n scopedData = jsonLogic2.apply(values[0], data);\n scopedLogic = values[1];\n if (!Array.isArray(scopedData)) {\n return [];\n }\n return scopedData.filter(function(datum) {\n return jsonLogic2.truthy(jsonLogic2.apply(scopedLogic, datum));\n });\n } else if (op === \"map\") {\n scopedData = jsonLogic2.apply(values[0], data);\n scopedLogic = values[1];\n if (!Array.isArray(scopedData)) {\n return [];\n }\n return scopedData.map(function(datum) {\n return jsonLogic2.apply(scopedLogic, datum);\n });\n } else if (op === \"reduce\") {\n scopedData = jsonLogic2.apply(values[0], data);\n scopedLogic = values[1];\n initial = typeof values[2] !== \"undefined\" ? jsonLogic2.apply(values[2], data) : null;\n if (!Array.isArray(scopedData)) {\n return initial;\n }\n return scopedData.reduce(\n function(accumulator, current2) {\n return jsonLogic2.apply(\n scopedLogic,\n { current: current2, accumulator }\n );\n },\n initial\n );\n } else if (op === \"all\") {\n scopedData = jsonLogic2.apply(values[0], data);\n scopedLogic = values[1];\n if (!Array.isArray(scopedData) || !scopedData.length) {\n return false;\n }\n for (i = 0; i < scopedData.length; i += 1) {\n if (!jsonLogic2.truthy(jsonLogic2.apply(scopedLogic, scopedData[i]))) {\n return false;\n }\n }\n return true;\n } else if (op === \"none\") {\n scopedData = jsonLogic2.apply(values[0], data);\n scopedLogic = values[1];\n if (!Array.isArray(scopedData) || !scopedData.length) {\n return true;\n }\n for (i = 0; i < scopedData.length; i += 1) {\n if (jsonLogic2.truthy(jsonLogic2.apply(scopedLogic, scopedData[i]))) {\n return false;\n }\n }\n return true;\n } else if (op === \"some\") {\n scopedData = jsonLogic2.apply(values[0], data);\n scopedLogic = values[1];\n if (!Array.isArray(scopedData) || !scopedData.length) {\n return false;\n }\n for (i = 0; i < scopedData.length; i += 1) {\n if (jsonLogic2.truthy(jsonLogic2.apply(scopedLogic, scopedData[i]))) {\n return true;\n }\n }\n return false;\n }\n values = values.map(function(val) {\n return jsonLogic2.apply(val, data);\n });\n if (operations.hasOwnProperty(op) && typeof operations[op] === \"function\") {\n return operations[op].apply(data, values);\n } else if (op.indexOf(\".\") > 0) {\n var sub_ops = String(op).split(\".\");\n var operation = operations;\n for (i = 0; i < sub_ops.length; i++) {\n if (!operation.hasOwnProperty(sub_ops[i])) {\n throw new Error(\"Unrecognized operation \" + op + \" (failed at \" + sub_ops.slice(0, i + 1).join(\".\") + \")\");\n }\n operation = operation[sub_ops[i]];\n }\n return operation.apply(data, values);\n }\n throw new Error(\"Unrecognized operation \" + op);\n };\n jsonLogic2.uses_data = function(logic) {\n var collection = [];\n if (jsonLogic2.is_logic(logic)) {\n var op = jsonLogic2.get_operator(logic);\n var values = logic[op];\n if (!Array.isArray(values)) {\n values = [values];\n }\n if (op === \"var\") {\n collection.push(values[0]);\n } else {\n values.forEach(function(val) {\n collection.push.apply(collection, jsonLogic2.uses_data(val));\n });\n }\n }\n return arrayUnique(collection);\n };\n jsonLogic2.add_operation = function(name, code2) {\n operations[name] = code2;\n };\n jsonLogic2.rm_operation = function(name) {\n delete operations[name];\n };\n jsonLogic2.rule_like = function(rule, pattern) {\n if (pattern === rule) {\n return true;\n }\n if (pattern === \"@\") {\n return true;\n }\n if (pattern === \"number\") {\n return typeof rule === \"number\";\n }\n if (pattern === \"string\") {\n return typeof rule === \"string\";\n }\n if (pattern === \"array\") {\n return Array.isArray(rule) && !jsonLogic2.is_logic(rule);\n }\n if (jsonLogic2.is_logic(pattern)) {\n if (jsonLogic2.is_logic(rule)) {\n var pattern_op = jsonLogic2.get_operator(pattern);\n var rule_op = jsonLogic2.get_operator(rule);\n if (pattern_op === \"@\" || pattern_op === rule_op) {\n return jsonLogic2.rule_like(\n jsonLogic2.get_values(rule, false),\n jsonLogic2.get_values(pattern, false)\n );\n }\n }\n return false;\n }\n if (Array.isArray(pattern)) {\n if (Array.isArray(rule)) {\n if (pattern.length !== rule.length) {\n return false;\n }\n for (var i = 0; i < pattern.length; i += 1) {\n if (!jsonLogic2.rule_like(rule[i], pattern[i])) {\n return false;\n }\n }\n return true;\n } else {\n return false;\n }\n }\n return false;\n };\n return jsonLogic2;\n });\n }\n});\n\n// node_modules/.pnpm/path-to-regexp@8.3.0/node_modules/path-to-regexp/dist/index.js\nvar require_dist = __commonJS({\n \"node_modules/.pnpm/path-to-regexp@8.3.0/node_modules/path-to-regexp/dist/index.js\"(exports) {\n \"use strict\";\n Object.defineProperty(exports, \"__esModule\", { value: true });\n exports.PathError = exports.TokenData = void 0;\n exports.parse = parse;\n exports.compile = compile2;\n exports.match = match2;\n exports.pathToRegexp = pathToRegexp;\n exports.stringify = stringify;\n var DEFAULT_DELIMITER = \"/\";\n var NOOP_VALUE = (value) => value;\n var ID_START = /^[$_\\p{ID_Start}]$/u;\n var ID_CONTINUE = /^[$\\u200c\\u200d\\p{ID_Continue}]$/u;\n var SIMPLE_TOKENS = {\n // Groups.\n \"{\": \"{\",\n \"}\": \"}\",\n // Reserved.\n \"(\": \"(\",\n \")\": \")\",\n \"[\": \"[\",\n \"]\": \"]\",\n \"+\": \"+\",\n \"?\": \"?\",\n \"!\": \"!\"\n };\n function escapeText2(str) {\n return str.replace(/[{}()\\[\\]+?!:*\\\\]/g, \"\\\\$&\");\n }\n function escape3(str) {\n return str.replace(/[.+*?^${}()[\\]|/\\\\]/g, \"\\\\$&\");\n }\n var TokenData = class {\n constructor(tokens, originalPath) {\n this.tokens = tokens;\n this.originalPath = originalPath;\n }\n };\n exports.TokenData = TokenData;\n var PathError = class extends TypeError {\n constructor(message, originalPath) {\n let text2 = message;\n if (originalPath)\n text2 += `: ${originalPath}`;\n text2 += `; visit https://git.new/pathToRegexpError for info`;\n super(text2);\n this.originalPath = originalPath;\n }\n };\n exports.PathError = PathError;\n function parse(str, options = {}) {\n const { encodePath = NOOP_VALUE } = options;\n const chars = [...str];\n const tokens = [];\n let index = 0;\n let pos = 0;\n function name() {\n let value = \"\";\n if (ID_START.test(chars[index])) {\n do {\n value += chars[index++];\n } while (ID_CONTINUE.test(chars[index]));\n } else if (chars[index] === '\"') {\n let quoteStart = index;\n while (index++ < chars.length) {\n if (chars[index] === '\"') {\n index++;\n quoteStart = 0;\n break;\n }\n if (chars[index] === \"\\\\\")\n index++;\n value += chars[index];\n }\n if (quoteStart) {\n throw new PathError(`Unterminated quote at index ${quoteStart}`, str);\n }\n }\n if (!value) {\n throw new PathError(`Missing parameter name at index ${index}`, str);\n }\n return value;\n }\n while (index < chars.length) {\n const value = chars[index];\n const type = SIMPLE_TOKENS[value];\n if (type) {\n tokens.push({ type, index: index++, value });\n } else if (value === \"\\\\\") {\n tokens.push({ type: \"escape\", index: index++, value: chars[index++] });\n } else if (value === \":\") {\n tokens.push({ type: \"param\", index: index++, value: name() });\n } else if (value === \"*\") {\n tokens.push({ type: \"wildcard\", index: index++, value: name() });\n } else {\n tokens.push({ type: \"char\", index: index++, value });\n }\n }\n tokens.push({ type: \"end\", index, value: \"\" });\n function consumeUntil(endType) {\n const output = [];\n while (true) {\n const token = tokens[pos++];\n if (token.type === endType)\n break;\n if (token.type === \"char\" || token.type === \"escape\") {\n let path = token.value;\n let cur = tokens[pos];\n while (cur.type === \"char\" || cur.type === \"escape\") {\n path += cur.value;\n cur = tokens[++pos];\n }\n output.push({\n type: \"text\",\n value: encodePath(path)\n });\n continue;\n }\n if (token.type === \"param\" || token.type === \"wildcard\") {\n output.push({\n type: token.type,\n name: token.value\n });\n continue;\n }\n if (token.type === \"{\") {\n output.push({\n type: \"group\",\n tokens: consumeUntil(\"}\")\n });\n continue;\n }\n throw new PathError(`Unexpected ${token.type} at index ${token.index}, expected ${endType}`, str);\n }\n return output;\n }\n return new TokenData(consumeUntil(\"end\"), str);\n }\n function compile2(path, options = {}) {\n const { encode: encode3 = encodeURIComponent, delimiter: delimiter2 = DEFAULT_DELIMITER } = options;\n const data = typeof path === \"object\" ? path : parse(path, options);\n const fn = tokensToFunction(data.tokens, delimiter2, encode3);\n return function path2(params = {}) {\n const [path3, ...missing] = fn(params);\n if (missing.length) {\n throw new TypeError(`Missing parameters: ${missing.join(\", \")}`);\n }\n return path3;\n };\n }\n function tokensToFunction(tokens, delimiter2, encode3) {\n const encoders = tokens.map((token) => tokenToFunction(token, delimiter2, encode3));\n return (data) => {\n const result = [\"\"];\n for (const encoder of encoders) {\n const [value, ...extras] = encoder(data);\n result[0] += value;\n result.push(...extras);\n }\n return result;\n };\n }\n function tokenToFunction(token, delimiter2, encode3) {\n if (token.type === \"text\")\n return () => [token.value];\n if (token.type === \"group\") {\n const fn = tokensToFunction(token.tokens, delimiter2, encode3);\n return (data) => {\n const [value, ...missing] = fn(data);\n if (!missing.length)\n return [value];\n return [\"\"];\n };\n }\n const encodeValue = encode3 || NOOP_VALUE;\n if (token.type === \"wildcard\" && encode3 !== false) {\n return (data) => {\n const value = data[token.name];\n if (value == null)\n return [\"\", token.name];\n if (!Array.isArray(value) || value.length === 0) {\n throw new TypeError(`Expected \"${token.name}\" to be a non-empty array`);\n }\n return [\n value.map((value2, index) => {\n if (typeof value2 !== \"string\") {\n throw new TypeError(`Expected \"${token.name}/${index}\" to be a string`);\n }\n return encodeValue(value2);\n }).join(delimiter2)\n ];\n };\n }\n return (data) => {\n const value = data[token.name];\n if (value == null)\n return [\"\", token.name];\n if (typeof value !== \"string\") {\n throw new TypeError(`Expected \"${token.name}\" to be a string`);\n }\n return [encodeValue(value)];\n };\n }\n function match2(path, options = {}) {\n const { decode: decode3 = decodeURIComponent, delimiter: delimiter2 = DEFAULT_DELIMITER } = options;\n const { regexp, keys } = pathToRegexp(path, options);\n const decoders = keys.map((key) => {\n if (decode3 === false)\n return NOOP_VALUE;\n if (key.type === \"param\")\n return decode3;\n return (value) => value.split(delimiter2).map(decode3);\n });\n return function match3(input) {\n const m = regexp.exec(input);\n if (!m)\n return false;\n const path2 = m[0];\n const params = /* @__PURE__ */ Object.create(null);\n for (let i = 1; i < m.length; i++) {\n if (m[i] === void 0)\n continue;\n const key = keys[i - 1];\n const decoder = decoders[i - 1];\n params[key.name] = decoder(m[i]);\n }\n return { path: path2, params };\n };\n }\n function pathToRegexp(path, options = {}) {\n const { delimiter: delimiter2 = DEFAULT_DELIMITER, end = true, sensitive = false, trailing = true } = options;\n const keys = [];\n const flags = sensitive ? \"\" : \"i\";\n const sources = [];\n for (const input of pathsToArray(path, [])) {\n const data = typeof input === \"object\" ? input : parse(input, options);\n for (const tokens of flatten(data.tokens, 0, [])) {\n sources.push(toRegExpSource(tokens, delimiter2, keys, data.originalPath));\n }\n }\n let pattern = `^(?:${sources.join(\"|\")})`;\n if (trailing)\n pattern += `(?:${escape3(delimiter2)}$)?`;\n pattern += end ? \"$\" : `(?=${escape3(delimiter2)}|$)`;\n const regexp = new RegExp(pattern, flags);\n return { regexp, keys };\n }\n function pathsToArray(paths, init) {\n if (Array.isArray(paths)) {\n for (const p of paths)\n pathsToArray(p, init);\n } else {\n init.push(paths);\n }\n return init;\n }\n function* flatten(tokens, index, init) {\n if (index === tokens.length) {\n return yield init;\n }\n const token = tokens[index];\n if (token.type === \"group\") {\n for (const seq of flatten(token.tokens, 0, init.slice())) {\n yield* flatten(tokens, index + 1, seq);\n }\n } else {\n init.push(token);\n }\n yield* flatten(tokens, index + 1, init);\n }\n function toRegExpSource(tokens, delimiter2, keys, originalPath) {\n let result = \"\";\n let backtrack = \"\";\n let isSafeSegmentParam = true;\n for (const token of tokens) {\n if (token.type === \"text\") {\n result += escape3(token.value);\n backtrack += token.value;\n isSafeSegmentParam || (isSafeSegmentParam = token.value.includes(delimiter2));\n continue;\n }\n if (token.type === \"param\" || token.type === \"wildcard\") {\n if (!isSafeSegmentParam && !backtrack) {\n throw new PathError(`Missing text before \"${token.name}\" ${token.type}`, originalPath);\n }\n if (token.type === \"param\") {\n result += `(${negate(delimiter2, isSafeSegmentParam ? \"\" : backtrack)}+)`;\n } else {\n result += `([\\\\s\\\\S]+)`;\n }\n keys.push(token);\n backtrack = \"\";\n isSafeSegmentParam = false;\n continue;\n }\n }\n return result;\n }\n function negate(delimiter2, backtrack) {\n if (backtrack.length < 2) {\n if (delimiter2.length < 2)\n return `[^${escape3(delimiter2 + backtrack)}]`;\n return `(?:(?!${escape3(delimiter2)})[^${escape3(backtrack)}])`;\n }\n if (delimiter2.length < 2) {\n return `(?:(?!${escape3(backtrack)})[^${escape3(delimiter2)}])`;\n }\n return `(?:(?!${escape3(backtrack)}|${escape3(delimiter2)})[\\\\s\\\\S])`;\n }\n function stringifyTokens(tokens) {\n let value = \"\";\n let i = 0;\n function name(value2) {\n const isSafe = isNameSafe(value2) && isNextNameSafe(tokens[i]);\n return isSafe ? value2 : JSON.stringify(value2);\n }\n while (i < tokens.length) {\n const token = tokens[i++];\n if (token.type === \"text\") {\n value += escapeText2(token.value);\n continue;\n }\n if (token.type === \"group\") {\n value += `{${stringifyTokens(token.tokens)}}`;\n continue;\n }\n if (token.type === \"param\") {\n value += `:${name(token.name)}`;\n continue;\n }\n if (token.type === \"wildcard\") {\n value += `*${name(token.name)}`;\n continue;\n }\n throw new TypeError(`Unknown token type: ${token.type}`);\n }\n return value;\n }\n function stringify(data) {\n return stringifyTokens(data.tokens);\n }\n function isNameSafe(name) {\n const [first, ...rest] = name;\n return ID_START.test(first) && rest.every((char) => ID_CONTINUE.test(char));\n }\n function isNextNameSafe(token) {\n if (token && token.type === \"text\")\n return !ID_CONTINUE.test(token.value[0]);\n return true;\n }\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/constants.js\nvar require_constants = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/constants.js\"(exports, module) {\n \"use strict\";\n var SEMVER_SPEC_VERSION = \"2.0.0\";\n var MAX_LENGTH = 256;\n var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || /* istanbul ignore next */\n 9007199254740991;\n var MAX_SAFE_COMPONENT_LENGTH = 16;\n var MAX_SAFE_BUILD_LENGTH = MAX_LENGTH - 6;\n var RELEASE_TYPES = [\n \"major\",\n \"premajor\",\n \"minor\",\n \"preminor\",\n \"patch\",\n \"prepatch\",\n \"prerelease\"\n ];\n module.exports = {\n MAX_LENGTH,\n MAX_SAFE_COMPONENT_LENGTH,\n MAX_SAFE_BUILD_LENGTH,\n MAX_SAFE_INTEGER,\n RELEASE_TYPES,\n SEMVER_SPEC_VERSION,\n FLAG_INCLUDE_PRERELEASE: 1,\n FLAG_LOOSE: 2\n };\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/debug.js\nvar require_debug = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/debug.js\"(exports, module) {\n \"use strict\";\n var debug = typeof process === \"object\" && process.env && process.env.NODE_DEBUG && /\\bsemver\\b/i.test(process.env.NODE_DEBUG) ? (...args) => console.error(\"SEMVER\", ...args) : () => {\n };\n module.exports = debug;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/re.js\nvar require_re = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/re.js\"(exports, module) {\n \"use strict\";\n var {\n MAX_SAFE_COMPONENT_LENGTH,\n MAX_SAFE_BUILD_LENGTH,\n MAX_LENGTH\n } = require_constants();\n var debug = require_debug();\n exports = module.exports = {};\n var re = exports.re = [];\n var safeRe = exports.safeRe = [];\n var src = exports.src = [];\n var safeSrc = exports.safeSrc = [];\n var t = exports.t = {};\n var R = 0;\n var LETTERDASHNUMBER = \"[a-zA-Z0-9-]\";\n var safeRegexReplacements = [\n [\"\\\\s\", 1],\n [\"\\\\d\", MAX_LENGTH],\n [LETTERDASHNUMBER, MAX_SAFE_BUILD_LENGTH]\n ];\n var makeSafeRegex = (value) => {\n for (const [token, max2] of safeRegexReplacements) {\n value = value.split(`${token}*`).join(`${token}{0,${max2}}`).split(`${token}+`).join(`${token}{1,${max2}}`);\n }\n return value;\n };\n var createToken = (name, value, isGlobal) => {\n const safe = makeSafeRegex(value);\n const index = R++;\n debug(name, index, value);\n t[name] = index;\n src[index] = value;\n safeSrc[index] = safe;\n re[index] = new RegExp(value, isGlobal ? \"g\" : void 0);\n safeRe[index] = new RegExp(safe, isGlobal ? \"g\" : void 0);\n };\n createToken(\"NUMERICIDENTIFIER\", \"0|[1-9]\\\\d*\");\n createToken(\"NUMERICIDENTIFIERLOOSE\", \"\\\\d+\");\n createToken(\"NONNUMERICIDENTIFIER\", `\\\\d*[a-zA-Z-]${LETTERDASHNUMBER}*`);\n createToken(\"MAINVERSION\", `(${src[t.NUMERICIDENTIFIER]})\\\\.(${src[t.NUMERICIDENTIFIER]})\\\\.(${src[t.NUMERICIDENTIFIER]})`);\n createToken(\"MAINVERSIONLOOSE\", `(${src[t.NUMERICIDENTIFIERLOOSE]})\\\\.(${src[t.NUMERICIDENTIFIERLOOSE]})\\\\.(${src[t.NUMERICIDENTIFIERLOOSE]})`);\n createToken(\"PRERELEASEIDENTIFIER\", `(?:${src[t.NONNUMERICIDENTIFIER]}|${src[t.NUMERICIDENTIFIER]})`);\n createToken(\"PRERELEASEIDENTIFIERLOOSE\", `(?:${src[t.NONNUMERICIDENTIFIER]}|${src[t.NUMERICIDENTIFIERLOOSE]})`);\n createToken(\"PRERELEASE\", `(?:-(${src[t.PRERELEASEIDENTIFIER]}(?:\\\\.${src[t.PRERELEASEIDENTIFIER]})*))`);\n createToken(\"PRERELEASELOOSE\", `(?:-?(${src[t.PRERELEASEIDENTIFIERLOOSE]}(?:\\\\.${src[t.PRERELEASEIDENTIFIERLOOSE]})*))`);\n createToken(\"BUILDIDENTIFIER\", `${LETTERDASHNUMBER}+`);\n createToken(\"BUILD\", `(?:\\\\+(${src[t.BUILDIDENTIFIER]}(?:\\\\.${src[t.BUILDIDENTIFIER]})*))`);\n createToken(\"FULLPLAIN\", `v?${src[t.MAINVERSION]}${src[t.PRERELEASE]}?${src[t.BUILD]}?`);\n createToken(\"FULL\", `^${src[t.FULLPLAIN]}$`);\n createToken(\"LOOSEPLAIN\", `[v=\\\\s]*${src[t.MAINVERSIONLOOSE]}${src[t.PRERELEASELOOSE]}?${src[t.BUILD]}?`);\n createToken(\"LOOSE\", `^${src[t.LOOSEPLAIN]}$`);\n createToken(\"GTLT\", \"((?:<|>)?=?)\");\n createToken(\"XRANGEIDENTIFIERLOOSE\", `${src[t.NUMERICIDENTIFIERLOOSE]}|x|X|\\\\*`);\n createToken(\"XRANGEIDENTIFIER\", `${src[t.NUMERICIDENTIFIER]}|x|X|\\\\*`);\n createToken(\"XRANGEPLAIN\", `[v=\\\\s]*(${src[t.XRANGEIDENTIFIER]})(?:\\\\.(${src[t.XRANGEIDENTIFIER]})(?:\\\\.(${src[t.XRANGEIDENTIFIER]})(?:${src[t.PRERELEASE]})?${src[t.BUILD]}?)?)?`);\n createToken(\"XRANGEPLAINLOOSE\", `[v=\\\\s]*(${src[t.XRANGEIDENTIFIERLOOSE]})(?:\\\\.(${src[t.XRANGEIDENTIFIERLOOSE]})(?:\\\\.(${src[t.XRANGEIDENTIFIERLOOSE]})(?:${src[t.PRERELEASELOOSE]})?${src[t.BUILD]}?)?)?`);\n createToken(\"XRANGE\", `^${src[t.GTLT]}\\\\s*${src[t.XRANGEPLAIN]}$`);\n createToken(\"XRANGELOOSE\", `^${src[t.GTLT]}\\\\s*${src[t.XRANGEPLAINLOOSE]}$`);\n createToken(\"COERCEPLAIN\", `${\"(^|[^\\\\d])(\\\\d{1,\"}${MAX_SAFE_COMPONENT_LENGTH}})(?:\\\\.(\\\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?(?:\\\\.(\\\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?`);\n createToken(\"COERCE\", `${src[t.COERCEPLAIN]}(?:$|[^\\\\d])`);\n createToken(\"COERCEFULL\", src[t.COERCEPLAIN] + `(?:${src[t.PRERELEASE]})?(?:${src[t.BUILD]})?(?:$|[^\\\\d])`);\n createToken(\"COERCERTL\", src[t.COERCE], true);\n createToken(\"COERCERTLFULL\", src[t.COERCEFULL], true);\n createToken(\"LONETILDE\", \"(?:~>?)\");\n createToken(\"TILDETRIM\", `(\\\\s*)${src[t.LONETILDE]}\\\\s+`, true);\n exports.tildeTrimReplace = \"$1~\";\n createToken(\"TILDE\", `^${src[t.LONETILDE]}${src[t.XRANGEPLAIN]}$`);\n createToken(\"TILDELOOSE\", `^${src[t.LONETILDE]}${src[t.XRANGEPLAINLOOSE]}$`);\n createToken(\"LONECARET\", \"(?:\\\\^)\");\n createToken(\"CARETTRIM\", `(\\\\s*)${src[t.LONECARET]}\\\\s+`, true);\n exports.caretTrimReplace = \"$1^\";\n createToken(\"CARET\", `^${src[t.LONECARET]}${src[t.XRANGEPLAIN]}$`);\n createToken(\"CARETLOOSE\", `^${src[t.LONECARET]}${src[t.XRANGEPLAINLOOSE]}$`);\n createToken(\"COMPARATORLOOSE\", `^${src[t.GTLT]}\\\\s*(${src[t.LOOSEPLAIN]})$|^$`);\n createToken(\"COMPARATOR\", `^${src[t.GTLT]}\\\\s*(${src[t.FULLPLAIN]})$|^$`);\n createToken(\"COMPARATORTRIM\", `(\\\\s*)${src[t.GTLT]}\\\\s*(${src[t.LOOSEPLAIN]}|${src[t.XRANGEPLAIN]})`, true);\n exports.comparatorTrimReplace = \"$1$2$3\";\n createToken(\"HYPHENRANGE\", `^\\\\s*(${src[t.XRANGEPLAIN]})\\\\s+-\\\\s+(${src[t.XRANGEPLAIN]})\\\\s*$`);\n createToken(\"HYPHENRANGELOOSE\", `^\\\\s*(${src[t.XRANGEPLAINLOOSE]})\\\\s+-\\\\s+(${src[t.XRANGEPLAINLOOSE]})\\\\s*$`);\n createToken(\"STAR\", \"(<|>)?=?\\\\s*\\\\*\");\n createToken(\"GTE0\", \"^\\\\s*>=\\\\s*0\\\\.0\\\\.0\\\\s*$\");\n createToken(\"GTE0PRE\", \"^\\\\s*>=\\\\s*0\\\\.0\\\\.0-0\\\\s*$\");\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/parse-options.js\nvar require_parse_options = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/parse-options.js\"(exports, module) {\n \"use strict\";\n var looseOption = Object.freeze({ loose: true });\n var emptyOpts = Object.freeze({});\n var parseOptions = (options) => {\n if (!options) {\n return emptyOpts;\n }\n if (typeof options !== \"object\") {\n return looseOption;\n }\n return options;\n };\n module.exports = parseOptions;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/identifiers.js\nvar require_identifiers = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/identifiers.js\"(exports, module) {\n \"use strict\";\n var numeric = /^[0-9]+$/;\n var compareIdentifiers = (a, b) => {\n if (typeof a === \"number\" && typeof b === \"number\") {\n return a === b ? 0 : a < b ? -1 : 1;\n }\n const anum = numeric.test(a);\n const bnum = numeric.test(b);\n if (anum && bnum) {\n a = +a;\n b = +b;\n }\n return a === b ? 0 : anum && !bnum ? -1 : bnum && !anum ? 1 : a < b ? -1 : 1;\n };\n var rcompareIdentifiers = (a, b) => compareIdentifiers(b, a);\n module.exports = {\n compareIdentifiers,\n rcompareIdentifiers\n };\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/classes/semver.js\nvar require_semver = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/classes/semver.js\"(exports, module) {\n \"use strict\";\n var debug = require_debug();\n var { MAX_LENGTH, MAX_SAFE_INTEGER } = require_constants();\n var { safeRe: re, t } = require_re();\n var parseOptions = require_parse_options();\n var { compareIdentifiers } = require_identifiers();\n var SemVer = class _SemVer {\n constructor(version, options) {\n options = parseOptions(options);\n if (version instanceof _SemVer) {\n if (version.loose === !!options.loose && version.includePrerelease === !!options.includePrerelease) {\n return version;\n } else {\n version = version.version;\n }\n } else if (typeof version !== \"string\") {\n throw new TypeError(`Invalid version. Must be a string. Got type \"${typeof version}\".`);\n }\n if (version.length > MAX_LENGTH) {\n throw new TypeError(\n `version is longer than ${MAX_LENGTH} characters`\n );\n }\n debug(\"SemVer\", version, options);\n this.options = options;\n this.loose = !!options.loose;\n this.includePrerelease = !!options.includePrerelease;\n const m = version.trim().match(options.loose ? re[t.LOOSE] : re[t.FULL]);\n if (!m) {\n throw new TypeError(`Invalid Version: ${version}`);\n }\n this.raw = version;\n this.major = +m[1];\n this.minor = +m[2];\n this.patch = +m[3];\n if (this.major > MAX_SAFE_INTEGER || this.major < 0) {\n throw new TypeError(\"Invalid major version\");\n }\n if (this.minor > MAX_SAFE_INTEGER || this.minor < 0) {\n throw new TypeError(\"Invalid minor version\");\n }\n if (this.patch > MAX_SAFE_INTEGER || this.patch < 0) {\n throw new TypeError(\"Invalid patch version\");\n }\n if (!m[4]) {\n this.prerelease = [];\n } else {\n this.prerelease = m[4].split(\".\").map((id) => {\n if (/^[0-9]+$/.test(id)) {\n const num = +id;\n if (num >= 0 && num < MAX_SAFE_INTEGER) {\n return num;\n }\n }\n return id;\n });\n }\n this.build = m[5] ? m[5].split(\".\") : [];\n this.format();\n }\n format() {\n this.version = `${this.major}.${this.minor}.${this.patch}`;\n if (this.prerelease.length) {\n this.version += `-${this.prerelease.join(\".\")}`;\n }\n return this.version;\n }\n toString() {\n return this.version;\n }\n compare(other) {\n debug(\"SemVer.compare\", this.version, this.options, other);\n if (!(other instanceof _SemVer)) {\n if (typeof other === \"string\" && other === this.version) {\n return 0;\n }\n other = new _SemVer(other, this.options);\n }\n if (other.version === this.version) {\n return 0;\n }\n return this.compareMain(other) || this.comparePre(other);\n }\n compareMain(other) {\n if (!(other instanceof _SemVer)) {\n other = new _SemVer(other, this.options);\n }\n if (this.major < other.major) {\n return -1;\n }\n if (this.major > other.major) {\n return 1;\n }\n if (this.minor < other.minor) {\n return -1;\n }\n if (this.minor > other.minor) {\n return 1;\n }\n if (this.patch < other.patch) {\n return -1;\n }\n if (this.patch > other.patch) {\n return 1;\n }\n return 0;\n }\n comparePre(other) {\n if (!(other instanceof _SemVer)) {\n other = new _SemVer(other, this.options);\n }\n if (this.prerelease.length && !other.prerelease.length) {\n return -1;\n } else if (!this.prerelease.length && other.prerelease.length) {\n return 1;\n } else if (!this.prerelease.length && !other.prerelease.length) {\n return 0;\n }\n let i = 0;\n do {\n const a = this.prerelease[i];\n const b = other.prerelease[i];\n debug(\"prerelease compare\", i, a, b);\n if (a === void 0 && b === void 0) {\n return 0;\n } else if (b === void 0) {\n return 1;\n } else if (a === void 0) {\n return -1;\n } else if (a === b) {\n continue;\n } else {\n return compareIdentifiers(a, b);\n }\n } while (++i);\n }\n compareBuild(other) {\n if (!(other instanceof _SemVer)) {\n other = new _SemVer(other, this.options);\n }\n let i = 0;\n do {\n const a = this.build[i];\n const b = other.build[i];\n debug(\"build compare\", i, a, b);\n if (a === void 0 && b === void 0) {\n return 0;\n } else if (b === void 0) {\n return 1;\n } else if (a === void 0) {\n return -1;\n } else if (a === b) {\n continue;\n } else {\n return compareIdentifiers(a, b);\n }\n } while (++i);\n }\n // preminor will bump the version up to the next minor release, and immediately\n // down to pre-release. premajor and prepatch work the same way.\n inc(release, identifier, identifierBase) {\n if (release.startsWith(\"pre\")) {\n if (!identifier && identifierBase === false) {\n throw new Error(\"invalid increment argument: identifier is empty\");\n }\n if (identifier) {\n const match2 = `-${identifier}`.match(this.options.loose ? re[t.PRERELEASELOOSE] : re[t.PRERELEASE]);\n if (!match2 || match2[1] !== identifier) {\n throw new Error(`invalid identifier: ${identifier}`);\n }\n }\n }\n switch (release) {\n case \"premajor\":\n this.prerelease.length = 0;\n this.patch = 0;\n this.minor = 0;\n this.major++;\n this.inc(\"pre\", identifier, identifierBase);\n break;\n case \"preminor\":\n this.prerelease.length = 0;\n this.patch = 0;\n this.minor++;\n this.inc(\"pre\", identifier, identifierBase);\n break;\n case \"prepatch\":\n this.prerelease.length = 0;\n this.inc(\"patch\", identifier, identifierBase);\n this.inc(\"pre\", identifier, identifierBase);\n break;\n // If the input is a non-prerelease version, this acts the same as\n // prepatch.\n case \"prerelease\":\n if (this.prerelease.length === 0) {\n this.inc(\"patch\", identifier, identifierBase);\n }\n this.inc(\"pre\", identifier, identifierBase);\n break;\n case \"release\":\n if (this.prerelease.length === 0) {\n throw new Error(`version ${this.raw} is not a prerelease`);\n }\n this.prerelease.length = 0;\n break;\n case \"major\":\n if (this.minor !== 0 || this.patch !== 0 || this.prerelease.length === 0) {\n this.major++;\n }\n this.minor = 0;\n this.patch = 0;\n this.prerelease = [];\n break;\n case \"minor\":\n if (this.patch !== 0 || this.prerelease.length === 0) {\n this.minor++;\n }\n this.patch = 0;\n this.prerelease = [];\n break;\n case \"patch\":\n if (this.prerelease.length === 0) {\n this.patch++;\n }\n this.prerelease = [];\n break;\n // This probably shouldn't be used publicly.\n // 1.0.0 'pre' would become 1.0.0-0 which is the wrong direction.\n case \"pre\": {\n const base2 = Number(identifierBase) ? 1 : 0;\n if (this.prerelease.length === 0) {\n this.prerelease = [base2];\n } else {\n let i = this.prerelease.length;\n while (--i >= 0) {\n if (typeof this.prerelease[i] === \"number\") {\n this.prerelease[i]++;\n i = -2;\n }\n }\n if (i === -1) {\n if (identifier === this.prerelease.join(\".\") && identifierBase === false) {\n throw new Error(\"invalid increment argument: identifier already exists\");\n }\n this.prerelease.push(base2);\n }\n }\n if (identifier) {\n let prerelease = [identifier, base2];\n if (identifierBase === false) {\n prerelease = [identifier];\n }\n if (compareIdentifiers(this.prerelease[0], identifier) === 0) {\n if (isNaN(this.prerelease[1])) {\n this.prerelease = prerelease;\n }\n } else {\n this.prerelease = prerelease;\n }\n }\n break;\n }\n default:\n throw new Error(`invalid increment argument: ${release}`);\n }\n this.raw = this.format();\n if (this.build.length) {\n this.raw += `+${this.build.join(\".\")}`;\n }\n return this;\n }\n };\n module.exports = SemVer;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/parse.js\nvar require_parse = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/parse.js\"(exports, module) {\n \"use strict\";\n var SemVer = require_semver();\n var parse = (version, options, throwErrors = false) => {\n if (version instanceof SemVer) {\n return version;\n }\n try {\n return new SemVer(version, options);\n } catch (er) {\n if (!throwErrors) {\n return null;\n }\n throw er;\n }\n };\n module.exports = parse;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/valid.js\nvar require_valid = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/valid.js\"(exports, module) {\n \"use strict\";\n var parse = require_parse();\n var valid = (version, options) => {\n const v = parse(version, options);\n return v ? v.version : null;\n };\n module.exports = valid;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/clean.js\nvar require_clean = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/clean.js\"(exports, module) {\n \"use strict\";\n var parse = require_parse();\n var clean2 = (version, options) => {\n const s = parse(version.trim().replace(/^[=v]+/, \"\"), options);\n return s ? s.version : null;\n };\n module.exports = clean2;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/inc.js\nvar require_inc = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/inc.js\"(exports, module) {\n \"use strict\";\n var SemVer = require_semver();\n var inc = (version, release, options, identifier, identifierBase) => {\n if (typeof options === \"string\") {\n identifierBase = identifier;\n identifier = options;\n options = void 0;\n }\n try {\n return new SemVer(\n version instanceof SemVer ? version.version : version,\n options\n ).inc(release, identifier, identifierBase).version;\n } catch (er) {\n return null;\n }\n };\n module.exports = inc;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/diff.js\nvar require_diff = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/diff.js\"(exports, module) {\n \"use strict\";\n var parse = require_parse();\n var diff = (version1, version2) => {\n const v1 = parse(version1, null, true);\n const v2 = parse(version2, null, true);\n const comparison = v1.compare(v2);\n if (comparison === 0) {\n return null;\n }\n const v1Higher = comparison > 0;\n const highVersion = v1Higher ? v1 : v2;\n const lowVersion = v1Higher ? v2 : v1;\n const highHasPre = !!highVersion.prerelease.length;\n const lowHasPre = !!lowVersion.prerelease.length;\n if (lowHasPre && !highHasPre) {\n if (!lowVersion.patch && !lowVersion.minor) {\n return \"major\";\n }\n if (lowVersion.compareMain(highVersion) === 0) {\n if (lowVersion.minor && !lowVersion.patch) {\n return \"minor\";\n }\n return \"patch\";\n }\n }\n const prefix = highHasPre ? \"pre\" : \"\";\n if (v1.major !== v2.major) {\n return prefix + \"major\";\n }\n if (v1.minor !== v2.minor) {\n return prefix + \"minor\";\n }\n if (v1.patch !== v2.patch) {\n return prefix + \"patch\";\n }\n return \"prerelease\";\n };\n module.exports = diff;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/major.js\nvar require_major = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/major.js\"(exports, module) {\n \"use strict\";\n var SemVer = require_semver();\n var major = (a, loose) => new SemVer(a, loose).major;\n module.exports = major;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/minor.js\nvar require_minor = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/minor.js\"(exports, module) {\n \"use strict\";\n var SemVer = require_semver();\n var minor = (a, loose) => new SemVer(a, loose).minor;\n module.exports = minor;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/patch.js\nvar require_patch = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/patch.js\"(exports, module) {\n \"use strict\";\n var SemVer = require_semver();\n var patch = (a, loose) => new SemVer(a, loose).patch;\n module.exports = patch;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/prerelease.js\nvar require_prerelease = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/prerelease.js\"(exports, module) {\n \"use strict\";\n var parse = require_parse();\n var prerelease = (version, options) => {\n const parsed = parse(version, options);\n return parsed && parsed.prerelease.length ? parsed.prerelease : null;\n };\n module.exports = prerelease;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/compare.js\nvar require_compare = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/compare.js\"(exports, module) {\n \"use strict\";\n var SemVer = require_semver();\n var compare = (a, b, loose) => new SemVer(a, loose).compare(new SemVer(b, loose));\n module.exports = compare;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/rcompare.js\nvar require_rcompare = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/rcompare.js\"(exports, module) {\n \"use strict\";\n var compare = require_compare();\n var rcompare = (a, b, loose) => compare(b, a, loose);\n module.exports = rcompare;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/compare-loose.js\nvar require_compare_loose = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/compare-loose.js\"(exports, module) {\n \"use strict\";\n var compare = require_compare();\n var compareLoose = (a, b) => compare(a, b, true);\n module.exports = compareLoose;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/compare-build.js\nvar require_compare_build = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/compare-build.js\"(exports, module) {\n \"use strict\";\n var SemVer = require_semver();\n var compareBuild = (a, b, loose) => {\n const versionA = new SemVer(a, loose);\n const versionB = new SemVer(b, loose);\n return versionA.compare(versionB) || versionA.compareBuild(versionB);\n };\n module.exports = compareBuild;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/sort.js\nvar require_sort = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/sort.js\"(exports, module) {\n \"use strict\";\n var compareBuild = require_compare_build();\n var sort = (list2, loose) => list2.sort((a, b) => compareBuild(a, b, loose));\n module.exports = sort;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/rsort.js\nvar require_rsort = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/rsort.js\"(exports, module) {\n \"use strict\";\n var compareBuild = require_compare_build();\n var rsort = (list2, loose) => list2.sort((a, b) => compareBuild(b, a, loose));\n module.exports = rsort;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/gt.js\nvar require_gt = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/gt.js\"(exports, module) {\n \"use strict\";\n var compare = require_compare();\n var gt = (a, b, loose) => compare(a, b, loose) > 0;\n module.exports = gt;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/lt.js\nvar require_lt = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/lt.js\"(exports, module) {\n \"use strict\";\n var compare = require_compare();\n var lt = (a, b, loose) => compare(a, b, loose) < 0;\n module.exports = lt;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/eq.js\nvar require_eq = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/eq.js\"(exports, module) {\n \"use strict\";\n var compare = require_compare();\n var eq = (a, b, loose) => compare(a, b, loose) === 0;\n module.exports = eq;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/neq.js\nvar require_neq = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/neq.js\"(exports, module) {\n \"use strict\";\n var compare = require_compare();\n var neq = (a, b, loose) => compare(a, b, loose) !== 0;\n module.exports = neq;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/gte.js\nvar require_gte = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/gte.js\"(exports, module) {\n \"use strict\";\n var compare = require_compare();\n var gte = (a, b, loose) => compare(a, b, loose) >= 0;\n module.exports = gte;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/lte.js\nvar require_lte = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/lte.js\"(exports, module) {\n \"use strict\";\n var compare = require_compare();\n var lte = (a, b, loose) => compare(a, b, loose) <= 0;\n module.exports = lte;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/cmp.js\nvar require_cmp = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/cmp.js\"(exports, module) {\n \"use strict\";\n var eq = require_eq();\n var neq = require_neq();\n var gt = require_gt();\n var gte = require_gte();\n var lt = require_lt();\n var lte = require_lte();\n var cmp = (a, op, b, loose) => {\n switch (op) {\n case \"===\":\n if (typeof a === \"object\") {\n a = a.version;\n }\n if (typeof b === \"object\") {\n b = b.version;\n }\n return a === b;\n case \"!==\":\n if (typeof a === \"object\") {\n a = a.version;\n }\n if (typeof b === \"object\") {\n b = b.version;\n }\n return a !== b;\n case \"\":\n case \"=\":\n case \"==\":\n return eq(a, b, loose);\n case \"!=\":\n return neq(a, b, loose);\n case \">\":\n return gt(a, b, loose);\n case \">=\":\n return gte(a, b, loose);\n case \"<\":\n return lt(a, b, loose);\n case \"<=\":\n return lte(a, b, loose);\n default:\n throw new TypeError(`Invalid operator: ${op}`);\n }\n };\n module.exports = cmp;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/coerce.js\nvar require_coerce = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/coerce.js\"(exports, module) {\n \"use strict\";\n var SemVer = require_semver();\n var parse = require_parse();\n var { safeRe: re, t } = require_re();\n var coerce = (version, options) => {\n if (version instanceof SemVer) {\n return version;\n }\n if (typeof version === \"number\") {\n version = String(version);\n }\n if (typeof version !== \"string\") {\n return null;\n }\n options = options || {};\n let match2 = null;\n if (!options.rtl) {\n match2 = version.match(options.includePrerelease ? re[t.COERCEFULL] : re[t.COERCE]);\n } else {\n const coerceRtlRegex = options.includePrerelease ? re[t.COERCERTLFULL] : re[t.COERCERTL];\n let next;\n while ((next = coerceRtlRegex.exec(version)) && (!match2 || match2.index + match2[0].length !== version.length)) {\n if (!match2 || next.index + next[0].length !== match2.index + match2[0].length) {\n match2 = next;\n }\n coerceRtlRegex.lastIndex = next.index + next[1].length + next[2].length;\n }\n coerceRtlRegex.lastIndex = -1;\n }\n if (match2 === null) {\n return null;\n }\n const major = match2[2];\n const minor = match2[3] || \"0\";\n const patch = match2[4] || \"0\";\n const prerelease = options.includePrerelease && match2[5] ? `-${match2[5]}` : \"\";\n const build = options.includePrerelease && match2[6] ? `+${match2[6]}` : \"\";\n return parse(`${major}.${minor}.${patch}${prerelease}${build}`, options);\n };\n module.exports = coerce;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/lrucache.js\nvar require_lrucache = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/lrucache.js\"(exports, module) {\n \"use strict\";\n var LRUCache = class {\n constructor() {\n this.max = 1e3;\n this.map = /* @__PURE__ */ new Map();\n }\n get(key) {\n const value = this.map.get(key);\n if (value === void 0) {\n return void 0;\n } else {\n this.map.delete(key);\n this.map.set(key, value);\n return value;\n }\n }\n delete(key) {\n return this.map.delete(key);\n }\n set(key, value) {\n const deleted = this.delete(key);\n if (!deleted && value !== void 0) {\n if (this.map.size >= this.max) {\n const firstKey = this.map.keys().next().value;\n this.delete(firstKey);\n }\n this.map.set(key, value);\n }\n return this;\n }\n };\n module.exports = LRUCache;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/classes/range.js\nvar require_range = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/classes/range.js\"(exports, module) {\n \"use strict\";\n var SPACE_CHARACTERS = /\\s+/g;\n var Range = class _Range {\n constructor(range, options) {\n options = parseOptions(options);\n if (range instanceof _Range) {\n if (range.loose === !!options.loose && range.includePrerelease === !!options.includePrerelease) {\n return range;\n } else {\n return new _Range(range.raw, options);\n }\n }\n if (range instanceof Comparator) {\n this.raw = range.value;\n this.set = [[range]];\n this.formatted = void 0;\n return this;\n }\n this.options = options;\n this.loose = !!options.loose;\n this.includePrerelease = !!options.includePrerelease;\n this.raw = range.trim().replace(SPACE_CHARACTERS, \" \");\n this.set = this.raw.split(\"||\").map((r) => this.parseRange(r.trim())).filter((c) => c.length);\n if (!this.set.length) {\n throw new TypeError(`Invalid SemVer Range: ${this.raw}`);\n }\n if (this.set.length > 1) {\n const first = this.set[0];\n this.set = this.set.filter((c) => !isNullSet(c[0]));\n if (this.set.length === 0) {\n this.set = [first];\n } else if (this.set.length > 1) {\n for (const c of this.set) {\n if (c.length === 1 && isAny(c[0])) {\n this.set = [c];\n break;\n }\n }\n }\n }\n this.formatted = void 0;\n }\n get range() {\n if (this.formatted === void 0) {\n this.formatted = \"\";\n for (let i = 0; i < this.set.length; i++) {\n if (i > 0) {\n this.formatted += \"||\";\n }\n const comps = this.set[i];\n for (let k = 0; k < comps.length; k++) {\n if (k > 0) {\n this.formatted += \" \";\n }\n this.formatted += comps[k].toString().trim();\n }\n }\n }\n return this.formatted;\n }\n format() {\n return this.range;\n }\n toString() {\n return this.range;\n }\n parseRange(range) {\n const memoOpts = (this.options.includePrerelease && FLAG_INCLUDE_PRERELEASE) | (this.options.loose && FLAG_LOOSE);\n const memoKey = memoOpts + \":\" + range;\n const cached = cache.get(memoKey);\n if (cached) {\n return cached;\n }\n const loose = this.options.loose;\n const hr2 = loose ? re[t.HYPHENRANGELOOSE] : re[t.HYPHENRANGE];\n range = range.replace(hr2, hyphenReplace(this.options.includePrerelease));\n debug(\"hyphen replace\", range);\n range = range.replace(re[t.COMPARATORTRIM], comparatorTrimReplace);\n debug(\"comparator trim\", range);\n range = range.replace(re[t.TILDETRIM], tildeTrimReplace);\n debug(\"tilde trim\", range);\n range = range.replace(re[t.CARETTRIM], caretTrimReplace);\n debug(\"caret trim\", range);\n let rangeList = range.split(\" \").map((comp) => parseComparator(comp, this.options)).join(\" \").split(/\\s+/).map((comp) => replaceGTE0(comp, this.options));\n if (loose) {\n rangeList = rangeList.filter((comp) => {\n debug(\"loose invalid filter\", comp, this.options);\n return !!comp.match(re[t.COMPARATORLOOSE]);\n });\n }\n debug(\"range list\", rangeList);\n const rangeMap = /* @__PURE__ */ new Map();\n const comparators = rangeList.map((comp) => new Comparator(comp, this.options));\n for (const comp of comparators) {\n if (isNullSet(comp)) {\n return [comp];\n }\n rangeMap.set(comp.value, comp);\n }\n if (rangeMap.size > 1 && rangeMap.has(\"\")) {\n rangeMap.delete(\"\");\n }\n const result = [...rangeMap.values()];\n cache.set(memoKey, result);\n return result;\n }\n intersects(range, options) {\n if (!(range instanceof _Range)) {\n throw new TypeError(\"a Range is required\");\n }\n return this.set.some((thisComparators) => {\n return isSatisfiable(thisComparators, options) && range.set.some((rangeComparators) => {\n return isSatisfiable(rangeComparators, options) && thisComparators.every((thisComparator) => {\n return rangeComparators.every((rangeComparator) => {\n return thisComparator.intersects(rangeComparator, options);\n });\n });\n });\n });\n }\n // if ANY of the sets match ALL of its comparators, then pass\n test(version) {\n if (!version) {\n return false;\n }\n if (typeof version === \"string\") {\n try {\n version = new SemVer(version, this.options);\n } catch (er) {\n return false;\n }\n }\n for (let i = 0; i < this.set.length; i++) {\n if (testSet(this.set[i], version, this.options)) {\n return true;\n }\n }\n return false;\n }\n };\n module.exports = Range;\n var LRU = require_lrucache();\n var cache = new LRU();\n var parseOptions = require_parse_options();\n var Comparator = require_comparator();\n var debug = require_debug();\n var SemVer = require_semver();\n var {\n safeRe: re,\n t,\n comparatorTrimReplace,\n tildeTrimReplace,\n caretTrimReplace\n } = require_re();\n var { FLAG_INCLUDE_PRERELEASE, FLAG_LOOSE } = require_constants();\n var isNullSet = (c) => c.value === \"<0.0.0-0\";\n var isAny = (c) => c.value === \"\";\n var isSatisfiable = (comparators, options) => {\n let result = true;\n const remainingComparators = comparators.slice();\n let testComparator = remainingComparators.pop();\n while (result && remainingComparators.length) {\n result = remainingComparators.every((otherComparator) => {\n return testComparator.intersects(otherComparator, options);\n });\n testComparator = remainingComparators.pop();\n }\n return result;\n };\n var parseComparator = (comp, options) => {\n comp = comp.replace(re[t.BUILD], \"\");\n debug(\"comp\", comp, options);\n comp = replaceCarets(comp, options);\n debug(\"caret\", comp);\n comp = replaceTildes(comp, options);\n debug(\"tildes\", comp);\n comp = replaceXRanges(comp, options);\n debug(\"xrange\", comp);\n comp = replaceStars(comp, options);\n debug(\"stars\", comp);\n return comp;\n };\n var isX = (id) => !id || id.toLowerCase() === \"x\" || id === \"*\";\n var replaceTildes = (comp, options) => {\n return comp.trim().split(/\\s+/).map((c) => replaceTilde(c, options)).join(\" \");\n };\n var replaceTilde = (comp, options) => {\n const r = options.loose ? re[t.TILDELOOSE] : re[t.TILDE];\n return comp.replace(r, (_, M, m, p, pr) => {\n debug(\"tilde\", comp, _, M, m, p, pr);\n let ret;\n if (isX(M)) {\n ret = \"\";\n } else if (isX(m)) {\n ret = `>=${M}.0.0 <${+M + 1}.0.0-0`;\n } else if (isX(p)) {\n ret = `>=${M}.${m}.0 <${M}.${+m + 1}.0-0`;\n } else if (pr) {\n debug(\"replaceTilde pr\", pr);\n ret = `>=${M}.${m}.${p}-${pr} <${M}.${+m + 1}.0-0`;\n } else {\n ret = `>=${M}.${m}.${p} <${M}.${+m + 1}.0-0`;\n }\n debug(\"tilde return\", ret);\n return ret;\n });\n };\n var replaceCarets = (comp, options) => {\n return comp.trim().split(/\\s+/).map((c) => replaceCaret(c, options)).join(\" \");\n };\n var replaceCaret = (comp, options) => {\n debug(\"caret\", comp, options);\n const r = options.loose ? re[t.CARETLOOSE] : re[t.CARET];\n const z = options.includePrerelease ? \"-0\" : \"\";\n return comp.replace(r, (_, M, m, p, pr) => {\n debug(\"caret\", comp, _, M, m, p, pr);\n let ret;\n if (isX(M)) {\n ret = \"\";\n } else if (isX(m)) {\n ret = `>=${M}.0.0${z} <${+M + 1}.0.0-0`;\n } else if (isX(p)) {\n if (M === \"0\") {\n ret = `>=${M}.${m}.0${z} <${M}.${+m + 1}.0-0`;\n } else {\n ret = `>=${M}.${m}.0${z} <${+M + 1}.0.0-0`;\n }\n } else if (pr) {\n debug(\"replaceCaret pr\", pr);\n if (M === \"0\") {\n if (m === \"0\") {\n ret = `>=${M}.${m}.${p}-${pr} <${M}.${m}.${+p + 1}-0`;\n } else {\n ret = `>=${M}.${m}.${p}-${pr} <${M}.${+m + 1}.0-0`;\n }\n } else {\n ret = `>=${M}.${m}.${p}-${pr} <${+M + 1}.0.0-0`;\n }\n } else {\n debug(\"no pr\");\n if (M === \"0\") {\n if (m === \"0\") {\n ret = `>=${M}.${m}.${p}${z} <${M}.${m}.${+p + 1}-0`;\n } else {\n ret = `>=${M}.${m}.${p}${z} <${M}.${+m + 1}.0-0`;\n }\n } else {\n ret = `>=${M}.${m}.${p} <${+M + 1}.0.0-0`;\n }\n }\n debug(\"caret return\", ret);\n return ret;\n });\n };\n var replaceXRanges = (comp, options) => {\n debug(\"replaceXRanges\", comp, options);\n return comp.split(/\\s+/).map((c) => replaceXRange(c, options)).join(\" \");\n };\n var replaceXRange = (comp, options) => {\n comp = comp.trim();\n const r = options.loose ? re[t.XRANGELOOSE] : re[t.XRANGE];\n return comp.replace(r, (ret, gtlt, M, m, p, pr) => {\n debug(\"xRange\", comp, ret, gtlt, M, m, p, pr);\n const xM = isX(M);\n const xm = xM || isX(m);\n const xp = xm || isX(p);\n const anyX = xp;\n if (gtlt === \"=\" && anyX) {\n gtlt = \"\";\n }\n pr = options.includePrerelease ? \"-0\" : \"\";\n if (xM) {\n if (gtlt === \">\" || gtlt === \"<\") {\n ret = \"<0.0.0-0\";\n } else {\n ret = \"*\";\n }\n } else if (gtlt && anyX) {\n if (xm) {\n m = 0;\n }\n p = 0;\n if (gtlt === \">\") {\n gtlt = \">=\";\n if (xm) {\n M = +M + 1;\n m = 0;\n p = 0;\n } else {\n m = +m + 1;\n p = 0;\n }\n } else if (gtlt === \"<=\") {\n gtlt = \"<\";\n if (xm) {\n M = +M + 1;\n } else {\n m = +m + 1;\n }\n }\n if (gtlt === \"<\") {\n pr = \"-0\";\n }\n ret = `${gtlt + M}.${m}.${p}${pr}`;\n } else if (xm) {\n ret = `>=${M}.0.0${pr} <${+M + 1}.0.0-0`;\n } else if (xp) {\n ret = `>=${M}.${m}.0${pr} <${M}.${+m + 1}.0-0`;\n }\n debug(\"xRange return\", ret);\n return ret;\n });\n };\n var replaceStars = (comp, options) => {\n debug(\"replaceStars\", comp, options);\n return comp.trim().replace(re[t.STAR], \"\");\n };\n var replaceGTE0 = (comp, options) => {\n debug(\"replaceGTE0\", comp, options);\n return comp.trim().replace(re[options.includePrerelease ? t.GTE0PRE : t.GTE0], \"\");\n };\n var hyphenReplace = (incPr) => ($0, from, fM, fm, fp, fpr, fb, to, tM, tm, tp, tpr) => {\n if (isX(fM)) {\n from = \"\";\n } else if (isX(fm)) {\n from = `>=${fM}.0.0${incPr ? \"-0\" : \"\"}`;\n } else if (isX(fp)) {\n from = `>=${fM}.${fm}.0${incPr ? \"-0\" : \"\"}`;\n } else if (fpr) {\n from = `>=${from}`;\n } else {\n from = `>=${from}${incPr ? \"-0\" : \"\"}`;\n }\n if (isX(tM)) {\n to = \"\";\n } else if (isX(tm)) {\n to = `<${+tM + 1}.0.0-0`;\n } else if (isX(tp)) {\n to = `<${tM}.${+tm + 1}.0-0`;\n } else if (tpr) {\n to = `<=${tM}.${tm}.${tp}-${tpr}`;\n } else if (incPr) {\n to = `<${tM}.${tm}.${+tp + 1}-0`;\n } else {\n to = `<=${to}`;\n }\n return `${from} ${to}`.trim();\n };\n var testSet = (set2, version, options) => {\n for (let i = 0; i < set2.length; i++) {\n if (!set2[i].test(version)) {\n return false;\n }\n }\n if (version.prerelease.length && !options.includePrerelease) {\n for (let i = 0; i < set2.length; i++) {\n debug(set2[i].semver);\n if (set2[i].semver === Comparator.ANY) {\n continue;\n }\n if (set2[i].semver.prerelease.length > 0) {\n const allowed = set2[i].semver;\n if (allowed.major === version.major && allowed.minor === version.minor && allowed.patch === version.patch) {\n return true;\n }\n }\n }\n return false;\n }\n return true;\n };\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/classes/comparator.js\nvar require_comparator = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/classes/comparator.js\"(exports, module) {\n \"use strict\";\n var ANY = /* @__PURE__ */ Symbol(\"SemVer ANY\");\n var Comparator = class _Comparator {\n static get ANY() {\n return ANY;\n }\n constructor(comp, options) {\n options = parseOptions(options);\n if (comp instanceof _Comparator) {\n if (comp.loose === !!options.loose) {\n return comp;\n } else {\n comp = comp.value;\n }\n }\n comp = comp.trim().split(/\\s+/).join(\" \");\n debug(\"comparator\", comp, options);\n this.options = options;\n this.loose = !!options.loose;\n this.parse(comp);\n if (this.semver === ANY) {\n this.value = \"\";\n } else {\n this.value = this.operator + this.semver.version;\n }\n debug(\"comp\", this);\n }\n parse(comp) {\n const r = this.options.loose ? re[t.COMPARATORLOOSE] : re[t.COMPARATOR];\n const m = comp.match(r);\n if (!m) {\n throw new TypeError(`Invalid comparator: ${comp}`);\n }\n this.operator = m[1] !== void 0 ? m[1] : \"\";\n if (this.operator === \"=\") {\n this.operator = \"\";\n }\n if (!m[2]) {\n this.semver = ANY;\n } else {\n this.semver = new SemVer(m[2], this.options.loose);\n }\n }\n toString() {\n return this.value;\n }\n test(version) {\n debug(\"Comparator.test\", version, this.options.loose);\n if (this.semver === ANY || version === ANY) {\n return true;\n }\n if (typeof version === \"string\") {\n try {\n version = new SemVer(version, this.options);\n } catch (er) {\n return false;\n }\n }\n return cmp(version, this.operator, this.semver, this.options);\n }\n intersects(comp, options) {\n if (!(comp instanceof _Comparator)) {\n throw new TypeError(\"a Comparator is required\");\n }\n if (this.operator === \"\") {\n if (this.value === \"\") {\n return true;\n }\n return new Range(comp.value, options).test(this.value);\n } else if (comp.operator === \"\") {\n if (comp.value === \"\") {\n return true;\n }\n return new Range(this.value, options).test(comp.semver);\n }\n options = parseOptions(options);\n if (options.includePrerelease && (this.value === \"<0.0.0-0\" || comp.value === \"<0.0.0-0\")) {\n return false;\n }\n if (!options.includePrerelease && (this.value.startsWith(\"<0.0.0\") || comp.value.startsWith(\"<0.0.0\"))) {\n return false;\n }\n if (this.operator.startsWith(\">\") && comp.operator.startsWith(\">\")) {\n return true;\n }\n if (this.operator.startsWith(\"<\") && comp.operator.startsWith(\"<\")) {\n return true;\n }\n if (this.semver.version === comp.semver.version && this.operator.includes(\"=\") && comp.operator.includes(\"=\")) {\n return true;\n }\n if (cmp(this.semver, \"<\", comp.semver, options) && this.operator.startsWith(\">\") && comp.operator.startsWith(\"<\")) {\n return true;\n }\n if (cmp(this.semver, \">\", comp.semver, options) && this.operator.startsWith(\"<\") && comp.operator.startsWith(\">\")) {\n return true;\n }\n return false;\n }\n };\n module.exports = Comparator;\n var parseOptions = require_parse_options();\n var { safeRe: re, t } = require_re();\n var cmp = require_cmp();\n var debug = require_debug();\n var SemVer = require_semver();\n var Range = require_range();\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/satisfies.js\nvar require_satisfies = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/satisfies.js\"(exports, module) {\n \"use strict\";\n var Range = require_range();\n var satisfies = (version, range, options) => {\n try {\n range = new Range(range, options);\n } catch (er) {\n return false;\n }\n return range.test(version);\n };\n module.exports = satisfies;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/to-comparators.js\nvar require_to_comparators = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/to-comparators.js\"(exports, module) {\n \"use strict\";\n var Range = require_range();\n var toComparators = (range, options) => new Range(range, options).set.map((comp) => comp.map((c) => c.value).join(\" \").trim().split(\" \"));\n module.exports = toComparators;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/max-satisfying.js\nvar require_max_satisfying = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/max-satisfying.js\"(exports, module) {\n \"use strict\";\n var SemVer = require_semver();\n var Range = require_range();\n var maxSatisfying = (versions, range, options) => {\n let max2 = null;\n let maxSV = null;\n let rangeObj = null;\n try {\n rangeObj = new Range(range, options);\n } catch (er) {\n return null;\n }\n versions.forEach((v) => {\n if (rangeObj.test(v)) {\n if (!max2 || maxSV.compare(v) === -1) {\n max2 = v;\n maxSV = new SemVer(max2, options);\n }\n }\n });\n return max2;\n };\n module.exports = maxSatisfying;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/min-satisfying.js\nvar require_min_satisfying = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/min-satisfying.js\"(exports, module) {\n \"use strict\";\n var SemVer = require_semver();\n var Range = require_range();\n var minSatisfying = (versions, range, options) => {\n let min = null;\n let minSV = null;\n let rangeObj = null;\n try {\n rangeObj = new Range(range, options);\n } catch (er) {\n return null;\n }\n versions.forEach((v) => {\n if (rangeObj.test(v)) {\n if (!min || minSV.compare(v) === 1) {\n min = v;\n minSV = new SemVer(min, options);\n }\n }\n });\n return min;\n };\n module.exports = minSatisfying;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/min-version.js\nvar require_min_version = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/min-version.js\"(exports, module) {\n \"use strict\";\n var SemVer = require_semver();\n var Range = require_range();\n var gt = require_gt();\n var minVersion = (range, loose) => {\n range = new Range(range, loose);\n let minver = new SemVer(\"0.0.0\");\n if (range.test(minver)) {\n return minver;\n }\n minver = new SemVer(\"0.0.0-0\");\n if (range.test(minver)) {\n return minver;\n }\n minver = null;\n for (let i = 0; i < range.set.length; ++i) {\n const comparators = range.set[i];\n let setMin = null;\n comparators.forEach((comparator) => {\n const compver = new SemVer(comparator.semver.version);\n switch (comparator.operator) {\n case \">\":\n if (compver.prerelease.length === 0) {\n compver.patch++;\n } else {\n compver.prerelease.push(0);\n }\n compver.raw = compver.format();\n /* fallthrough */\n case \"\":\n case \">=\":\n if (!setMin || gt(compver, setMin)) {\n setMin = compver;\n }\n break;\n case \"<\":\n case \"<=\":\n break;\n /* istanbul ignore next */\n default:\n throw new Error(`Unexpected operation: ${comparator.operator}`);\n }\n });\n if (setMin && (!minver || gt(minver, setMin))) {\n minver = setMin;\n }\n }\n if (minver && range.test(minver)) {\n return minver;\n }\n return null;\n };\n module.exports = minVersion;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/valid.js\nvar require_valid2 = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/valid.js\"(exports, module) {\n \"use strict\";\n var Range = require_range();\n var validRange = (range, options) => {\n try {\n return new Range(range, options).range || \"*\";\n } catch (er) {\n return null;\n }\n };\n module.exports = validRange;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/outside.js\nvar require_outside = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/outside.js\"(exports, module) {\n \"use strict\";\n var SemVer = require_semver();\n var Comparator = require_comparator();\n var { ANY } = Comparator;\n var Range = require_range();\n var satisfies = require_satisfies();\n var gt = require_gt();\n var lt = require_lt();\n var lte = require_lte();\n var gte = require_gte();\n var outside = (version, range, hilo, options) => {\n version = new SemVer(version, options);\n range = new Range(range, options);\n let gtfn, ltefn, ltfn, comp, ecomp;\n switch (hilo) {\n case \">\":\n gtfn = gt;\n ltefn = lte;\n ltfn = lt;\n comp = \">\";\n ecomp = \">=\";\n break;\n case \"<\":\n gtfn = lt;\n ltefn = gte;\n ltfn = gt;\n comp = \"<\";\n ecomp = \"<=\";\n break;\n default:\n throw new TypeError('Must provide a hilo val of \"<\" or \">\"');\n }\n if (satisfies(version, range, options)) {\n return false;\n }\n for (let i = 0; i < range.set.length; ++i) {\n const comparators = range.set[i];\n let high = null;\n let low = null;\n comparators.forEach((comparator) => {\n if (comparator.semver === ANY) {\n comparator = new Comparator(\">=0.0.0\");\n }\n high = high || comparator;\n low = low || comparator;\n if (gtfn(comparator.semver, high.semver, options)) {\n high = comparator;\n } else if (ltfn(comparator.semver, low.semver, options)) {\n low = comparator;\n }\n });\n if (high.operator === comp || high.operator === ecomp) {\n return false;\n }\n if ((!low.operator || low.operator === comp) && ltefn(version, low.semver)) {\n return false;\n } else if (low.operator === ecomp && ltfn(version, low.semver)) {\n return false;\n }\n }\n return true;\n };\n module.exports = outside;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/gtr.js\nvar require_gtr = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/gtr.js\"(exports, module) {\n \"use strict\";\n var outside = require_outside();\n var gtr = (version, range, options) => outside(version, range, \">\", options);\n module.exports = gtr;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/ltr.js\nvar require_ltr = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/ltr.js\"(exports, module) {\n \"use strict\";\n var outside = require_outside();\n var ltr = (version, range, options) => outside(version, range, \"<\", options);\n module.exports = ltr;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/intersects.js\nvar require_intersects = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/intersects.js\"(exports, module) {\n \"use strict\";\n var Range = require_range();\n var intersects = (r1, r2, options) => {\n r1 = new Range(r1, options);\n r2 = new Range(r2, options);\n return r1.intersects(r2, options);\n };\n module.exports = intersects;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/simplify.js\nvar require_simplify = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/simplify.js\"(exports, module) {\n \"use strict\";\n var satisfies = require_satisfies();\n var compare = require_compare();\n module.exports = (versions, range, options) => {\n const set2 = [];\n let first = null;\n let prev = null;\n const v = versions.sort((a, b) => compare(a, b, options));\n for (const version of v) {\n const included = satisfies(version, range, options);\n if (included) {\n prev = version;\n if (!first) {\n first = version;\n }\n } else {\n if (prev) {\n set2.push([first, prev]);\n }\n prev = null;\n first = null;\n }\n }\n if (first) {\n set2.push([first, null]);\n }\n const ranges = [];\n for (const [min, max2] of set2) {\n if (min === max2) {\n ranges.push(min);\n } else if (!max2 && min === v[0]) {\n ranges.push(\"*\");\n } else if (!max2) {\n ranges.push(`>=${min}`);\n } else if (min === v[0]) {\n ranges.push(`<=${max2}`);\n } else {\n ranges.push(`${min} - ${max2}`);\n }\n }\n const simplified = ranges.join(\" || \");\n const original = typeof range.raw === \"string\" ? range.raw : String(range);\n return simplified.length < original.length ? simplified : range;\n };\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/subset.js\nvar require_subset = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/subset.js\"(exports, module) {\n \"use strict\";\n var Range = require_range();\n var Comparator = require_comparator();\n var { ANY } = Comparator;\n var satisfies = require_satisfies();\n var compare = require_compare();\n var subset = (sub, dom, options = {}) => {\n if (sub === dom) {\n return true;\n }\n sub = new Range(sub, options);\n dom = new Range(dom, options);\n let sawNonNull = false;\n OUTER: for (const simpleSub of sub.set) {\n for (const simpleDom of dom.set) {\n const isSub = simpleSubset(simpleSub, simpleDom, options);\n sawNonNull = sawNonNull || isSub !== null;\n if (isSub) {\n continue OUTER;\n }\n }\n if (sawNonNull) {\n return false;\n }\n }\n return true;\n };\n var minimumVersionWithPreRelease = [new Comparator(\">=0.0.0-0\")];\n var minimumVersion = [new Comparator(\">=0.0.0\")];\n var simpleSubset = (sub, dom, options) => {\n if (sub === dom) {\n return true;\n }\n if (sub.length === 1 && sub[0].semver === ANY) {\n if (dom.length === 1 && dom[0].semver === ANY) {\n return true;\n } else if (options.includePrerelease) {\n sub = minimumVersionWithPreRelease;\n } else {\n sub = minimumVersion;\n }\n }\n if (dom.length === 1 && dom[0].semver === ANY) {\n if (options.includePrerelease) {\n return true;\n } else {\n dom = minimumVersion;\n }\n }\n const eqSet = /* @__PURE__ */ new Set();\n let gt, lt;\n for (const c of sub) {\n if (c.operator === \">\" || c.operator === \">=\") {\n gt = higherGT(gt, c, options);\n } else if (c.operator === \"<\" || c.operator === \"<=\") {\n lt = lowerLT(lt, c, options);\n } else {\n eqSet.add(c.semver);\n }\n }\n if (eqSet.size > 1) {\n return null;\n }\n let gtltComp;\n if (gt && lt) {\n gtltComp = compare(gt.semver, lt.semver, options);\n if (gtltComp > 0) {\n return null;\n } else if (gtltComp === 0 && (gt.operator !== \">=\" || lt.operator !== \"<=\")) {\n return null;\n }\n }\n for (const eq of eqSet) {\n if (gt && !satisfies(eq, String(gt), options)) {\n return null;\n }\n if (lt && !satisfies(eq, String(lt), options)) {\n return null;\n }\n for (const c of dom) {\n if (!satisfies(eq, String(c), options)) {\n return false;\n }\n }\n return true;\n }\n let higher, lower;\n let hasDomLT, hasDomGT;\n let needDomLTPre = lt && !options.includePrerelease && lt.semver.prerelease.length ? lt.semver : false;\n let needDomGTPre = gt && !options.includePrerelease && gt.semver.prerelease.length ? gt.semver : false;\n if (needDomLTPre && needDomLTPre.prerelease.length === 1 && lt.operator === \"<\" && needDomLTPre.prerelease[0] === 0) {\n needDomLTPre = false;\n }\n for (const c of dom) {\n hasDomGT = hasDomGT || c.operator === \">\" || c.operator === \">=\";\n hasDomLT = hasDomLT || c.operator === \"<\" || c.operator === \"<=\";\n if (gt) {\n if (needDomGTPre) {\n if (c.semver.prerelease && c.semver.prerelease.length && c.semver.major === needDomGTPre.major && c.semver.minor === needDomGTPre.minor && c.semver.patch === needDomGTPre.patch) {\n needDomGTPre = false;\n }\n }\n if (c.operator === \">\" || c.operator === \">=\") {\n higher = higherGT(gt, c, options);\n if (higher === c && higher !== gt) {\n return false;\n }\n } else if (gt.operator === \">=\" && !satisfies(gt.semver, String(c), options)) {\n return false;\n }\n }\n if (lt) {\n if (needDomLTPre) {\n if (c.semver.prerelease && c.semver.prerelease.length && c.semver.major === needDomLTPre.major && c.semver.minor === needDomLTPre.minor && c.semver.patch === needDomLTPre.patch) {\n needDomLTPre = false;\n }\n }\n if (c.operator === \"<\" || c.operator === \"<=\") {\n lower = lowerLT(lt, c, options);\n if (lower === c && lower !== lt) {\n return false;\n }\n } else if (lt.operator === \"<=\" && !satisfies(lt.semver, String(c), options)) {\n return false;\n }\n }\n if (!c.operator && (lt || gt) && gtltComp !== 0) {\n return false;\n }\n }\n if (gt && hasDomLT && !lt && gtltComp !== 0) {\n return false;\n }\n if (lt && hasDomGT && !gt && gtltComp !== 0) {\n return false;\n }\n if (needDomGTPre || needDomLTPre) {\n return false;\n }\n return true;\n };\n var higherGT = (a, b, options) => {\n if (!a) {\n return b;\n }\n const comp = compare(a.semver, b.semver, options);\n return comp > 0 ? a : comp < 0 ? b : b.operator === \">\" && a.operator === \">=\" ? b : a;\n };\n var lowerLT = (a, b, options) => {\n if (!a) {\n return b;\n }\n const comp = compare(a.semver, b.semver, options);\n return comp < 0 ? a : comp > 0 ? b : b.operator === \"<\" && a.operator === \"<=\" ? b : a;\n };\n module.exports = subset;\n }\n});\n\n// node_modules/.pnpm/semver@7.7.3/node_modules/semver/index.js\nvar require_semver2 = __commonJS({\n \"node_modules/.pnpm/semver@7.7.3/node_modules/semver/index.js\"(exports, module) {\n \"use strict\";\n var internalRe = require_re();\n var constants = require_constants();\n var SemVer = require_semver();\n var identifiers = require_identifiers();\n var parse = require_parse();\n var valid = require_valid();\n var clean2 = require_clean();\n var inc = require_inc();\n var diff = require_diff();\n var major = require_major();\n var minor = require_minor();\n var patch = require_patch();\n var prerelease = require_prerelease();\n var compare = require_compare();\n var rcompare = require_rcompare();\n var compareLoose = require_compare_loose();\n var compareBuild = require_compare_build();\n var sort = require_sort();\n var rsort = require_rsort();\n var gt = require_gt();\n var lt = require_lt();\n var eq = require_eq();\n var neq = require_neq();\n var gte = require_gte();\n var lte = require_lte();\n var cmp = require_cmp();\n var coerce = require_coerce();\n var Comparator = require_comparator();\n var Range = require_range();\n var satisfies = require_satisfies();\n var toComparators = require_to_comparators();\n var maxSatisfying = require_max_satisfying();\n var minSatisfying = require_min_satisfying();\n var minVersion = require_min_version();\n var validRange = require_valid2();\n var outside = require_outside();\n var gtr = require_gtr();\n var ltr = require_ltr();\n var intersects = require_intersects();\n var simplifyRange = require_simplify();\n var subset = require_subset();\n module.exports = {\n parse,\n valid,\n clean: clean2,\n inc,\n diff,\n major,\n minor,\n patch,\n prerelease,\n compare,\n rcompare,\n compareLoose,\n compareBuild,\n sort,\n rsort,\n gt,\n lt,\n eq,\n neq,\n gte,\n lte,\n cmp,\n coerce,\n Comparator,\n Range,\n satisfies,\n toComparators,\n maxSatisfying,\n minSatisfying,\n minVersion,\n validRange,\n outside,\n gtr,\n ltr,\n intersects,\n simplifyRange,\n subset,\n SemVer,\n re: internalRe.re,\n src: internalRe.src,\n tokens: internalRe.t,\n SEMVER_SPEC_VERSION: constants.SEMVER_SPEC_VERSION,\n RELEASE_TYPES: constants.RELEASE_TYPES,\n compareIdentifiers: identifiers.compareIdentifiers,\n rcompareIdentifiers: identifiers.rcompareIdentifiers\n };\n }\n});\n\n// node_modules/.pnpm/crc-32@1.2.2/node_modules/crc-32/crc32.js\nvar require_crc32 = __commonJS({\n \"node_modules/.pnpm/crc-32@1.2.2/node_modules/crc-32/crc32.js\"(exports) {\n var CRC322;\n (function(factory) {\n if (typeof DO_NOT_EXPORT_CRC === \"undefined\") {\n if (\"object\" === typeof exports) {\n factory(exports);\n } else if (\"function\" === typeof define && define.amd) {\n define(function() {\n var module2 = {};\n factory(module2);\n return module2;\n });\n } else {\n factory(CRC322 = {});\n }\n } else {\n factory(CRC322 = {});\n }\n })(function(CRC323) {\n CRC323.version = \"1.2.2\";\n function signed_crc_table() {\n var c = 0, table2 = new Array(256);\n for (var n = 0; n != 256; ++n) {\n c = n;\n c = c & 1 ? -306674912 ^ c >>> 1 : c >>> 1;\n c = c & 1 ? -306674912 ^ c >>> 1 : c >>> 1;\n c = c & 1 ? -306674912 ^ c >>> 1 : c >>> 1;\n c = c & 1 ? -306674912 ^ c >>> 1 : c >>> 1;\n c = c & 1 ? -306674912 ^ c >>> 1 : c >>> 1;\n c = c & 1 ? -306674912 ^ c >>> 1 : c >>> 1;\n c = c & 1 ? -306674912 ^ c >>> 1 : c >>> 1;\n c = c & 1 ? -306674912 ^ c >>> 1 : c >>> 1;\n table2[n] = c;\n }\n return typeof Int32Array !== \"undefined\" ? new Int32Array(table2) : table2;\n }\n var T0 = signed_crc_table();\n function slice_by_16_tables(T) {\n var c = 0, v = 0, n = 0, table2 = typeof Int32Array !== \"undefined\" ? new Int32Array(4096) : new Array(4096);\n for (n = 0; n != 256; ++n) table2[n] = T[n];\n for (n = 0; n != 256; ++n) {\n v = T[n];\n for (c = 256 + n; c < 4096; c += 256) v = table2[c] = v >>> 8 ^ T[v & 255];\n }\n var out = [];\n for (n = 1; n != 16; ++n) out[n - 1] = typeof Int32Array !== \"undefined\" ? table2.subarray(n * 256, n * 256 + 256) : table2.slice(n * 256, n * 256 + 256);\n return out;\n }\n var TT = slice_by_16_tables(T0);\n var T1 = TT[0], T2 = TT[1], T3 = TT[2], T4 = TT[3], T5 = TT[4];\n var T6 = TT[5], T7 = TT[6], T8 = TT[7], T9 = TT[8], Ta = TT[9];\n var Tb = TT[10], Tc = TT[11], Td = TT[12], Te = TT[13], Tf = TT[14];\n function crc32_bstr(bstr, seed) {\n var C = seed ^ -1;\n for (var i = 0, L = bstr.length; i < L; ) C = C >>> 8 ^ T0[(C ^ bstr.charCodeAt(i++)) & 255];\n return ~C;\n }\n function crc32_buf(B, seed) {\n var C = seed ^ -1, L = B.length - 15, i = 0;\n for (; i < L; ) C = Tf[B[i++] ^ C & 255] ^ Te[B[i++] ^ C >> 8 & 255] ^ Td[B[i++] ^ C >> 16 & 255] ^ Tc[B[i++] ^ C >>> 24] ^ Tb[B[i++]] ^ Ta[B[i++]] ^ T9[B[i++]] ^ T8[B[i++]] ^ T7[B[i++]] ^ T6[B[i++]] ^ T5[B[i++]] ^ T4[B[i++]] ^ T3[B[i++]] ^ T2[B[i++]] ^ T1[B[i++]] ^ T0[B[i++]];\n L += 15;\n while (i < L) C = C >>> 8 ^ T0[(C ^ B[i++]) & 255];\n return ~C;\n }\n function crc32_str(str, seed) {\n var C = seed ^ -1;\n for (var i = 0, L = str.length, c = 0, d = 0; i < L; ) {\n c = str.charCodeAt(i++);\n if (c < 128) {\n C = C >>> 8 ^ T0[(C ^ c) & 255];\n } else if (c < 2048) {\n C = C >>> 8 ^ T0[(C ^ (192 | c >> 6 & 31)) & 255];\n C = C >>> 8 ^ T0[(C ^ (128 | c & 63)) & 255];\n } else if (c >= 55296 && c < 57344) {\n c = (c & 1023) + 64;\n d = str.charCodeAt(i++) & 1023;\n C = C >>> 8 ^ T0[(C ^ (240 | c >> 8 & 7)) & 255];\n C = C >>> 8 ^ T0[(C ^ (128 | c >> 2 & 63)) & 255];\n C = C >>> 8 ^ T0[(C ^ (128 | d >> 6 & 15 | (c & 3) << 4)) & 255];\n C = C >>> 8 ^ T0[(C ^ (128 | d & 63)) & 255];\n } else {\n C = C >>> 8 ^ T0[(C ^ (224 | c >> 12 & 15)) & 255];\n C = C >>> 8 ^ T0[(C ^ (128 | c >> 6 & 63)) & 255];\n C = C >>> 8 ^ T0[(C ^ (128 | c & 63)) & 255];\n }\n }\n return ~C;\n }\n CRC323.table = T0;\n CRC323.bstr = crc32_bstr;\n CRC323.buf = crc32_buf;\n CRC323.str = crc32_str;\n });\n }\n});\n\n// apps/ecosystem-certifier/fixtures/flagship/knowledge-pack-entry.ts\nvar import_base64_js = __toESM(require_base64_js(), 1);\n\n// node_modules/.pnpm/fflate@0.8.2/node_modules/fflate/esm/browser.js\nvar u8 = Uint8Array;\nvar u16 = Uint16Array;\nvar i32 = Int32Array;\nvar fleb = new u8([\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 1,\n 1,\n 1,\n 1,\n 2,\n 2,\n 2,\n 2,\n 3,\n 3,\n 3,\n 3,\n 4,\n 4,\n 4,\n 4,\n 5,\n 5,\n 5,\n 5,\n 0,\n /* unused */\n 0,\n 0,\n /* impossible */\n 0\n]);\nvar fdeb = new u8([\n 0,\n 0,\n 0,\n 0,\n 1,\n 1,\n 2,\n 2,\n 3,\n 3,\n 4,\n 4,\n 5,\n 5,\n 6,\n 6,\n 7,\n 7,\n 8,\n 8,\n 9,\n 9,\n 10,\n 10,\n 11,\n 11,\n 12,\n 12,\n 13,\n 13,\n /* unused */\n 0,\n 0\n]);\nvar clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]);\nvar freb = function(eb, start) {\n var b = new u16(31);\n for (var i = 0; i < 31; ++i) {\n b[i] = start += 1 << eb[i - 1];\n }\n var r = new i32(b[30]);\n for (var i = 1; i < 30; ++i) {\n for (var j = b[i]; j < b[i + 1]; ++j) {\n r[j] = j - b[i] << 5 | i;\n }\n }\n return { b, r };\n};\nvar _a = freb(fleb, 2);\nvar fl = _a.b;\nvar revfl = _a.r;\nfl[28] = 258, revfl[258] = 28;\nvar _b = freb(fdeb, 0);\nvar fd = _b.b;\nvar revfd = _b.r;\nvar rev = new u16(32768);\nfor (i = 0; i < 32768; ++i) {\n x = (i & 43690) >> 1 | (i & 21845) << 1;\n x = (x & 52428) >> 2 | (x & 13107) << 2;\n x = (x & 61680) >> 4 | (x & 3855) << 4;\n rev[i] = ((x & 65280) >> 8 | (x & 255) << 8) >> 1;\n}\nvar x;\nvar i;\nvar hMap = (function(cd, mb, r) {\n var s = cd.length;\n var i = 0;\n var l = new u16(mb);\n for (; i < s; ++i) {\n if (cd[i])\n ++l[cd[i] - 1];\n }\n var le = new u16(mb);\n for (i = 1; i < mb; ++i) {\n le[i] = le[i - 1] + l[i - 1] << 1;\n }\n var co;\n if (r) {\n co = new u16(1 << mb);\n var rvb = 15 - mb;\n for (i = 0; i < s; ++i) {\n if (cd[i]) {\n var sv = i << 4 | cd[i];\n var r_1 = mb - cd[i];\n var v = le[cd[i] - 1]++ << r_1;\n for (var m = v | (1 << r_1) - 1; v <= m; ++v) {\n co[rev[v] >> rvb] = sv;\n }\n }\n }\n } else {\n co = new u16(s);\n for (i = 0; i < s; ++i) {\n if (cd[i]) {\n co[i] = rev[le[cd[i] - 1]++] >> 15 - cd[i];\n }\n }\n }\n return co;\n});\nvar flt = new u8(288);\nfor (i = 0; i < 144; ++i)\n flt[i] = 8;\nvar i;\nfor (i = 144; i < 256; ++i)\n flt[i] = 9;\nvar i;\nfor (i = 256; i < 280; ++i)\n flt[i] = 7;\nvar i;\nfor (i = 280; i < 288; ++i)\n flt[i] = 8;\nvar i;\nvar fdt = new u8(32);\nfor (i = 0; i < 32; ++i)\n fdt[i] = 5;\nvar i;\nvar flrm = /* @__PURE__ */ hMap(flt, 9, 1);\nvar fdrm = /* @__PURE__ */ hMap(fdt, 5, 1);\nvar max = function(a) {\n var m = a[0];\n for (var i = 1; i < a.length; ++i) {\n if (a[i] > m)\n m = a[i];\n }\n return m;\n};\nvar bits = function(d, p, m) {\n var o = p / 8 | 0;\n return (d[o] | d[o + 1] << 8) >> (p & 7) & m;\n};\nvar bits16 = function(d, p) {\n var o = p / 8 | 0;\n return (d[o] | d[o + 1] << 8 | d[o + 2] << 16) >> (p & 7);\n};\nvar shft = function(p) {\n return (p + 7) / 8 | 0;\n};\nvar slc = function(v, s, e) {\n if (s == null || s < 0)\n s = 0;\n if (e == null || e > v.length)\n e = v.length;\n return new u8(v.subarray(s, e));\n};\nvar ec = [\n \"unexpected EOF\",\n \"invalid block type\",\n \"invalid length/literal\",\n \"invalid distance\",\n \"stream finished\",\n \"no stream handler\",\n ,\n \"no callback\",\n \"invalid UTF-8 data\",\n \"extra field too long\",\n \"date not in range 1980-2099\",\n \"filename too long\",\n \"stream finishing\",\n \"invalid zip data\"\n // determined by unknown compression method\n];\nvar err = function(ind, msg, nt) {\n var e = new Error(msg || ec[ind]);\n e.code = ind;\n if (Error.captureStackTrace)\n Error.captureStackTrace(e, err);\n if (!nt)\n throw e;\n return e;\n};\nvar inflt = function(dat, st, buf, dict) {\n var sl = dat.length, dl = dict ? dict.length : 0;\n if (!sl || st.f && !st.l)\n return buf || new u8(0);\n var noBuf = !buf;\n var resize = noBuf || st.i != 2;\n var noSt = st.i;\n if (noBuf)\n buf = new u8(sl * 3);\n var cbuf = function(l2) {\n var bl = buf.length;\n if (l2 > bl) {\n var nbuf = new u8(Math.max(bl * 2, l2));\n nbuf.set(buf);\n buf = nbuf;\n }\n };\n var final = st.f || 0, pos = st.p || 0, bt = st.b || 0, lm = st.l, dm = st.d, lbt = st.m, dbt = st.n;\n var tbts = sl * 8;\n do {\n if (!lm) {\n final = bits(dat, pos, 1);\n var type = bits(dat, pos + 1, 3);\n pos += 3;\n if (!type) {\n var s = shft(pos) + 4, l = dat[s - 4] | dat[s - 3] << 8, t = s + l;\n if (t > sl) {\n if (noSt)\n err(0);\n break;\n }\n if (resize)\n cbuf(bt + l);\n buf.set(dat.subarray(s, t), bt);\n st.b = bt += l, st.p = pos = t * 8, st.f = final;\n continue;\n } else if (type == 1)\n lm = flrm, dm = fdrm, lbt = 9, dbt = 5;\n else if (type == 2) {\n var hLit = bits(dat, pos, 31) + 257, hcLen = bits(dat, pos + 10, 15) + 4;\n var tl = hLit + bits(dat, pos + 5, 31) + 1;\n pos += 14;\n var ldt = new u8(tl);\n var clt = new u8(19);\n for (var i = 0; i < hcLen; ++i) {\n clt[clim[i]] = bits(dat, pos + i * 3, 7);\n }\n pos += hcLen * 3;\n var clb = max(clt), clbmsk = (1 << clb) - 1;\n var clm = hMap(clt, clb, 1);\n for (var i = 0; i < tl; ) {\n var r = clm[bits(dat, pos, clbmsk)];\n pos += r & 15;\n var s = r >> 4;\n if (s < 16) {\n ldt[i++] = s;\n } else {\n var c = 0, n = 0;\n if (s == 16)\n n = 3 + bits(dat, pos, 3), pos += 2, c = ldt[i - 1];\n else if (s == 17)\n n = 3 + bits(dat, pos, 7), pos += 3;\n else if (s == 18)\n n = 11 + bits(dat, pos, 127), pos += 7;\n while (n--)\n ldt[i++] = c;\n }\n }\n var lt = ldt.subarray(0, hLit), dt = ldt.subarray(hLit);\n lbt = max(lt);\n dbt = max(dt);\n lm = hMap(lt, lbt, 1);\n dm = hMap(dt, dbt, 1);\n } else\n err(1);\n if (pos > tbts) {\n if (noSt)\n err(0);\n break;\n }\n }\n if (resize)\n cbuf(bt + 131072);\n var lms = (1 << lbt) - 1, dms = (1 << dbt) - 1;\n var lpos = pos;\n for (; ; lpos = pos) {\n var c = lm[bits16(dat, pos) & lms], sym = c >> 4;\n pos += c & 15;\n if (pos > tbts) {\n if (noSt)\n err(0);\n break;\n }\n if (!c)\n err(2);\n if (sym < 256)\n buf[bt++] = sym;\n else if (sym == 256) {\n lpos = pos, lm = null;\n break;\n } else {\n var add2 = sym - 254;\n if (sym > 264) {\n var i = sym - 257, b = fleb[i];\n add2 = bits(dat, pos, (1 << b) - 1) + fl[i];\n pos += b;\n }\n var d = dm[bits16(dat, pos) & dms], dsym = d >> 4;\n if (!d)\n err(3);\n pos += d & 15;\n var dt = fd[dsym];\n if (dsym > 3) {\n var b = fdeb[dsym];\n dt += bits16(dat, pos) & (1 << b) - 1, pos += b;\n }\n if (pos > tbts) {\n if (noSt)\n err(0);\n break;\n }\n if (resize)\n cbuf(bt + 131072);\n var end = bt + add2;\n if (bt < dt) {\n var shift = dl - dt, dend = Math.min(dt, end);\n if (shift + bt < 0)\n err(3);\n for (; bt < dend; ++bt)\n buf[bt] = dict[shift + bt];\n }\n for (; bt < end; ++bt)\n buf[bt] = buf[bt - dt];\n }\n }\n st.l = lm, st.p = lpos, st.b = bt, st.f = final;\n if (lm)\n final = 1, st.m = lbt, st.d = dm, st.n = dbt;\n } while (!final);\n return bt != buf.length && noBuf ? slc(buf, 0, bt) : buf.subarray(0, bt);\n};\nvar et = /* @__PURE__ */ new u8(0);\nfunction inflateSync(data, opts) {\n return inflt(data, { i: 2 }, opts && opts.out, opts && opts.dictionary);\n}\nvar td = typeof TextDecoder != \"undefined\" && /* @__PURE__ */ new TextDecoder();\nvar tds = 0;\ntry {\n td.decode(et, { stream: true });\n tds = 1;\n} catch (e) {\n}\n\n// apps/ecosystem-certifier/fixtures/flagship/knowledge-pack-entry.ts\nvar import_fast_deep_equal = __toESM(require_fast_deep_equal(), 1);\nvar import_fast_json_stable_stringify = __toESM(require_fast_json_stable_stringify(), 1);\nvar import_he = __toESM(require_he(), 1);\nvar import_json_logic_js = __toESM(require_logic(), 1);\n\n// node_modules/.pnpm/uc.micro@2.1.0/node_modules/uc.micro/index.mjs\nvar uc_exports = {};\n__export(uc_exports, {\n Any: () => regex_default,\n Cc: () => regex_default2,\n Cf: () => regex_default3,\n P: () => regex_default4,\n S: () => regex_default5,\n Z: () => regex_default6\n});\n\n// node_modules/.pnpm/uc.micro@2.1.0/node_modules/uc.micro/properties/Any/regex.mjs\nvar regex_default = /[\\0-\\uD7FF\\uE000-\\uFFFF]|[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]|[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?:[^\\uD800-\\uDBFF]|^)[\\uDC00-\\uDFFF]/;\n\n// node_modules/.pnpm/uc.micro@2.1.0/node_modules/uc.micro/categories/Cc/regex.mjs\nvar regex_default2 = /[\\0-\\x1F\\x7F-\\x9F]/;\n\n// node_modules/.pnpm/uc.micro@2.1.0/node_modules/uc.micro/categories/Cf/regex.mjs\nvar regex_default3 = /[\\xAD\\u0600-\\u0605\\u061C\\u06DD\\u070F\\u0890\\u0891\\u08E2\\u180E\\u200B-\\u200F\\u202A-\\u202E\\u2060-\\u2064\\u2066-\\u206F\\uFEFF\\uFFF9-\\uFFFB]|\\uD804[\\uDCBD\\uDCCD]|\\uD80D[\\uDC30-\\uDC3F]|\\uD82F[\\uDCA0-\\uDCA3]|\\uD834[\\uDD73-\\uDD7A]|\\uDB40[\\uDC01\\uDC20-\\uDC7F]/;\n\n// node_modules/.pnpm/uc.micro@2.1.0/node_modules/uc.micro/categories/P/regex.mjs\nvar regex_default4 = /[!-#%-\\*,-\\/:;\\?@\\[-\\]_\\{\\}\\xA1\\xA7\\xAB\\xB6\\xB7\\xBB\\xBF\\u037E\\u0387\\u055A-\\u055F\\u0589\\u058A\\u05BE\\u05C0\\u05C3\\u05C6\\u05F3\\u05F4\\u0609\\u060A\\u060C\\u060D\\u061B\\u061D-\\u061F\\u066A-\\u066D\\u06D4\\u0700-\\u070D\\u07F7-\\u07F9\\u0830-\\u083E\\u085E\\u0964\\u0965\\u0970\\u09FD\\u0A76\\u0AF0\\u0C77\\u0C84\\u0DF4\\u0E4F\\u0E5A\\u0E5B\\u0F04-\\u0F12\\u0F14\\u0F3A-\\u0F3D\\u0F85\\u0FD0-\\u0FD4\\u0FD9\\u0FDA\\u104A-\\u104F\\u10FB\\u1360-\\u1368\\u1400\\u166E\\u169B\\u169C\\u16EB-\\u16ED\\u1735\\u1736\\u17D4-\\u17D6\\u17D8-\\u17DA\\u1800-\\u180A\\u1944\\u1945\\u1A1E\\u1A1F\\u1AA0-\\u1AA6\\u1AA8-\\u1AAD\\u1B5A-\\u1B60\\u1B7D\\u1B7E\\u1BFC-\\u1BFF\\u1C3B-\\u1C3F\\u1C7E\\u1C7F\\u1CC0-\\u1CC7\\u1CD3\\u2010-\\u2027\\u2030-\\u2043\\u2045-\\u2051\\u2053-\\u205E\\u207D\\u207E\\u208D\\u208E\\u2308-\\u230B\\u2329\\u232A\\u2768-\\u2775\\u27C5\\u27C6\\u27E6-\\u27EF\\u2983-\\u2998\\u29D8-\\u29DB\\u29FC\\u29FD\\u2CF9-\\u2CFC\\u2CFE\\u2CFF\\u2D70\\u2E00-\\u2E2E\\u2E30-\\u2E4F\\u2E52-\\u2E5D\\u3001-\\u3003\\u3008-\\u3011\\u3014-\\u301F\\u3030\\u303D\\u30A0\\u30FB\\uA4FE\\uA4FF\\uA60D-\\uA60F\\uA673\\uA67E\\uA6F2-\\uA6F7\\uA874-\\uA877\\uA8CE\\uA8CF\\uA8F8-\\uA8FA\\uA8FC\\uA92E\\uA92F\\uA95F\\uA9C1-\\uA9CD\\uA9DE\\uA9DF\\uAA5C-\\uAA5F\\uAADE\\uAADF\\uAAF0\\uAAF1\\uABEB\\uFD3E\\uFD3F\\uFE10-\\uFE19\\uFE30-\\uFE52\\uFE54-\\uFE61\\uFE63\\uFE68\\uFE6A\\uFE6B\\uFF01-\\uFF03\\uFF05-\\uFF0A\\uFF0C-\\uFF0F\\uFF1A\\uFF1B\\uFF1F\\uFF20\\uFF3B-\\uFF3D\\uFF3F\\uFF5B\\uFF5D\\uFF5F-\\uFF65]|\\uD800[\\uDD00-\\uDD02\\uDF9F\\uDFD0]|\\uD801\\uDD6F|\\uD802[\\uDC57\\uDD1F\\uDD3F\\uDE50-\\uDE58\\uDE7F\\uDEF0-\\uDEF6\\uDF39-\\uDF3F\\uDF99-\\uDF9C]|\\uD803[\\uDEAD\\uDF55-\\uDF59\\uDF86-\\uDF89]|\\uD804[\\uDC47-\\uDC4D\\uDCBB\\uDCBC\\uDCBE-\\uDCC1\\uDD40-\\uDD43\\uDD74\\uDD75\\uDDC5-\\uDDC8\\uDDCD\\uDDDB\\uDDDD-\\uDDDF\\uDE38-\\uDE3D\\uDEA9]|\\uD805[\\uDC4B-\\uDC4F\\uDC5A\\uDC5B\\uDC5D\\uDCC6\\uDDC1-\\uDDD7\\uDE41-\\uDE43\\uDE60-\\uDE6C\\uDEB9\\uDF3C-\\uDF3E]|\\uD806[\\uDC3B\\uDD44-\\uDD46\\uDDE2\\uDE3F-\\uDE46\\uDE9A-\\uDE9C\\uDE9E-\\uDEA2\\uDF00-\\uDF09]|\\uD807[\\uDC41-\\uDC45\\uDC70\\uDC71\\uDEF7\\uDEF8\\uDF43-\\uDF4F\\uDFFF]|\\uD809[\\uDC70-\\uDC74]|\\uD80B[\\uDFF1\\uDFF2]|\\uD81A[\\uDE6E\\uDE6F\\uDEF5\\uDF37-\\uDF3B\\uDF44]|\\uD81B[\\uDE97-\\uDE9A\\uDFE2]|\\uD82F\\uDC9F|\\uD836[\\uDE87-\\uDE8B]|\\uD83A[\\uDD5E\\uDD5F]/;\n\n// node_modules/.pnpm/uc.micro@2.1.0/node_modules/uc.micro/categories/S/regex.mjs\nvar regex_default5 = /[\\$\\+<->\\^`\\|~\\xA2-\\xA6\\xA8\\xA9\\xAC\\xAE-\\xB1\\xB4\\xB8\\xD7\\xF7\\u02C2-\\u02C5\\u02D2-\\u02DF\\u02E5-\\u02EB\\u02ED\\u02EF-\\u02FF\\u0375\\u0384\\u0385\\u03F6\\u0482\\u058D-\\u058F\\u0606-\\u0608\\u060B\\u060E\\u060F\\u06DE\\u06E9\\u06FD\\u06FE\\u07F6\\u07FE\\u07FF\\u0888\\u09F2\\u09F3\\u09FA\\u09FB\\u0AF1\\u0B70\\u0BF3-\\u0BFA\\u0C7F\\u0D4F\\u0D79\\u0E3F\\u0F01-\\u0F03\\u0F13\\u0F15-\\u0F17\\u0F1A-\\u0F1F\\u0F34\\u0F36\\u0F38\\u0FBE-\\u0FC5\\u0FC7-\\u0FCC\\u0FCE\\u0FCF\\u0FD5-\\u0FD8\\u109E\\u109F\\u1390-\\u1399\\u166D\\u17DB\\u1940\\u19DE-\\u19FF\\u1B61-\\u1B6A\\u1B74-\\u1B7C\\u1FBD\\u1FBF-\\u1FC1\\u1FCD-\\u1FCF\\u1FDD-\\u1FDF\\u1FED-\\u1FEF\\u1FFD\\u1FFE\\u2044\\u2052\\u207A-\\u207C\\u208A-\\u208C\\u20A0-\\u20C0\\u2100\\u2101\\u2103-\\u2106\\u2108\\u2109\\u2114\\u2116-\\u2118\\u211E-\\u2123\\u2125\\u2127\\u2129\\u212E\\u213A\\u213B\\u2140-\\u2144\\u214A-\\u214D\\u214F\\u218A\\u218B\\u2190-\\u2307\\u230C-\\u2328\\u232B-\\u2426\\u2440-\\u244A\\u249C-\\u24E9\\u2500-\\u2767\\u2794-\\u27C4\\u27C7-\\u27E5\\u27F0-\\u2982\\u2999-\\u29D7\\u29DC-\\u29FB\\u29FE-\\u2B73\\u2B76-\\u2B95\\u2B97-\\u2BFF\\u2CE5-\\u2CEA\\u2E50\\u2E51\\u2E80-\\u2E99\\u2E9B-\\u2EF3\\u2F00-\\u2FD5\\u2FF0-\\u2FFF\\u3004\\u3012\\u3013\\u3020\\u3036\\u3037\\u303E\\u303F\\u309B\\u309C\\u3190\\u3191\\u3196-\\u319F\\u31C0-\\u31E3\\u31EF\\u3200-\\u321E\\u322A-\\u3247\\u3250\\u3260-\\u327F\\u328A-\\u32B0\\u32C0-\\u33FF\\u4DC0-\\u4DFF\\uA490-\\uA4C6\\uA700-\\uA716\\uA720\\uA721\\uA789\\uA78A\\uA828-\\uA82B\\uA836-\\uA839\\uAA77-\\uAA79\\uAB5B\\uAB6A\\uAB6B\\uFB29\\uFBB2-\\uFBC2\\uFD40-\\uFD4F\\uFDCF\\uFDFC-\\uFDFF\\uFE62\\uFE64-\\uFE66\\uFE69\\uFF04\\uFF0B\\uFF1C-\\uFF1E\\uFF3E\\uFF40\\uFF5C\\uFF5E\\uFFE0-\\uFFE6\\uFFE8-\\uFFEE\\uFFFC\\uFFFD]|\\uD800[\\uDD37-\\uDD3F\\uDD79-\\uDD89\\uDD8C-\\uDD8E\\uDD90-\\uDD9C\\uDDA0\\uDDD0-\\uDDFC]|\\uD802[\\uDC77\\uDC78\\uDEC8]|\\uD805\\uDF3F|\\uD807[\\uDFD5-\\uDFF1]|\\uD81A[\\uDF3C-\\uDF3F\\uDF45]|\\uD82F\\uDC9C|\\uD833[\\uDF50-\\uDFC3]|\\uD834[\\uDC00-\\uDCF5\\uDD00-\\uDD26\\uDD29-\\uDD64\\uDD6A-\\uDD6C\\uDD83\\uDD84\\uDD8C-\\uDDA9\\uDDAE-\\uDDEA\\uDE00-\\uDE41\\uDE45\\uDF00-\\uDF56]|\\uD835[\\uDEC1\\uDEDB\\uDEFB\\uDF15\\uDF35\\uDF4F\\uDF6F\\uDF89\\uDFA9\\uDFC3]|\\uD836[\\uDC00-\\uDDFF\\uDE37-\\uDE3A\\uDE6D-\\uDE74\\uDE76-\\uDE83\\uDE85\\uDE86]|\\uD838[\\uDD4F\\uDEFF]|\\uD83B[\\uDCAC\\uDCB0\\uDD2E\\uDEF0\\uDEF1]|\\uD83C[\\uDC00-\\uDC2B\\uDC30-\\uDC93\\uDCA0-\\uDCAE\\uDCB1-\\uDCBF\\uDCC1-\\uDCCF\\uDCD1-\\uDCF5\\uDD0D-\\uDDAD\\uDDE6-\\uDE02\\uDE10-\\uDE3B\\uDE40-\\uDE48\\uDE50\\uDE51\\uDE60-\\uDE65\\uDF00-\\uDFFF]|\\uD83D[\\uDC00-\\uDED7\\uDEDC-\\uDEEC\\uDEF0-\\uDEFC\\uDF00-\\uDF76\\uDF7B-\\uDFD9\\uDFE0-\\uDFEB\\uDFF0]|\\uD83E[\\uDC00-\\uDC0B\\uDC10-\\uDC47\\uDC50-\\uDC59\\uDC60-\\uDC87\\uDC90-\\uDCAD\\uDCB0\\uDCB1\\uDD00-\\uDE53\\uDE60-\\uDE6D\\uDE70-\\uDE7C\\uDE80-\\uDE88\\uDE90-\\uDEBD\\uDEBF-\\uDEC5\\uDECE-\\uDEDB\\uDEE0-\\uDEE8\\uDEF0-\\uDEF8\\uDF00-\\uDF92\\uDF94-\\uDFCA]/;\n\n// node_modules/.pnpm/uc.micro@2.1.0/node_modules/uc.micro/categories/Z/regex.mjs\nvar regex_default6 = /[ \\xA0\\u1680\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]/;\n\n// node_modules/.pnpm/linkify-it@5.0.0/node_modules/linkify-it/lib/re.mjs\nfunction re_default(opts) {\n const re = {};\n opts = opts || {};\n re.src_Any = regex_default.source;\n re.src_Cc = regex_default2.source;\n re.src_Z = regex_default6.source;\n re.src_P = regex_default4.source;\n re.src_ZPCc = [re.src_Z, re.src_P, re.src_Cc].join(\"|\");\n re.src_ZCc = [re.src_Z, re.src_Cc].join(\"|\");\n const text_separators = \"[><|]\";\n re.src_pseudo_letter = \"(?:(?!\" + text_separators + \"|\" + re.src_ZPCc + \")\" + re.src_Any + \")\";\n re.src_ip4 = \"(?:(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\";\n re.src_auth = \"(?:(?:(?!\" + re.src_ZCc + \"|[@/\\\\[\\\\]()]).)+@)?\";\n re.src_port = \"(?::(?:6(?:[0-4]\\\\d{3}|5(?:[0-4]\\\\d{2}|5(?:[0-2]\\\\d|3[0-5])))|[1-5]?\\\\d{1,4}))?\";\n re.src_host_terminator = \"(?=$|\" + text_separators + \"|\" + re.src_ZPCc + \")(?!\" + (opts[\"---\"] ? \"-(?!--)|\" : \"-|\") + \"_|:\\\\d|\\\\.-|\\\\.(?!$|\" + re.src_ZPCc + \"))\";\n re.src_path = \"(?:[/?#](?:(?!\" + re.src_ZCc + \"|\" + text_separators + `|[()[\\\\]{}.,\"'?!\\\\-;]).|\\\\[(?:(?!` + re.src_ZCc + \"|\\\\]).)*\\\\]|\\\\((?:(?!\" + re.src_ZCc + \"|[)]).)*\\\\)|\\\\{(?:(?!\" + re.src_ZCc + '|[}]).)*\\\\}|\\\\\"(?:(?!' + re.src_ZCc + `|[\"]).)+\\\\\"|\\\\'(?:(?!` + re.src_ZCc + \"|[']).)+\\\\'|\\\\'(?=\" + re.src_pseudo_letter + \"|[-])|\\\\.{2,}[a-zA-Z0-9%/&]|\\\\.(?!\" + re.src_ZCc + \"|[.]|$)|\" + (opts[\"---\"] ? \"\\\\-(?!--(?:[^-]|$))(?:-*)|\" : \"\\\\-+|\") + // allow `,,,` in paths\n \",(?!\" + re.src_ZCc + \"|$)|;(?!\" + re.src_ZCc + \"|$)|\\\\!+(?!\" + re.src_ZCc + \"|[!]|$)|\\\\?(?!\" + re.src_ZCc + \"|[?]|$))+|\\\\/)?\";\n re.src_email_name = '[\\\\-;:&=\\\\+\\\\$,\\\\.a-zA-Z0-9_][\\\\-;:&=\\\\+\\\\$,\\\\\"\\\\.a-zA-Z0-9_]*';\n re.src_xn = \"xn--[a-z0-9\\\\-]{1,59}\";\n re.src_domain_root = // Allow letters & digits (http://test1)\n \"(?:\" + re.src_xn + \"|\" + re.src_pseudo_letter + \"{1,63})\";\n re.src_domain = \"(?:\" + re.src_xn + \"|(?:\" + re.src_pseudo_letter + \")|(?:\" + re.src_pseudo_letter + \"(?:-|\" + re.src_pseudo_letter + \"){0,61}\" + re.src_pseudo_letter + \"))\";\n re.src_host = \"(?:(?:(?:(?:\" + re.src_domain + \")\\\\.)*\" + re.src_domain + \"))\";\n re.tpl_host_fuzzy = \"(?:\" + re.src_ip4 + \"|(?:(?:(?:\" + re.src_domain + \")\\\\.)+(?:%TLDS%)))\";\n re.tpl_host_no_ip_fuzzy = \"(?:(?:(?:\" + re.src_domain + \")\\\\.)+(?:%TLDS%))\";\n re.src_host_strict = re.src_host + re.src_host_terminator;\n re.tpl_host_fuzzy_strict = re.tpl_host_fuzzy + re.src_host_terminator;\n re.src_host_port_strict = re.src_host + re.src_port + re.src_host_terminator;\n re.tpl_host_port_fuzzy_strict = re.tpl_host_fuzzy + re.src_port + re.src_host_terminator;\n re.tpl_host_port_no_ip_fuzzy_strict = re.tpl_host_no_ip_fuzzy + re.src_port + re.src_host_terminator;\n re.tpl_host_fuzzy_test = \"localhost|www\\\\.|\\\\.\\\\d{1,3}\\\\.|(?:\\\\.(?:%TLDS%)(?:\" + re.src_ZPCc + \"|>|$))\";\n re.tpl_email_fuzzy = \"(^|\" + text_separators + '|\"|\\\\(|' + re.src_ZCc + \")(\" + re.src_email_name + \"@\" + re.tpl_host_fuzzy_strict + \")\";\n re.tpl_link_fuzzy = // Fuzzy link can't be prepended with .:/\\- and non punctuation.\n // but can start with > (markdown blockquote)\n \"(^|(?![.:/\\\\-_@])(?:[$+<=>^`||]|\" + re.src_ZPCc + \"))((?![$+<=>^`||])\" + re.tpl_host_port_fuzzy_strict + re.src_path + \")\";\n re.tpl_link_no_ip_fuzzy = // Fuzzy link can't be prepended with .:/\\- and non punctuation.\n // but can start with > (markdown blockquote)\n \"(^|(?![.:/\\\\-_@])(?:[$+<=>^`||]|\" + re.src_ZPCc + \"))((?![$+<=>^`||])\" + re.tpl_host_port_no_ip_fuzzy_strict + re.src_path + \")\";\n return re;\n}\n\n// node_modules/.pnpm/linkify-it@5.0.0/node_modules/linkify-it/index.mjs\nfunction assign(obj) {\n const sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n if (!source) {\n return;\n }\n Object.keys(source).forEach(function(key) {\n obj[key] = source[key];\n });\n });\n return obj;\n}\nfunction _class(obj) {\n return Object.prototype.toString.call(obj);\n}\nfunction isString(obj) {\n return _class(obj) === \"[object String]\";\n}\nfunction isObject(obj) {\n return _class(obj) === \"[object Object]\";\n}\nfunction isRegExp(obj) {\n return _class(obj) === \"[object RegExp]\";\n}\nfunction isFunction(obj) {\n return _class(obj) === \"[object Function]\";\n}\nfunction escapeRE(str) {\n return str.replace(/[.?*+^$[\\]\\\\(){}|-]/g, \"\\\\$&\");\n}\nvar defaultOptions = {\n fuzzyLink: true,\n fuzzyEmail: true,\n fuzzyIP: false\n};\nfunction isOptionsObj(obj) {\n return Object.keys(obj || {}).reduce(function(acc, k) {\n return acc || defaultOptions.hasOwnProperty(k);\n }, false);\n}\nvar defaultSchemas = {\n \"http:\": {\n validate: function(text2, pos, self) {\n const tail = text2.slice(pos);\n if (!self.re.http) {\n self.re.http = new RegExp(\n \"^\\\\/\\\\/\" + self.re.src_auth + self.re.src_host_port_strict + self.re.src_path,\n \"i\"\n );\n }\n if (self.re.http.test(tail)) {\n return tail.match(self.re.http)[0].length;\n }\n return 0;\n }\n },\n \"https:\": \"http:\",\n \"ftp:\": \"http:\",\n \"//\": {\n validate: function(text2, pos, self) {\n const tail = text2.slice(pos);\n if (!self.re.no_http) {\n self.re.no_http = new RegExp(\n \"^\" + self.re.src_auth + // Don't allow single-level domains, because of false positives like '//test'\n // with code comments\n \"(?:localhost|(?:(?:\" + self.re.src_domain + \")\\\\.)+\" + self.re.src_domain_root + \")\" + self.re.src_port + self.re.src_host_terminator + self.re.src_path,\n \"i\"\n );\n }\n if (self.re.no_http.test(tail)) {\n if (pos >= 3 && text2[pos - 3] === \":\") {\n return 0;\n }\n if (pos >= 3 && text2[pos - 3] === \"/\") {\n return 0;\n }\n return tail.match(self.re.no_http)[0].length;\n }\n return 0;\n }\n },\n \"mailto:\": {\n validate: function(text2, pos, self) {\n const tail = text2.slice(pos);\n if (!self.re.mailto) {\n self.re.mailto = new RegExp(\n \"^\" + self.re.src_email_name + \"@\" + self.re.src_host_strict,\n \"i\"\n );\n }\n if (self.re.mailto.test(tail)) {\n return tail.match(self.re.mailto)[0].length;\n }\n return 0;\n }\n }\n};\nvar tlds_2ch_src_re = \"a[cdefgilmnoqrstuwxz]|b[abdefghijmnorstvwyz]|c[acdfghiklmnoruvwxyz]|d[ejkmoz]|e[cegrstu]|f[ijkmor]|g[abdefghilmnpqrstuwy]|h[kmnrtu]|i[delmnoqrst]|j[emop]|k[eghimnprwyz]|l[abcikrstuvy]|m[acdeghklmnopqrstuvwxyz]|n[acefgilopruz]|om|p[aefghklmnrstwy]|qa|r[eosuw]|s[abcdeghijklmnortuvxyz]|t[cdfghjklmnortvwz]|u[agksyz]|v[aceginu]|w[fs]|y[et]|z[amw]\";\nvar tlds_default = \"biz|com|edu|gov|net|org|pro|web|xxx|aero|asia|coop|info|museum|name|shop|рф\".split(\"|\");\nfunction resetScanCache(self) {\n self.__index__ = -1;\n self.__text_cache__ = \"\";\n}\nfunction createValidator(re) {\n return function(text2, pos) {\n const tail = text2.slice(pos);\n if (re.test(tail)) {\n return tail.match(re)[0].length;\n }\n return 0;\n };\n}\nfunction createNormalizer() {\n return function(match2, self) {\n self.normalize(match2);\n };\n}\nfunction compile(self) {\n const re = self.re = re_default(self.__opts__);\n const tlds2 = self.__tlds__.slice();\n self.onCompile();\n if (!self.__tlds_replaced__) {\n tlds2.push(tlds_2ch_src_re);\n }\n tlds2.push(re.src_xn);\n re.src_tlds = tlds2.join(\"|\");\n function untpl(tpl) {\n return tpl.replace(\"%TLDS%\", re.src_tlds);\n }\n re.email_fuzzy = RegExp(untpl(re.tpl_email_fuzzy), \"i\");\n re.link_fuzzy = RegExp(untpl(re.tpl_link_fuzzy), \"i\");\n re.link_no_ip_fuzzy = RegExp(untpl(re.tpl_link_no_ip_fuzzy), \"i\");\n re.host_fuzzy_test = RegExp(untpl(re.tpl_host_fuzzy_test), \"i\");\n const aliases = [];\n self.__compiled__ = {};\n function schemaError(name, val) {\n throw new Error('(LinkifyIt) Invalid schema \"' + name + '\": ' + val);\n }\n Object.keys(self.__schemas__).forEach(function(name) {\n const val = self.__schemas__[name];\n if (val === null) {\n return;\n }\n const compiled = { validate: null, link: null };\n self.__compiled__[name] = compiled;\n if (isObject(val)) {\n if (isRegExp(val.validate)) {\n compiled.validate = createValidator(val.validate);\n } else if (isFunction(val.validate)) {\n compiled.validate = val.validate;\n } else {\n schemaError(name, val);\n }\n if (isFunction(val.normalize)) {\n compiled.normalize = val.normalize;\n } else if (!val.normalize) {\n compiled.normalize = createNormalizer();\n } else {\n schemaError(name, val);\n }\n return;\n }\n if (isString(val)) {\n aliases.push(name);\n return;\n }\n schemaError(name, val);\n });\n aliases.forEach(function(alias) {\n if (!self.__compiled__[self.__schemas__[alias]]) {\n return;\n }\n self.__compiled__[alias].validate = self.__compiled__[self.__schemas__[alias]].validate;\n self.__compiled__[alias].normalize = self.__compiled__[self.__schemas__[alias]].normalize;\n });\n self.__compiled__[\"\"] = { validate: null, normalize: createNormalizer() };\n const slist = Object.keys(self.__compiled__).filter(function(name) {\n return name.length > 0 && self.__compiled__[name];\n }).map(escapeRE).join(\"|\");\n self.re.schema_test = RegExp(\"(^|(?!_)(?:[><|]|\" + re.src_ZPCc + \"))(\" + slist + \")\", \"i\");\n self.re.schema_search = RegExp(\"(^|(?!_)(?:[><|]|\" + re.src_ZPCc + \"))(\" + slist + \")\", \"ig\");\n self.re.schema_at_start = RegExp(\"^\" + self.re.schema_search.source, \"i\");\n self.re.pretest = RegExp(\n \"(\" + self.re.schema_test.source + \")|(\" + self.re.host_fuzzy_test.source + \")|@\",\n \"i\"\n );\n resetScanCache(self);\n}\nfunction Match(self, shift) {\n const start = self.__index__;\n const end = self.__last_index__;\n const text2 = self.__text_cache__.slice(start, end);\n this.schema = self.__schema__.toLowerCase();\n this.index = start + shift;\n this.lastIndex = end + shift;\n this.raw = text2;\n this.text = text2;\n this.url = text2;\n}\nfunction createMatch(self, shift) {\n const match2 = new Match(self, shift);\n self.__compiled__[match2.schema].normalize(match2, self);\n return match2;\n}\nfunction LinkifyIt(schemas, options) {\n if (!(this instanceof LinkifyIt)) {\n return new LinkifyIt(schemas, options);\n }\n if (!options) {\n if (isOptionsObj(schemas)) {\n options = schemas;\n schemas = {};\n }\n }\n this.__opts__ = assign({}, defaultOptions, options);\n this.__index__ = -1;\n this.__last_index__ = -1;\n this.__schema__ = \"\";\n this.__text_cache__ = \"\";\n this.__schemas__ = assign({}, defaultSchemas, schemas);\n this.__compiled__ = {};\n this.__tlds__ = tlds_default;\n this.__tlds_replaced__ = false;\n this.re = {};\n compile(this);\n}\nLinkifyIt.prototype.add = function add(schema, definition) {\n this.__schemas__[schema] = definition;\n compile(this);\n return this;\n};\nLinkifyIt.prototype.set = function set(options) {\n this.__opts__ = assign(this.__opts__, options);\n return this;\n};\nLinkifyIt.prototype.test = function test(text2) {\n this.__text_cache__ = text2;\n this.__index__ = -1;\n if (!text2.length) {\n return false;\n }\n let m, ml, me, len, shift, next, re, tld_pos, at_pos;\n if (this.re.schema_test.test(text2)) {\n re = this.re.schema_search;\n re.lastIndex = 0;\n while ((m = re.exec(text2)) !== null) {\n len = this.testSchemaAt(text2, m[2], re.lastIndex);\n if (len) {\n this.__schema__ = m[2];\n this.__index__ = m.index + m[1].length;\n this.__last_index__ = m.index + m[0].length + len;\n break;\n }\n }\n }\n if (this.__opts__.fuzzyLink && this.__compiled__[\"http:\"]) {\n tld_pos = text2.search(this.re.host_fuzzy_test);\n if (tld_pos >= 0) {\n if (this.__index__ < 0 || tld_pos < this.__index__) {\n if ((ml = text2.match(this.__opts__.fuzzyIP ? this.re.link_fuzzy : this.re.link_no_ip_fuzzy)) !== null) {\n shift = ml.index + ml[1].length;\n if (this.__index__ < 0 || shift < this.__index__) {\n this.__schema__ = \"\";\n this.__index__ = shift;\n this.__last_index__ = ml.index + ml[0].length;\n }\n }\n }\n }\n }\n if (this.__opts__.fuzzyEmail && this.__compiled__[\"mailto:\"]) {\n at_pos = text2.indexOf(\"@\");\n if (at_pos >= 0) {\n if ((me = text2.match(this.re.email_fuzzy)) !== null) {\n shift = me.index + me[1].length;\n next = me.index + me[0].length;\n if (this.__index__ < 0 || shift < this.__index__ || shift === this.__index__ && next > this.__last_index__) {\n this.__schema__ = \"mailto:\";\n this.__index__ = shift;\n this.__last_index__ = next;\n }\n }\n }\n }\n return this.__index__ >= 0;\n};\nLinkifyIt.prototype.pretest = function pretest(text2) {\n return this.re.pretest.test(text2);\n};\nLinkifyIt.prototype.testSchemaAt = function testSchemaAt(text2, schema, pos) {\n if (!this.__compiled__[schema.toLowerCase()]) {\n return 0;\n }\n return this.__compiled__[schema.toLowerCase()].validate(text2, pos, this);\n};\nLinkifyIt.prototype.match = function match(text2) {\n const result = [];\n let shift = 0;\n if (this.__index__ >= 0 && this.__text_cache__ === text2) {\n result.push(createMatch(this, shift));\n shift = this.__last_index__;\n }\n let tail = shift ? text2.slice(shift) : text2;\n while (this.test(tail)) {\n result.push(createMatch(this, shift));\n tail = tail.slice(this.__last_index__);\n shift += this.__last_index__;\n }\n if (result.length) {\n return result;\n }\n return null;\n};\nLinkifyIt.prototype.matchAtStart = function matchAtStart(text2) {\n this.__text_cache__ = text2;\n this.__index__ = -1;\n if (!text2.length) return null;\n const m = this.re.schema_at_start.exec(text2);\n if (!m) return null;\n const len = this.testSchemaAt(text2, m[2], m[0].length);\n if (!len) return null;\n this.__schema__ = m[2];\n this.__index__ = m.index + m[1].length;\n this.__last_index__ = m.index + m[0].length + len;\n return createMatch(this, 0);\n};\nLinkifyIt.prototype.tlds = function tlds(list2, keepOld) {\n list2 = Array.isArray(list2) ? list2 : [list2];\n if (!keepOld) {\n this.__tlds__ = list2.slice();\n this.__tlds_replaced__ = true;\n compile(this);\n return this;\n }\n this.__tlds__ = this.__tlds__.concat(list2).sort().filter(function(el, idx, arr) {\n return el !== arr[idx - 1];\n }).reverse();\n compile(this);\n return this;\n};\nLinkifyIt.prototype.normalize = function normalize(match2) {\n if (!match2.schema) {\n match2.url = \"http://\" + match2.url;\n }\n if (match2.schema === \"mailto:\" && !/^mailto:/i.test(match2.url)) {\n match2.url = \"mailto:\" + match2.url;\n }\n};\nLinkifyIt.prototype.onCompile = function onCompile() {\n};\nvar linkify_it_default = LinkifyIt;\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/common/utils.mjs\nvar utils_exports = {};\n__export(utils_exports, {\n arrayReplaceAt: () => arrayReplaceAt,\n assign: () => assign2,\n escapeHtml: () => escapeHtml,\n escapeRE: () => escapeRE2,\n fromCodePoint: () => fromCodePoint2,\n has: () => has,\n isMdAsciiPunct: () => isMdAsciiPunct,\n isPunctChar: () => isPunctChar,\n isSpace: () => isSpace,\n isString: () => isString2,\n isValidEntityCode: () => isValidEntityCode,\n isWhiteSpace: () => isWhiteSpace,\n lib: () => lib,\n normalizeReference: () => normalizeReference,\n unescapeAll: () => unescapeAll,\n unescapeMd: () => unescapeMd\n});\n\n// node_modules/.pnpm/mdurl@2.0.0/node_modules/mdurl/index.mjs\nvar mdurl_exports = {};\n__export(mdurl_exports, {\n decode: () => decode_default,\n encode: () => encode_default,\n format: () => format,\n parse: () => parse_default\n});\n\n// node_modules/.pnpm/mdurl@2.0.0/node_modules/mdurl/lib/decode.mjs\nvar decodeCache = {};\nfunction getDecodeCache(exclude) {\n let cache = decodeCache[exclude];\n if (cache) {\n return cache;\n }\n cache = decodeCache[exclude] = [];\n for (let i = 0; i < 128; i++) {\n const ch = String.fromCharCode(i);\n cache.push(ch);\n }\n for (let i = 0; i < exclude.length; i++) {\n const ch = exclude.charCodeAt(i);\n cache[ch] = \"%\" + (\"0\" + ch.toString(16).toUpperCase()).slice(-2);\n }\n return cache;\n}\nfunction decode(string, exclude) {\n if (typeof exclude !== \"string\") {\n exclude = decode.defaultChars;\n }\n const cache = getDecodeCache(exclude);\n return string.replace(/(%[a-f0-9]{2})+/gi, function(seq) {\n let result = \"\";\n for (let i = 0, l = seq.length; i < l; i += 3) {\n const b1 = parseInt(seq.slice(i + 1, i + 3), 16);\n if (b1 < 128) {\n result += cache[b1];\n continue;\n }\n if ((b1 & 224) === 192 && i + 3 < l) {\n const b2 = parseInt(seq.slice(i + 4, i + 6), 16);\n if ((b2 & 192) === 128) {\n const chr = b1 << 6 & 1984 | b2 & 63;\n if (chr < 128) {\n result += \"��\";\n } else {\n result += String.fromCharCode(chr);\n }\n i += 3;\n continue;\n }\n }\n if ((b1 & 240) === 224 && i + 6 < l) {\n const b2 = parseInt(seq.slice(i + 4, i + 6), 16);\n const b3 = parseInt(seq.slice(i + 7, i + 9), 16);\n if ((b2 & 192) === 128 && (b3 & 192) === 128) {\n const chr = b1 << 12 & 61440 | b2 << 6 & 4032 | b3 & 63;\n if (chr < 2048 || chr >= 55296 && chr <= 57343) {\n result += \"���\";\n } else {\n result += String.fromCharCode(chr);\n }\n i += 6;\n continue;\n }\n }\n if ((b1 & 248) === 240 && i + 9 < l) {\n const b2 = parseInt(seq.slice(i + 4, i + 6), 16);\n const b3 = parseInt(seq.slice(i + 7, i + 9), 16);\n const b4 = parseInt(seq.slice(i + 10, i + 12), 16);\n if ((b2 & 192) === 128 && (b3 & 192) === 128 && (b4 & 192) === 128) {\n let chr = b1 << 18 & 1835008 | b2 << 12 & 258048 | b3 << 6 & 4032 | b4 & 63;\n if (chr < 65536 || chr > 1114111) {\n result += \"����\";\n } else {\n chr -= 65536;\n result += String.fromCharCode(55296 + (chr >> 10), 56320 + (chr & 1023));\n }\n i += 9;\n continue;\n }\n }\n result += \"�\";\n }\n return result;\n });\n}\ndecode.defaultChars = \";/?:@&=+$,#\";\ndecode.componentChars = \"\";\nvar decode_default = decode;\n\n// node_modules/.pnpm/mdurl@2.0.0/node_modules/mdurl/lib/encode.mjs\nvar encodeCache = {};\nfunction getEncodeCache(exclude) {\n let cache = encodeCache[exclude];\n if (cache) {\n return cache;\n }\n cache = encodeCache[exclude] = [];\n for (let i = 0; i < 128; i++) {\n const ch = String.fromCharCode(i);\n if (/^[0-9a-z]$/i.test(ch)) {\n cache.push(ch);\n } else {\n cache.push(\"%\" + (\"0\" + i.toString(16).toUpperCase()).slice(-2));\n }\n }\n for (let i = 0; i < exclude.length; i++) {\n cache[exclude.charCodeAt(i)] = exclude[i];\n }\n return cache;\n}\nfunction encode(string, exclude, keepEscaped) {\n if (typeof exclude !== \"string\") {\n keepEscaped = exclude;\n exclude = encode.defaultChars;\n }\n if (typeof keepEscaped === \"undefined\") {\n keepEscaped = true;\n }\n const cache = getEncodeCache(exclude);\n let result = \"\";\n for (let i = 0, l = string.length; i < l; i++) {\n const code2 = string.charCodeAt(i);\n if (keepEscaped && code2 === 37 && i + 2 < l) {\n if (/^[0-9a-f]{2}$/i.test(string.slice(i + 1, i + 3))) {\n result += string.slice(i, i + 3);\n i += 2;\n continue;\n }\n }\n if (code2 < 128) {\n result += cache[code2];\n continue;\n }\n if (code2 >= 55296 && code2 <= 57343) {\n if (code2 >= 55296 && code2 <= 56319 && i + 1 < l) {\n const nextCode = string.charCodeAt(i + 1);\n if (nextCode >= 56320 && nextCode <= 57343) {\n result += encodeURIComponent(string[i] + string[i + 1]);\n i++;\n continue;\n }\n }\n result += \"%EF%BF%BD\";\n continue;\n }\n result += encodeURIComponent(string[i]);\n }\n return result;\n}\nencode.defaultChars = \";/?:@&=+$,-_.!~*'()#\";\nencode.componentChars = \"-_.!~*'()\";\nvar encode_default = encode;\n\n// node_modules/.pnpm/mdurl@2.0.0/node_modules/mdurl/lib/format.mjs\nfunction format(url) {\n let result = \"\";\n result += url.protocol || \"\";\n result += url.slashes ? \"//\" : \"\";\n result += url.auth ? url.auth + \"@\" : \"\";\n if (url.hostname && url.hostname.indexOf(\":\") !== -1) {\n result += \"[\" + url.hostname + \"]\";\n } else {\n result += url.hostname || \"\";\n }\n result += url.port ? \":\" + url.port : \"\";\n result += url.pathname || \"\";\n result += url.search || \"\";\n result += url.hash || \"\";\n return result;\n}\n\n// node_modules/.pnpm/mdurl@2.0.0/node_modules/mdurl/lib/parse.mjs\nfunction Url() {\n this.protocol = null;\n this.slashes = null;\n this.auth = null;\n this.port = null;\n this.hostname = null;\n this.hash = null;\n this.search = null;\n this.pathname = null;\n}\nvar protocolPattern = /^([a-z0-9.+-]+:)/i;\nvar portPattern = /:[0-9]*$/;\nvar simplePathPattern = /^(\\/\\/?(?!\\/)[^\\?\\s]*)(\\?[^\\s]*)?$/;\nvar delims = [\"<\", \">\", '\"', \"`\", \" \", \"\\r\", \"\\n\", \"\t\"];\nvar unwise = [\"{\", \"}\", \"|\", \"\\\\\", \"^\", \"`\"].concat(delims);\nvar autoEscape = [\"'\"].concat(unwise);\nvar nonHostChars = [\"%\", \"/\", \"?\", \";\", \"#\"].concat(autoEscape);\nvar hostEndingChars = [\"/\", \"?\", \"#\"];\nvar hostnameMaxLen = 255;\nvar hostnamePartPattern = /^[+a-z0-9A-Z_-]{0,63}$/;\nvar hostnamePartStart = /^([+a-z0-9A-Z_-]{0,63})(.*)$/;\nvar hostlessProtocol = {\n javascript: true,\n \"javascript:\": true\n};\nvar slashedProtocol = {\n http: true,\n https: true,\n ftp: true,\n gopher: true,\n file: true,\n \"http:\": true,\n \"https:\": true,\n \"ftp:\": true,\n \"gopher:\": true,\n \"file:\": true\n};\nfunction urlParse(url, slashesDenoteHost) {\n if (url && url instanceof Url) return url;\n const u = new Url();\n u.parse(url, slashesDenoteHost);\n return u;\n}\nUrl.prototype.parse = function(url, slashesDenoteHost) {\n let lowerProto, hec, slashes;\n let rest = url;\n rest = rest.trim();\n if (!slashesDenoteHost && url.split(\"#\").length === 1) {\n const simplePath = simplePathPattern.exec(rest);\n if (simplePath) {\n this.pathname = simplePath[1];\n if (simplePath[2]) {\n this.search = simplePath[2];\n }\n return this;\n }\n }\n let proto = protocolPattern.exec(rest);\n if (proto) {\n proto = proto[0];\n lowerProto = proto.toLowerCase();\n this.protocol = proto;\n rest = rest.substr(proto.length);\n }\n if (slashesDenoteHost || proto || rest.match(/^\\/\\/[^@\\/]+@[^@\\/]+/)) {\n slashes = rest.substr(0, 2) === \"//\";\n if (slashes && !(proto && hostlessProtocol[proto])) {\n rest = rest.substr(2);\n this.slashes = true;\n }\n }\n if (!hostlessProtocol[proto] && (slashes || proto && !slashedProtocol[proto])) {\n let hostEnd = -1;\n for (let i = 0; i < hostEndingChars.length; i++) {\n hec = rest.indexOf(hostEndingChars[i]);\n if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) {\n hostEnd = hec;\n }\n }\n let auth, atSign;\n if (hostEnd === -1) {\n atSign = rest.lastIndexOf(\"@\");\n } else {\n atSign = rest.lastIndexOf(\"@\", hostEnd);\n }\n if (atSign !== -1) {\n auth = rest.slice(0, atSign);\n rest = rest.slice(atSign + 1);\n this.auth = auth;\n }\n hostEnd = -1;\n for (let i = 0; i < nonHostChars.length; i++) {\n hec = rest.indexOf(nonHostChars[i]);\n if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) {\n hostEnd = hec;\n }\n }\n if (hostEnd === -1) {\n hostEnd = rest.length;\n }\n if (rest[hostEnd - 1] === \":\") {\n hostEnd--;\n }\n const host = rest.slice(0, hostEnd);\n rest = rest.slice(hostEnd);\n this.parseHost(host);\n this.hostname = this.hostname || \"\";\n const ipv6Hostname = this.hostname[0] === \"[\" && this.hostname[this.hostname.length - 1] === \"]\";\n if (!ipv6Hostname) {\n const hostparts = this.hostname.split(/\\./);\n for (let i = 0, l = hostparts.length; i < l; i++) {\n const part = hostparts[i];\n if (!part) {\n continue;\n }\n if (!part.match(hostnamePartPattern)) {\n let newpart = \"\";\n for (let j = 0, k = part.length; j < k; j++) {\n if (part.charCodeAt(j) > 127) {\n newpart += \"x\";\n } else {\n newpart += part[j];\n }\n }\n if (!newpart.match(hostnamePartPattern)) {\n const validParts = hostparts.slice(0, i);\n const notHost = hostparts.slice(i + 1);\n const bit = part.match(hostnamePartStart);\n if (bit) {\n validParts.push(bit[1]);\n notHost.unshift(bit[2]);\n }\n if (notHost.length) {\n rest = notHost.join(\".\") + rest;\n }\n this.hostname = validParts.join(\".\");\n break;\n }\n }\n }\n }\n if (this.hostname.length > hostnameMaxLen) {\n this.hostname = \"\";\n }\n if (ipv6Hostname) {\n this.hostname = this.hostname.substr(1, this.hostname.length - 2);\n }\n }\n const hash = rest.indexOf(\"#\");\n if (hash !== -1) {\n this.hash = rest.substr(hash);\n rest = rest.slice(0, hash);\n }\n const qm = rest.indexOf(\"?\");\n if (qm !== -1) {\n this.search = rest.substr(qm);\n rest = rest.slice(0, qm);\n }\n if (rest) {\n this.pathname = rest;\n }\n if (slashedProtocol[lowerProto] && this.hostname && !this.pathname) {\n this.pathname = \"\";\n }\n return this;\n};\nUrl.prototype.parseHost = function(host) {\n let port = portPattern.exec(host);\n if (port) {\n port = port[0];\n if (port !== \":\") {\n this.port = port.substr(1);\n }\n host = host.substr(0, host.length - port.length);\n }\n if (host) {\n this.hostname = host;\n }\n};\nvar parse_default = urlParse;\n\n// node_modules/.pnpm/entities@4.5.0/node_modules/entities/lib/esm/generated/decode-data-html.js\nvar decode_data_html_default = new Uint16Array(\n // prettier-ignore\n 'ᵁ<Õıʊҝջאٵ۞ޢߖࠏ੊ઑඡ๭༉༦჊ረዡᐕᒝᓃᓟᔥ\\0\\0\\0\\0\\0\\0ᕫᛍᦍᰒᷝ὾⁠↰⊍⏀⏻⑂⠤⤒ⴈ⹈⿎〖㊺㘹㞬㣾㨨㩱㫠㬮ࠀEMabcfglmnoprstu\\\\bfms„‹•˜¦³¹ÈÏlig耻Æ䃆P耻&䀦cute耻Á䃁reve;䄂Āiyx}rc耻Â䃂;䐐r;쀀𝔄rave耻À䃀pha;䎑acr;䄀d;橓Āgp¡on;䄄f;쀀𝔸plyFunction;恡ing耻Å䃅Ācs¾Ãr;쀀𝒜ign;扔ilde耻Ã䃃ml耻Ä䃄ЀaceforsuåûþėĜĢħĪĀcrêòkslash;或Ŷöø;櫧ed;挆y;䐑ƀcrtąċĔause;戵noullis;愬a;䎒r;쀀𝔅pf;쀀𝔹eve;䋘còēmpeq;扎܀HOacdefhilorsuōőŖƀƞƢƵƷƺǜȕɳɸɾcy;䐧PY耻©䂩ƀcpyŝŢźute;䄆Ā;iŧŨ拒talDifferentialD;慅leys;愭ȀaeioƉƎƔƘron;䄌dil耻Ç䃇rc;䄈nint;戰ot;䄊ĀdnƧƭilla;䂸terDot;䂷òſi;䎧rcleȀDMPTLJNjǑǖot;抙inus;抖lus;投imes;抗oĀcsǢǸkwiseContourIntegral;戲eCurlyĀDQȃȏoubleQuote;思uote;怙ȀlnpuȞȨɇɕonĀ;eȥȦ户;橴ƀgitȯȶȺruent;扡nt;戯ourIntegral;戮ĀfrɌɎ;愂oduct;成nterClockwiseContourIntegral;戳oss;樯cr;쀀𝒞pĀ;Cʄʅ拓ap;才րDJSZacefiosʠʬʰʴʸˋ˗ˡ˦̳ҍĀ;oŹʥtrahd;椑cy;䐂cy;䐅cy;䐏ƀgrsʿ˄ˇger;怡r;憡hv;櫤Āayː˕ron;䄎;䐔lĀ;t˝˞戇a;䎔r;쀀𝔇Āaf˫̧Ācm˰̢riticalȀADGT̖̜̀̆cute;䂴oŴ̋̍;䋙bleAcute;䋝rave;䁠ilde;䋜ond;拄ferentialD;慆Ѱ̽\\0\\0\\0͔͂\\0Ѕf;쀀𝔻ƀ;DE͈͉͍䂨ot;惜qual;扐blèCDLRUVͣͲ΂ϏϢϸontourIntegraìȹoɴ͹\\0\\0ͻ»͉nArrow;懓Āeo·ΤftƀARTΐΖΡrrow;懐ightArrow;懔eåˊngĀLRΫτeftĀARγιrrow;柸ightArrow;柺ightArrow;柹ightĀATϘϞrrow;懒ee;抨pɁϩ\\0\\0ϯrrow;懑ownArrow;懕erticalBar;戥ǹABLRTaВЪаўѿͼrrowƀ;BUНОТ憓ar;椓pArrow;懵reve;䌑eft˒к\\0ц\\0ѐightVector;楐eeVector;楞ectorĀ;Bљњ憽ar;楖ightǔѧ\\0ѱeeVector;楟ectorĀ;BѺѻ懁ar;楗eeĀ;A҆҇护rrow;憧ĀctҒҗr;쀀𝒟rok;䄐ࠀNTacdfglmopqstuxҽӀӄӋӞӢӧӮӵԡԯԶՒ՝ՠեG;䅊H耻Ð䃐cute耻É䃉ƀaiyӒӗӜron;䄚rc耻Ê䃊;䐭ot;䄖r;쀀𝔈rave耻È䃈ement;戈ĀapӺӾcr;䄒tyɓԆ\\0\\0ԒmallSquare;旻erySmallSquare;斫ĀgpԦԪon;䄘f;쀀𝔼silon;䎕uĀaiԼՉlĀ;TՂՃ橵ilde;扂librium;懌Āci՗՚r;愰m;橳a;䎗ml耻Ë䃋Āipժկsts;戃onentialE;慇ʀcfiosօֈ֍ֲ׌y;䐤r;쀀𝔉lledɓ֗\\0\\0֣mallSquare;旼erySmallSquare;斪Ͱֺ\\0ֿ\\0\\0ׄf;쀀𝔽All;戀riertrf;愱cò׋؀JTabcdfgorstר׬ׯ׺؀ؒؖ؛؝أ٬ٲcy;䐃耻>䀾mmaĀ;d׷׸䎓;䏜reve;䄞ƀeiy؇،ؐdil;䄢rc;䄜;䐓ot;䄠r;쀀𝔊;拙pf;쀀𝔾eater̀EFGLSTصلَٖٛ٦qualĀ;Lؾؿ扥ess;招ullEqual;执reater;檢ess;扷lantEqual;橾ilde;扳cr;쀀𝒢;扫ЀAacfiosuڅڋږڛڞڪھۊRDcy;䐪Āctڐڔek;䋇;䁞irc;䄤r;愌lbertSpace;愋ǰگ\\0ڲf;愍izontalLine;攀Āctۃۅòکrok;䄦mpńېۘownHumðįqual;扏܀EJOacdfgmnostuۺ۾܃܇܎ܚܞܡܨ݄ݸދޏޕcy;䐕lig;䄲cy;䐁cute耻Í䃍Āiyܓܘrc耻Î䃎;䐘ot;䄰r;愑rave耻Ì䃌ƀ;apܠܯܿĀcgܴܷr;䄪inaryI;慈lieóϝǴ݉\\0ݢĀ;eݍݎ戬Āgrݓݘral;戫section;拂isibleĀCTݬݲomma;恣imes;恢ƀgptݿރވon;䄮f;쀀𝕀a;䎙cr;愐ilde;䄨ǫޚ\\0ޞcy;䐆l耻Ï䃏ʀcfosuެ޷޼߂ߐĀiyޱ޵rc;䄴;䐙r;쀀𝔍pf;쀀𝕁ǣ߇\\0ߌr;쀀𝒥rcy;䐈kcy;䐄΀HJacfosߤߨ߽߬߱ࠂࠈcy;䐥cy;䐌ppa;䎚Āey߶߻dil;䄶;䐚r;쀀𝔎pf;쀀𝕂cr;쀀𝒦րJTaceflmostࠥࠩࠬࡐࡣ঳সে্਷ੇcy;䐉耻<䀼ʀcmnpr࠷࠼ࡁࡄࡍute;䄹bda;䎛g;柪lacetrf;愒r;憞ƀaeyࡗ࡜ࡡron;䄽dil;䄻;䐛Āfsࡨ॰tԀACDFRTUVarࡾࢩࢱࣦ࣠ࣼयज़ΐ४Ānrࢃ࢏gleBracket;柨rowƀ;BR࢙࢚࢞憐ar;懤ightArrow;懆eiling;挈oǵࢷ\\0ࣃbleBracket;柦nǔࣈ\\0࣒eeVector;楡ectorĀ;Bࣛࣜ懃ar;楙loor;挊ightĀAV࣯ࣵrrow;憔ector;楎Āerँगeƀ;AVउऊऐ抣rrow;憤ector;楚iangleƀ;BEतथऩ抲ar;槏qual;抴pƀDTVषूौownVector;楑eeVector;楠ectorĀ;Bॖॗ憿ar;楘ectorĀ;B॥०憼ar;楒ightáΜs̀EFGLSTॾঋকঝঢভqualGreater;拚ullEqual;扦reater;扶ess;檡lantEqual;橽ilde;扲r;쀀𝔏Ā;eঽা拘ftarrow;懚idot;䄿ƀnpw৔ਖਛgȀLRlr৞৷ਂਐeftĀAR০৬rrow;柵ightArrow;柷ightArrow;柶eftĀarγਊightáοightáϊf;쀀𝕃erĀLRਢਬeftArrow;憙ightArrow;憘ƀchtਾੀੂòࡌ;憰rok;䅁;扪Ѐacefiosuਗ਼੝੠੷੼અઋ઎p;椅y;䐜Ādl੥੯iumSpace;恟lintrf;愳r;쀀𝔐nusPlus;戓pf;쀀𝕄cò੶;䎜ҀJacefostuણધભીଔଙඑ඗ඞcy;䐊cute;䅃ƀaey઴હાron;䅇dil;䅅;䐝ƀgswે૰଎ativeƀMTV૓૟૨ediumSpace;怋hiĀcn૦૘ë૙eryThiî૙tedĀGL૸ଆreaterGreateòٳessLesóੈLine;䀊r;쀀𝔑ȀBnptଢନଷ଺reak;恠BreakingSpace;䂠f;愕ڀ;CDEGHLNPRSTV୕ୖ୪୼஡௫ఄ౞಄ದ೘ൡඅ櫬Āou୛୤ngruent;扢pCap;扭oubleVerticalBar;戦ƀlqxஃஊ஛ement;戉ualĀ;Tஒஓ扠ilde;쀀≂̸ists;戄reater΀;EFGLSTஶஷ஽௉௓௘௥扯qual;扱ullEqual;쀀≧̸reater;쀀≫̸ess;批lantEqual;쀀⩾̸ilde;扵umpń௲௽ownHump;쀀≎̸qual;쀀≏̸eĀfsఊధtTriangleƀ;BEచఛడ拪ar;쀀⧏̸qual;括s̀;EGLSTవశ఼ౄోౘ扮qual;扰reater;扸ess;쀀≪̸lantEqual;쀀⩽̸ilde;扴estedĀGL౨౹reaterGreater;쀀⪢̸essLess;쀀⪡̸recedesƀ;ESಒಓಛ技qual;쀀⪯̸lantEqual;拠ĀeiಫಹverseElement;戌ghtTriangleƀ;BEೋೌ೒拫ar;쀀⧐̸qual;拭ĀquೝഌuareSuĀbp೨೹setĀ;E೰ೳ쀀⊏̸qual;拢ersetĀ;Eഃആ쀀⊐̸qual;拣ƀbcpഓതൎsetĀ;Eഛഞ쀀⊂⃒qual;抈ceedsȀ;ESTലള഻െ抁qual;쀀⪰̸lantEqual;拡ilde;쀀≿̸ersetĀ;E൘൛쀀⊃⃒qual;抉ildeȀ;EFT൮൯൵ൿ扁qual;扄ullEqual;扇ilde;扉erticalBar;戤cr;쀀𝒩ilde耻Ñ䃑;䎝܀Eacdfgmoprstuvලෂ෉෕ෛ෠෧෼ขภยา฿ไlig;䅒cute耻Ó䃓Āiy෎ීrc耻Ô䃔;䐞blac;䅐r;쀀𝔒rave耻Ò䃒ƀaei෮ෲ෶cr;䅌ga;䎩cron;䎟pf;쀀𝕆enCurlyĀDQฎบoubleQuote;怜uote;怘;橔Āclวฬr;쀀𝒪ash耻Ø䃘iŬื฼de耻Õ䃕es;樷ml耻Ö䃖erĀBP๋๠Āar๐๓r;怾acĀek๚๜;揞et;掴arenthesis;揜Ҁacfhilors๿ງຊຏຒດຝະ໼rtialD;戂y;䐟r;쀀𝔓i;䎦;䎠usMinus;䂱Āipຢອncareplanåڝf;愙Ȁ;eio຺ູ໠໤檻cedesȀ;EST່້໏໚扺qual;檯lantEqual;扼ilde;找me;怳Ādp໩໮uct;戏ortionĀ;aȥ໹l;戝Āci༁༆r;쀀𝒫;䎨ȀUfos༑༖༛༟OT耻\"䀢r;쀀𝔔pf;愚cr;쀀𝒬؀BEacefhiorsu༾གྷཇའཱིྦྷྪྭ႖ႩႴႾarr;椐G耻®䂮ƀcnrཎནབute;䅔g;柫rĀ;tཛྷཝ憠l;椖ƀaeyཧཬཱron;䅘dil;䅖;䐠Ā;vླྀཹ愜erseĀEUྂྙĀlq྇ྎement;戋uilibrium;懋pEquilibrium;楯r»ཹo;䎡ghtЀACDFTUVa࿁࿫࿳ဢဨၛႇϘĀnr࿆࿒gleBracket;柩rowƀ;BL࿜࿝࿡憒ar;懥eftArrow;懄eiling;按oǵ࿹\\0စbleBracket;柧nǔည\\0နeeVector;楝ectorĀ;Bဝသ懂ar;楕loor;挋Āerိ၃eƀ;AVဵံြ抢rrow;憦ector;楛iangleƀ;BEၐၑၕ抳ar;槐qual;抵pƀDTVၣၮၸownVector;楏eeVector;楜ectorĀ;Bႂႃ憾ar;楔ectorĀ;B႑႒懀ar;楓Āpuႛ႞f;愝ndImplies;楰ightarrow;懛ĀchႹႼr;愛;憱leDelayed;槴ڀHOacfhimoqstuფჱჷჽᄙᄞᅑᅖᅡᅧᆵᆻᆿĀCcჩხHcy;䐩y;䐨FTcy;䐬cute;䅚ʀ;aeiyᄈᄉᄎᄓᄗ檼ron;䅠dil;䅞rc;䅜;䐡r;쀀𝔖ortȀDLRUᄪᄴᄾᅉownArrow»ОeftArrow»࢚ightArrow»࿝pArrow;憑gma;䎣allCircle;战pf;쀀𝕊ɲᅭ\\0\\0ᅰt;戚areȀ;ISUᅻᅼᆉᆯ斡ntersection;抓uĀbpᆏᆞsetĀ;Eᆗᆘ抏qual;抑ersetĀ;Eᆨᆩ抐qual;抒nion;抔cr;쀀𝒮ar;拆ȀbcmpᇈᇛሉላĀ;sᇍᇎ拐etĀ;Eᇍᇕqual;抆ĀchᇠህeedsȀ;ESTᇭᇮᇴᇿ扻qual;檰lantEqual;扽ilde;承Tháྌ;我ƀ;esሒሓሣ拑rsetĀ;Eሜም抃qual;抇et»ሓրHRSacfhiorsሾቄ቉ቕ቞ቱቶኟዂወዑORN耻Þ䃞ADE;愢ĀHc቎ቒcy;䐋y;䐦Ābuቚቜ;䀉;䎤ƀaeyብቪቯron;䅤dil;䅢;䐢r;쀀𝔗Āeiቻ኉Dzኀ\\0ኇefore;戴a;䎘Ācn኎ኘkSpace;쀀  Space;怉ldeȀ;EFTካኬኲኼ戼qual;扃ullEqual;扅ilde;扈pf;쀀𝕋ipleDot;惛Āctዖዛr;쀀𝒯rok;䅦ૡዷጎጚጦ\\0ጬጱ\\0\\0\\0\\0\\0ጸጽ፷ᎅ\\0᏿ᐄᐊᐐĀcrዻጁute耻Ú䃚rĀ;oጇገ憟cir;楉rǣጓ\\0጖y;䐎ve;䅬Āiyጞጣrc耻Û䃛;䐣blac;䅰r;쀀𝔘rave耻Ù䃙acr;䅪Ādiፁ፩erĀBPፈ፝Āarፍፐr;䁟acĀekፗፙ;揟et;掵arenthesis;揝onĀ;P፰፱拃lus;抎Āgp፻፿on;䅲f;쀀𝕌ЀADETadps᎕ᎮᎸᏄϨᏒᏗᏳrrowƀ;BDᅐᎠᎤar;椒ownArrow;懅ownArrow;憕quilibrium;楮eeĀ;AᏋᏌ报rrow;憥ownáϳerĀLRᏞᏨeftArrow;憖ightArrow;憗iĀ;lᏹᏺ䏒on;䎥ing;䅮cr;쀀𝒰ilde;䅨ml耻Ü䃜ҀDbcdefosvᐧᐬᐰᐳᐾᒅᒊᒐᒖash;披ar;櫫y;䐒ashĀ;lᐻᐼ抩;櫦Āerᑃᑅ;拁ƀbtyᑌᑐᑺar;怖Ā;iᑏᑕcalȀBLSTᑡᑥᑪᑴar;戣ine;䁼eparator;杘ilde;所ThinSpace;怊r;쀀𝔙pf;쀀𝕍cr;쀀𝒱dash;抪ʀcefosᒧᒬᒱᒶᒼirc;䅴dge;拀r;쀀𝔚pf;쀀𝕎cr;쀀𝒲Ȁfiosᓋᓐᓒᓘr;쀀𝔛;䎞pf;쀀𝕏cr;쀀𝒳ҀAIUacfosuᓱᓵᓹᓽᔄᔏᔔᔚᔠcy;䐯cy;䐇cy;䐮cute耻Ý䃝Āiyᔉᔍrc;䅶;䐫r;쀀𝔜pf;쀀𝕐cr;쀀𝒴ml;䅸ЀHacdefosᔵᔹᔿᕋᕏᕝᕠᕤcy;䐖cute;䅹Āayᕄᕉron;䅽;䐗ot;䅻Dzᕔ\\0ᕛoWidtè૙a;䎖r;愨pf;愤cr;쀀𝒵௡ᖃᖊᖐ\\0ᖰᖶᖿ\\0\\0\\0\\0ᗆᗛᗫᙟ᙭\\0ᚕ᚛ᚲᚹ\\0ᚾcute耻á䃡reve;䄃̀;Ediuyᖜᖝᖡᖣᖨᖭ戾;쀀∾̳;房rc耻â䃢te肻´̆;䐰lig耻æ䃦Ā;r²ᖺ;쀀𝔞rave耻à䃠ĀepᗊᗖĀfpᗏᗔsym;愵èᗓha;䎱ĀapᗟcĀclᗤᗧr;䄁g;樿ɤᗰ\\0\\0ᘊʀ;adsvᗺᗻᗿᘁᘇ戧nd;橕;橜lope;橘;橚΀;elmrszᘘᘙᘛᘞᘿᙏᙙ戠;榤e»ᘙsdĀ;aᘥᘦ戡ѡᘰᘲᘴᘶᘸᘺᘼᘾ;榨;榩;榪;榫;榬;榭;榮;榯tĀ;vᙅᙆ戟bĀ;dᙌᙍ抾;榝Āptᙔᙗh;戢»¹arr;捼Āgpᙣᙧon;䄅f;쀀𝕒΀;Eaeiop዁ᙻᙽᚂᚄᚇᚊ;橰cir;橯;扊d;手s;䀧roxĀ;e዁ᚒñᚃing耻å䃥ƀctyᚡᚦᚨr;쀀𝒶;䀪mpĀ;e዁ᚯñʈilde耻ã䃣ml耻ä䃤Āciᛂᛈoninôɲnt;樑ࠀNabcdefiklnoprsu᛭ᛱᜰ᜼ᝃᝈ᝸᝽០៦ᠹᡐᜍ᤽᥈ᥰot;櫭Ācrᛶ᜞kȀcepsᜀᜅᜍᜓong;扌psilon;䏶rime;怵imĀ;e᜚᜛戽q;拍Ŷᜢᜦee;抽edĀ;gᜬᜭ挅e»ᜭrkĀ;t፜᜷brk;掶Āoyᜁᝁ;䐱quo;怞ʀcmprtᝓ᝛ᝡᝤᝨausĀ;eĊĉptyv;榰séᜌnoõēƀahwᝯ᝱ᝳ;䎲;愶een;扬r;쀀𝔟g΀costuvwឍឝឳេ៕៛៞ƀaiuបពរðݠrc;旯p»፱ƀdptឤឨឭot;樀lus;樁imes;樂ɱឹ\\0\\0ើcup;樆ar;昅riangleĀdu៍្own;施p;斳plus;樄eåᑄåᒭarow;植ƀako៭ᠦᠵĀcn៲ᠣkƀlst៺֫᠂ozenge;槫riangleȀ;dlr᠒᠓᠘᠝斴own;斾eft;旂ight;斸k;搣Ʊᠫ\\0ᠳƲᠯ\\0ᠱ;斒;斑4;斓ck;斈ĀeoᠾᡍĀ;qᡃᡆ쀀=⃥uiv;쀀≡⃥t;挐Ȁptwxᡙᡞᡧᡬf;쀀𝕓Ā;tᏋᡣom»Ꮜtie;拈؀DHUVbdhmptuvᢅᢖᢪᢻᣗᣛᣬ᣿ᤅᤊᤐᤡȀLRlrᢎᢐᢒᢔ;敗;敔;敖;敓ʀ;DUduᢡᢢᢤᢦᢨ敐;敦;敩;敤;敧ȀLRlrᢳᢵᢷᢹ;敝;敚;敜;教΀;HLRhlrᣊᣋᣍᣏᣑᣓᣕ救;敬;散;敠;敫;敢;敟ox;槉ȀLRlrᣤᣦᣨᣪ;敕;敒;攐;攌ʀ;DUduڽ᣷᣹᣻᣽;敥;敨;攬;攴inus;抟lus;択imes;抠ȀLRlrᤙᤛᤝ᤟;敛;敘;攘;攔΀;HLRhlrᤰᤱᤳᤵᤷ᤻᤹攂;敪;敡;敞;攼;攤;攜Āevģ᥂bar耻¦䂦Ȁceioᥑᥖᥚᥠr;쀀𝒷mi;恏mĀ;e᜚᜜lƀ;bhᥨᥩᥫ䁜;槅sub;柈Ŭᥴ᥾lĀ;e᥹᥺怢t»᥺pƀ;Eeįᦅᦇ;檮Ā;qۜۛೡᦧ\\0᧨ᨑᨕᨲ\\0ᨷᩐ\\0\\0᪴\\0\\0᫁\\0\\0ᬡᬮ᭍᭒\\0᯽\\0ᰌƀcpr᦭ᦲ᧝ute;䄇̀;abcdsᦿᧀᧄ᧊᧕᧙戩nd;橄rcup;橉Āau᧏᧒p;橋p;橇ot;橀;쀀∩︀Āeo᧢᧥t;恁îړȀaeiu᧰᧻ᨁᨅǰ᧵\\0᧸s;橍on;䄍dil耻ç䃧rc;䄉psĀ;sᨌᨍ橌m;橐ot;䄋ƀdmnᨛᨠᨦil肻¸ƭptyv;榲t脀¢;eᨭᨮ䂢räƲr;쀀𝔠ƀceiᨽᩀᩍy;䑇ckĀ;mᩇᩈ朓ark»ᩈ;䏇r΀;Ecefms᩟᩠ᩢᩫ᪤᪪᪮旋;槃ƀ;elᩩᩪᩭ䋆q;扗eɡᩴ\\0\\0᪈rrowĀlr᩼᪁eft;憺ight;憻ʀRSacd᪒᪔᪖᪚᪟»ཇ;擈st;抛irc;抚ash;抝nint;樐id;櫯cir;槂ubsĀ;u᪻᪼晣it»᪼ˬ᫇᫔᫺\\0ᬊonĀ;eᫍᫎ䀺Ā;qÇÆɭ᫙\\0\\0᫢aĀ;t᫞᫟䀬;䁀ƀ;fl᫨᫩᫫戁îᅠeĀmx᫱᫶ent»᫩eóɍǧ᫾\\0ᬇĀ;dኻᬂot;橭nôɆƀfryᬐᬔᬗ;쀀𝕔oäɔ脀©;sŕᬝr;愗Āaoᬥᬩrr;憵ss;朗Ācuᬲᬷr;쀀𝒸Ābpᬼ᭄Ā;eᭁᭂ櫏;櫑Ā;eᭉᭊ櫐;櫒dot;拯΀delprvw᭠᭬᭷ᮂᮬᯔ᯹arrĀlr᭨᭪;椸;椵ɰ᭲\\0\\0᭵r;拞c;拟arrĀ;p᭿ᮀ憶;椽̀;bcdosᮏᮐᮖᮡᮥᮨ截rcap;橈Āauᮛᮞp;橆p;橊ot;抍r;橅;쀀∪︀Ȁalrv᮵ᮿᯞᯣrrĀ;mᮼᮽ憷;椼yƀevwᯇᯔᯘqɰᯎ\\0\\0ᯒreã᭳uã᭵ee;拎edge;拏en耻¤䂤earrowĀlrᯮ᯳eft»ᮀight»ᮽeäᯝĀciᰁᰇoninôǷnt;戱lcty;挭ঀAHabcdefhijlorstuwz᰸᰻᰿ᱝᱩᱵᲊᲞᲬᲷ᳻᳿ᴍᵻᶑᶫᶻ᷆᷍rò΁ar;楥Ȁglrs᱈ᱍ᱒᱔ger;怠eth;愸òᄳhĀ;vᱚᱛ怐»ऊūᱡᱧarow;椏aã̕Āayᱮᱳron;䄏;䐴ƀ;ao̲ᱼᲄĀgrʿᲁr;懊tseq;橷ƀglmᲑᲔᲘ耻°䂰ta;䎴ptyv;榱ĀirᲣᲨsht;楿;쀀𝔡arĀlrᲳᲵ»ࣜ»သʀaegsv᳂͸᳖᳜᳠mƀ;oș᳊᳔ndĀ;ș᳑uit;晦amma;䏝in;拲ƀ;io᳧᳨᳸䃷de脀÷;o᳧ᳰntimes;拇nø᳷cy;䑒cɯᴆ\\0\\0ᴊrn;挞op;挍ʀlptuwᴘᴝᴢᵉᵕlar;䀤f;쀀𝕕ʀ;emps̋ᴭᴷᴽᵂqĀ;d͒ᴳot;扑inus;戸lus;戔quare;抡blebarwedgåúnƀadhᄮᵝᵧownarrowóᲃarpoonĀlrᵲᵶefôᲴighôᲶŢᵿᶅkaro÷གɯᶊ\\0\\0ᶎrn;挟op;挌ƀcotᶘᶣᶦĀryᶝᶡ;쀀𝒹;䑕l;槶rok;䄑Ādrᶰᶴot;拱iĀ;fᶺ᠖斿Āah᷀᷃ròЩaòྦangle;榦Āci᷒ᷕy;䑟grarr;柿ऀDacdefglmnopqrstuxḁḉḙḸոḼṉṡṾấắẽỡἪἷὄ὎὚ĀDoḆᴴoôᲉĀcsḎḔute耻é䃩ter;橮ȀaioyḢḧḱḶron;䄛rĀ;cḭḮ扖耻ê䃪lon;払;䑍ot;䄗ĀDrṁṅot;扒;쀀𝔢ƀ;rsṐṑṗ檚ave耻è䃨Ā;dṜṝ檖ot;檘Ȁ;ilsṪṫṲṴ檙nters;揧;愓Ā;dṹṺ檕ot;檗ƀapsẅẉẗcr;䄓tyƀ;svẒẓẕ戅et»ẓpĀ1;ẝẤijạả;怄;怅怃ĀgsẪẬ;䅋p;怂ĀgpẴẸon;䄙f;쀀𝕖ƀalsỄỎỒrĀ;sỊị拕l;槣us;橱iƀ;lvỚớở䎵on»ớ;䏵ȀcsuvỪỳἋἣĀioữḱrc»Ḯɩỹ\\0\\0ỻíՈantĀglἂἆtr»ṝess»Ṻƀaeiἒ἖Ἒls;䀽st;扟vĀ;DȵἠD;橸parsl;槥ĀDaἯἳot;打rr;楱ƀcdiἾὁỸr;愯oô͒ĀahὉὋ;䎷耻ð䃰Āmrὓὗl耻ë䃫o;悬ƀcipὡὤὧl;䀡sôծĀeoὬὴctatioîՙnentialåչৡᾒ\\0ᾞ\\0ᾡᾧ\\0\\0ῆῌ\\0ΐ\\0ῦῪ \\0 ⁚llingdotseñṄy;䑄male;晀ƀilrᾭᾳ῁lig;耀ffiɩᾹ\\0\\0᾽g;耀ffig;耀ffl;쀀𝔣lig;耀filig;쀀fjƀaltῙ῜ῡt;晭ig;耀flns;斱of;䆒ǰ΅\\0ῳf;쀀𝕗ĀakֿῷĀ;vῼ´拔;櫙artint;樍Āao‌⁕Ācs‑⁒ႉ‸⁅⁈\\0⁐β•‥‧‪‬\\0‮耻½䂽;慓耻¼䂼;慕;慙;慛Ƴ‴\\0‶;慔;慖ʴ‾⁁\\0\\0⁃耻¾䂾;慗;慜5;慘ƶ⁌\\0⁎;慚;慝8;慞l;恄wn;挢cr;쀀𝒻ࢀEabcdefgijlnorstv₂₉₟₥₰₴⃰⃵⃺⃿℃ℒℸ̗ℾ⅒↞Ā;lٍ₇;檌ƀcmpₐₕ₝ute;䇵maĀ;dₜ᳚䎳;檆reve;䄟Āiy₪₮rc;䄝;䐳ot;䄡Ȁ;lqsؾق₽⃉ƀ;qsؾٌ⃄lanô٥Ȁ;cdl٥⃒⃥⃕c;檩otĀ;o⃜⃝檀Ā;l⃢⃣檂;檄Ā;e⃪⃭쀀⋛︀s;檔r;쀀𝔤Ā;gٳ؛mel;愷cy;䑓Ȁ;Eajٚℌℎℐ;檒;檥;檤ȀEaesℛℝ℩ℴ;扩pĀ;p℣ℤ檊rox»ℤĀ;q℮ℯ檈Ā;q℮ℛim;拧pf;쀀𝕘Āci⅃ⅆr;愊mƀ;el٫ⅎ⅐;檎;檐茀>;cdlqr׮ⅠⅪⅮⅳⅹĀciⅥⅧ;檧r;橺ot;拗Par;榕uest;橼ʀadelsↄⅪ←ٖ↛ǰ↉\\0↎proø₞r;楸qĀlqؿ↖lesó₈ií٫Āen↣↭rtneqq;쀀≩︀Å↪ԀAabcefkosy⇄⇇⇱⇵⇺∘∝∯≨≽ròΠȀilmr⇐⇔⇗⇛rsðᒄf»․ilôکĀdr⇠⇤cy;䑊ƀ;cwࣴ⇫⇯ir;楈;憭ar;意irc;䄥ƀalr∁∎∓rtsĀ;u∉∊晥it»∊lip;怦con;抹r;쀀𝔥sĀew∣∩arow;椥arow;椦ʀamopr∺∾≃≞≣rr;懿tht;戻kĀlr≉≓eftarrow;憩ightarrow;憪f;쀀𝕙bar;怕ƀclt≯≴≸r;쀀𝒽asè⇴rok;䄧Ābp⊂⊇ull;恃hen»ᱛૡ⊣\\0⊪\\0⊸⋅⋎\\0⋕⋳\\0\\0⋸⌢⍧⍢⍿\\0⎆⎪⎴cute耻í䃭ƀ;iyݱ⊰⊵rc耻î䃮;䐸Ācx⊼⊿y;䐵cl耻¡䂡ĀfrΟ⋉;쀀𝔦rave耻ì䃬Ȁ;inoܾ⋝⋩⋮Āin⋢⋦nt;樌t;戭fin;槜ta;愩lig;䄳ƀaop⋾⌚⌝ƀcgt⌅⌈⌗r;䄫ƀelpܟ⌏⌓inåގarôܠh;䄱f;抷ed;䆵ʀ;cfotӴ⌬⌱⌽⍁are;愅inĀ;t⌸⌹戞ie;槝doô⌙ʀ;celpݗ⍌⍐⍛⍡al;抺Āgr⍕⍙eróᕣã⍍arhk;樗rod;樼Ȁcgpt⍯⍲⍶⍻y;䑑on;䄯f;쀀𝕚a;䎹uest耻¿䂿Āci⎊⎏r;쀀𝒾nʀ;EdsvӴ⎛⎝⎡ӳ;拹ot;拵Ā;v⎦⎧拴;拳Ā;iݷ⎮lde;䄩ǫ⎸\\0⎼cy;䑖l耻ï䃯̀cfmosu⏌⏗⏜⏡⏧⏵Āiy⏑⏕rc;䄵;䐹r;쀀𝔧ath;䈷pf;쀀𝕛ǣ⏬\\0⏱r;쀀𝒿rcy;䑘kcy;䑔Ѐacfghjos␋␖␢␧␭␱␵␻ppaĀ;v␓␔䎺;䏰Āey␛␠dil;䄷;䐺r;쀀𝔨reen;䄸cy;䑅cy;䑜pf;쀀𝕜cr;쀀𝓀஀ABEHabcdefghjlmnoprstuv⑰⒁⒆⒍⒑┎┽╚▀♎♞♥♹♽⚚⚲⛘❝❨➋⟀⠁⠒ƀart⑷⑺⑼rò৆òΕail;椛arr;椎Ā;gঔ⒋;檋ar;楢ॣ⒥\\0⒪\\0⒱\\0\\0\\0\\0\\0⒵Ⓔ\\0ⓆⓈⓍ\\0⓹ute;䄺mptyv;榴raîࡌbda;䎻gƀ;dlࢎⓁⓃ;榑åࢎ;檅uo耻«䂫rЀ;bfhlpst࢙ⓞⓦⓩ⓫⓮⓱⓵Ā;f࢝ⓣs;椟s;椝ë≒p;憫l;椹im;楳l;憢ƀ;ae⓿─┄檫il;椙Ā;s┉┊檭;쀀⪭︀ƀabr┕┙┝rr;椌rk;杲Āak┢┬cĀek┨┪;䁻;䁛Āes┱┳;榋lĀdu┹┻;榏;榍Ȁaeuy╆╋╖╘ron;䄾Ādi═╔il;䄼ìࢰâ┩;䐻Ȁcqrs╣╦╭╽a;椶uoĀ;rนᝆĀdu╲╷har;楧shar;楋h;憲ʀ;fgqs▋▌উ◳◿扤tʀahlrt▘▤▷◂◨rrowĀ;t࢙□aé⓶arpoonĀdu▯▴own»њp»०eftarrows;懇ightƀahs◍◖◞rrowĀ;sࣴࢧarpoonó྘quigarro÷⇰hreetimes;拋ƀ;qs▋ও◺lanôবʀ;cdgsব☊☍☝☨c;檨otĀ;o☔☕橿Ā;r☚☛檁;檃Ā;e☢☥쀀⋚︀s;檓ʀadegs☳☹☽♉♋pproøⓆot;拖qĀgq♃♅ôউgtò⒌ôছiíলƀilr♕࣡♚sht;楼;쀀𝔩Ā;Eজ♣;檑š♩♶rĀdu▲♮Ā;l॥♳;楪lk;斄cy;䑙ʀ;achtੈ⚈⚋⚑⚖rò◁orneòᴈard;楫ri;旺Āio⚟⚤dot;䅀ustĀ;a⚬⚭掰che»⚭ȀEaes⚻⚽⛉⛔;扨pĀ;p⛃⛄檉rox»⛄Ā;q⛎⛏檇Ā;q⛎⚻im;拦Ѐabnoptwz⛩⛴⛷✚✯❁❇❐Ānr⛮⛱g;柬r;懽rëࣁgƀlmr⛿✍✔eftĀar০✇ightá৲apsto;柼ightá৽parrowĀlr✥✩efô⓭ight;憬ƀafl✶✹✽r;榅;쀀𝕝us;樭imes;樴š❋❏st;戗áፎƀ;ef❗❘᠀旊nge»❘arĀ;l❤❥䀨t;榓ʀachmt❳❶❼➅➇ròࢨorneòᶌarĀ;d྘➃;業;怎ri;抿̀achiqt➘➝ੀ➢➮➻quo;怹r;쀀𝓁mƀ;egল➪➬;檍;檏Ābu┪➳oĀ;rฟ➹;怚rok;䅂萀<;cdhilqrࠫ⟒☹⟜⟠⟥⟪⟰Āci⟗⟙;檦r;橹reå◲mes;拉arr;楶uest;橻ĀPi⟵⟹ar;榖ƀ;ef⠀भ᠛旃rĀdu⠇⠍shar;楊har;楦Āen⠗⠡rtneqq;쀀≨︀Å⠞܀Dacdefhilnopsu⡀⡅⢂⢎⢓⢠⢥⢨⣚⣢⣤ઃ⣳⤂Dot;戺Ȁclpr⡎⡒⡣⡽r耻¯䂯Āet⡗⡙;時Ā;e⡞⡟朠se»⡟Ā;sျ⡨toȀ;dluျ⡳⡷⡻owîҌefôएðᏑker;斮Āoy⢇⢌mma;権;䐼ash;怔asuredangle»ᘦr;쀀𝔪o;愧ƀcdn⢯⢴⣉ro耻µ䂵Ȁ;acdᑤ⢽⣀⣄sôᚧir;櫰ot肻·Ƶusƀ;bd⣒ᤃ⣓戒Ā;uᴼ⣘;横ţ⣞⣡p;櫛ò−ðઁĀdp⣩⣮els;抧f;쀀𝕞Āct⣸⣽r;쀀𝓂pos»ᖝƀ;lm⤉⤊⤍䎼timap;抸ఀGLRVabcdefghijlmoprstuvw⥂⥓⥾⦉⦘⧚⧩⨕⨚⩘⩝⪃⪕⪤⪨⬄⬇⭄⭿⮮ⰴⱧⱼ⳩Āgt⥇⥋;쀀⋙̸Ā;v⥐௏쀀≫⃒ƀelt⥚⥲⥶ftĀar⥡⥧rrow;懍ightarrow;懎;쀀⋘̸Ā;v⥻ే쀀≪⃒ightarrow;懏ĀDd⦎⦓ash;抯ash;抮ʀbcnpt⦣⦧⦬⦱⧌la»˞ute;䅄g;쀀∠⃒ʀ;Eiop඄⦼⧀⧅⧈;쀀⩰̸d;쀀≋̸s;䅉roø඄urĀ;a⧓⧔普lĀ;s⧓ସdz⧟\\0⧣p肻 ଷmpĀ;e௹ఀʀaeouy⧴⧾⨃⨐⨓ǰ⧹\\0⧻;橃on;䅈dil;䅆ngĀ;dൾ⨊ot;쀀⩭̸p;橂;䐽ash;怓΀;Aadqsxஒ⨩⨭⨻⩁⩅⩐rr;懗rĀhr⨳⨶k;椤Ā;oᏲᏰot;쀀≐̸uiöୣĀei⩊⩎ar;椨í஘istĀ;s஠டr;쀀𝔫ȀEest௅⩦⩹⩼ƀ;qs஼⩭௡ƀ;qs஼௅⩴lanô௢ií௪Ā;rஶ⪁»ஷƀAap⪊⪍⪑rò⥱rr;憮ar;櫲ƀ;svྍ⪜ྌĀ;d⪡⪢拼;拺cy;䑚΀AEadest⪷⪺⪾⫂⫅⫶⫹rò⥦;쀀≦̸rr;憚r;急Ȁ;fqs఻⫎⫣⫯tĀar⫔⫙rro÷⫁ightarro÷⪐ƀ;qs఻⪺⫪lanôౕĀ;sౕ⫴»శiíౝĀ;rవ⫾iĀ;eచథiäඐĀpt⬌⬑f;쀀𝕟膀¬;in⬙⬚⬶䂬nȀ;Edvஉ⬤⬨⬮;쀀⋹̸ot;쀀⋵̸ǡஉ⬳⬵;拷;拶iĀ;vಸ⬼ǡಸ⭁⭃;拾;拽ƀaor⭋⭣⭩rȀ;ast୻⭕⭚⭟lleì୻l;쀀⫽⃥;쀀∂̸lint;樔ƀ;ceಒ⭰⭳uåಥĀ;cಘ⭸Ā;eಒ⭽ñಘȀAait⮈⮋⮝⮧rò⦈rrƀ;cw⮔⮕⮙憛;쀀⤳̸;쀀↝̸ghtarrow»⮕riĀ;eೋೖ΀chimpqu⮽⯍⯙⬄୸⯤⯯Ȁ;cerല⯆ഷ⯉uå൅;쀀𝓃ortɭ⬅\\0\\0⯖ará⭖mĀ;e൮⯟Ā;q൴൳suĀbp⯫⯭å೸åഋƀbcp⯶ⰑⰙȀ;Ees⯿ⰀഢⰄ抄;쀀⫅̸etĀ;eഛⰋqĀ;qണⰀcĀ;eലⰗñസȀ;EesⰢⰣൟⰧ抅;쀀⫆̸etĀ;e൘ⰮqĀ;qൠⰣȀgilrⰽⰿⱅⱇìௗlde耻ñ䃱çృiangleĀlrⱒⱜeftĀ;eచⱚñదightĀ;eೋⱥñ೗Ā;mⱬⱭ䎽ƀ;esⱴⱵⱹ䀣ro;愖p;怇ҀDHadgilrsⲏⲔⲙⲞⲣⲰⲶⳓⳣash;抭arr;椄p;쀀≍⃒ash;抬ĀetⲨⲬ;쀀≥⃒;쀀>⃒nfin;槞ƀAetⲽⳁⳅrr;椂;쀀≤⃒Ā;rⳊⳍ쀀<⃒ie;쀀⊴⃒ĀAtⳘⳜrr;椃rie;쀀⊵⃒im;쀀∼⃒ƀAan⳰⳴ⴂrr;懖rĀhr⳺⳽k;椣Ā;oᏧᏥear;椧ቓ᪕\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0ⴭ\\0ⴸⵈⵠⵥ⵲ⶄᬇ\\0\\0ⶍⶫ\\0ⷈⷎ\\0ⷜ⸙⸫⸾⹃Ācsⴱ᪗ute耻ó䃳ĀiyⴼⵅrĀ;c᪞ⵂ耻ô䃴;䐾ʀabios᪠ⵒⵗLjⵚlac;䅑v;樸old;榼lig;䅓Ācr⵩⵭ir;榿;쀀𝔬ͯ⵹\\0\\0⵼\\0ⶂn;䋛ave耻ò䃲;槁Ābmⶈ෴ar;榵Ȁacitⶕ⶘ⶥⶨrò᪀Āir⶝ⶠr;榾oss;榻nå๒;槀ƀaeiⶱⶵⶹcr;䅍ga;䏉ƀcdnⷀⷅǍron;䎿;榶pf;쀀𝕠ƀaelⷔ⷗ǒr;榷rp;榹΀;adiosvⷪⷫⷮ⸈⸍⸐⸖戨rò᪆Ȁ;efmⷷⷸ⸂⸅橝rĀ;oⷾⷿ愴f»ⷿ耻ª䂪耻º䂺gof;抶r;橖lope;橗;橛ƀclo⸟⸡⸧ò⸁ash耻ø䃸l;折iŬⸯ⸴de耻õ䃵esĀ;aǛ⸺s;樶ml耻ö䃶bar;挽ૡ⹞\\0⹽\\0⺀⺝\\0⺢⺹\\0\\0⻋ຜ\\0⼓\\0\\0⼫⾼\\0⿈rȀ;astЃ⹧⹲຅脀¶;l⹭⹮䂶leìЃɩ⹸\\0\\0⹻m;櫳;櫽y;䐿rʀcimpt⺋⺏⺓ᡥ⺗nt;䀥od;䀮il;怰enk;怱r;쀀𝔭ƀimo⺨⺰⺴Ā;v⺭⺮䏆;䏕maô੶ne;明ƀ;tv⺿⻀⻈䏀chfork»´;䏖Āau⻏⻟nĀck⻕⻝kĀ;h⇴⻛;愎ö⇴sҀ;abcdemst⻳⻴ᤈ⻹⻽⼄⼆⼊⼎䀫cir;樣ir;樢Āouᵀ⼂;樥;橲n肻±ຝim;樦wo;樧ƀipu⼙⼠⼥ntint;樕f;쀀𝕡nd耻£䂣Ԁ;Eaceinosu່⼿⽁⽄⽇⾁⾉⾒⽾⾶;檳p;檷uå໙Ā;c໎⽌̀;acens່⽙⽟⽦⽨⽾pproø⽃urlyeñ໙ñ໎ƀaes⽯⽶⽺pprox;檹qq;檵im;拨iíໟmeĀ;s⾈ຮ怲ƀEas⽸⾐⽺ð⽵ƀdfp໬⾙⾯ƀals⾠⾥⾪lar;挮ine;挒urf;挓Ā;t໻⾴ï໻rel;抰Āci⿀⿅r;쀀𝓅;䏈ncsp;怈̀fiopsu⿚⋢⿟⿥⿫⿱r;쀀𝔮pf;쀀𝕢rime;恗cr;쀀𝓆ƀaeo⿸〉〓tĀei⿾々rnionóڰnt;樖stĀ;e【】䀿ñἙô༔઀ABHabcdefhilmnoprstux぀けさすムㄎㄫㅇㅢㅲㆎ㈆㈕㈤㈩㉘㉮㉲㊐㊰㊷ƀartぇおがròႳòϝail;検aròᱥar;楤΀cdenqrtとふへみわゔヌĀeuねぱ;쀀∽̱te;䅕iãᅮmptyv;榳gȀ;del࿑らるろ;榒;榥å࿑uo耻»䂻rր;abcfhlpstw࿜ガクシスゼゾダッデナp;極Ā;f࿠ゴs;椠;椳s;椞ë≝ð✮l;楅im;楴l;憣;憝Āaiパフil;椚oĀ;nホボ戶aló༞ƀabrョリヮrò៥rk;杳ĀakンヽcĀekヹ・;䁽;䁝Āes㄂㄄;榌lĀduㄊㄌ;榎;榐Ȁaeuyㄗㄜㄧㄩron;䅙Ādiㄡㄥil;䅗ì࿲âヺ;䑀Ȁclqsㄴㄷㄽㅄa;椷dhar;楩uoĀ;rȎȍh;憳ƀacgㅎㅟངlȀ;ipsླྀㅘㅛႜnåႻarôྩt;断ƀilrㅩဣㅮsht;楽;쀀𝔯ĀaoㅷㆆrĀduㅽㅿ»ѻĀ;l႑ㆄ;楬Ā;vㆋㆌ䏁;䏱ƀgns㆕ㇹㇼht̀ahlrstㆤㆰ㇂㇘㇤㇮rrowĀ;t࿜ㆭaéトarpoonĀduㆻㆿowîㅾp»႒eftĀah㇊㇐rrowó࿪arpoonóՑightarrows;應quigarro÷ニhreetimes;拌g;䋚ingdotseñἲƀahm㈍㈐㈓rò࿪aòՑ;怏oustĀ;a㈞㈟掱che»㈟mid;櫮Ȁabpt㈲㈽㉀㉒Ānr㈷㈺g;柭r;懾rëဃƀafl㉇㉊㉎r;榆;쀀𝕣us;樮imes;樵Āap㉝㉧rĀ;g㉣㉤䀩t;榔olint;樒arò㇣Ȁachq㉻㊀Ⴜ㊅quo;怺r;쀀𝓇Ābu・㊊oĀ;rȔȓƀhir㊗㊛㊠reåㇸmes;拊iȀ;efl㊪ၙᠡ㊫方tri;槎luhar;楨;愞ൡ㋕㋛㋟㌬㌸㍱\\0㍺㎤\\0\\0㏬㏰\\0㐨㑈㑚㒭㒱㓊㓱\\0㘖\\0\\0㘳cute;䅛quï➺Ԁ;Eaceinpsyᇭ㋳㋵㋿㌂㌋㌏㌟㌦㌩;檴ǰ㋺\\0㋼;檸on;䅡uåᇾĀ;dᇳ㌇il;䅟rc;䅝ƀEas㌖㌘㌛;檶p;檺im;择olint;樓iíሄ;䑁otƀ;be㌴ᵇ㌵担;橦΀Aacmstx㍆㍊㍗㍛㍞㍣㍭rr;懘rĀhr㍐㍒ë∨Ā;oਸ਼਴t耻§䂧i;䀻war;椩mĀin㍩ðnuóñt;朶rĀ;o㍶⁕쀀𝔰Ȁacoy㎂㎆㎑㎠rp;景Āhy㎋㎏cy;䑉;䑈rtɭ㎙\\0\\0㎜iäᑤaraì⹯耻­䂭Āgm㎨㎴maƀ;fv㎱㎲㎲䏃;䏂Ѐ;deglnprካ㏅㏉㏎㏖㏞㏡㏦ot;橪Ā;q኱ኰĀ;E㏓㏔檞;檠Ā;E㏛㏜檝;檟e;扆lus;樤arr;楲aròᄽȀaeit㏸㐈㐏㐗Āls㏽㐄lsetmé㍪hp;樳parsl;槤Ādlᑣ㐔e;挣Ā;e㐜㐝檪Ā;s㐢㐣檬;쀀⪬︀ƀflp㐮㐳㑂tcy;䑌Ā;b㐸㐹䀯Ā;a㐾㐿槄r;挿f;쀀𝕤aĀdr㑍ЂesĀ;u㑔㑕晠it»㑕ƀcsu㑠㑹㒟Āau㑥㑯pĀ;sᆈ㑫;쀀⊓︀pĀ;sᆴ㑵;쀀⊔︀uĀbp㑿㒏ƀ;esᆗᆜ㒆etĀ;eᆗ㒍ñᆝƀ;esᆨᆭ㒖etĀ;eᆨ㒝ñᆮƀ;afᅻ㒦ְrť㒫ֱ»ᅼaròᅈȀcemt㒹㒾㓂㓅r;쀀𝓈tmîñiì㐕aræᆾĀar㓎㓕rĀ;f㓔ឿ昆Āan㓚㓭ightĀep㓣㓪psiloîỠhé⺯s»⡒ʀbcmnp㓻㕞ሉ㖋㖎Ҁ;Edemnprs㔎㔏㔑㔕㔞㔣㔬㔱㔶抂;櫅ot;檽Ā;dᇚ㔚ot;櫃ult;櫁ĀEe㔨㔪;櫋;把lus;檿arr;楹ƀeiu㔽㕒㕕tƀ;en㔎㕅㕋qĀ;qᇚ㔏eqĀ;q㔫㔨m;櫇Ābp㕚㕜;櫕;櫓c̀;acensᇭ㕬㕲㕹㕻㌦pproø㋺urlyeñᇾñᇳƀaes㖂㖈㌛pproø㌚qñ㌗g;晪ڀ123;Edehlmnps㖩㖬㖯ሜ㖲㖴㗀㗉㗕㗚㗟㗨㗭耻¹䂹耻²䂲耻³䂳;櫆Āos㖹㖼t;檾ub;櫘Ā;dሢ㗅ot;櫄sĀou㗏㗒l;柉b;櫗arr;楻ult;櫂ĀEe㗤㗦;櫌;抋lus;櫀ƀeiu㗴㘉㘌tƀ;enሜ㗼㘂qĀ;qሢ㖲eqĀ;q㗧㗤m;櫈Ābp㘑㘓;櫔;櫖ƀAan㘜㘠㘭rr;懙rĀhr㘦㘨ë∮Ā;oਫ਩war;椪lig耻ß䃟௡㙑㙝㙠ዎ㙳㙹\\0㙾㛂\\0\\0\\0\\0\\0㛛㜃\\0㜉㝬\\0\\0\\0㞇ɲ㙖\\0\\0㙛get;挖;䏄rë๟ƀaey㙦㙫㙰ron;䅥dil;䅣;䑂lrec;挕r;쀀𝔱Ȁeiko㚆㚝㚵㚼Dz㚋\\0㚑eĀ4fኄኁaƀ;sv㚘㚙㚛䎸ym;䏑Ācn㚢㚲kĀas㚨㚮pproø዁im»ኬsðኞĀas㚺㚮ð዁rn耻þ䃾Ǭ̟㛆⋧es膀×;bd㛏㛐㛘䃗Ā;aᤏ㛕r;樱;樰ƀeps㛡㛣㜀á⩍Ȁ;bcf҆㛬㛰㛴ot;挶ir;櫱Ā;o㛹㛼쀀𝕥rk;櫚á㍢rime;怴ƀaip㜏㜒㝤dåቈ΀adempst㜡㝍㝀㝑㝗㝜㝟ngleʀ;dlqr㜰㜱㜶㝀㝂斵own»ᶻeftĀ;e⠀㜾ñम;扜ightĀ;e㊪㝋ñၚot;旬inus;樺lus;樹b;槍ime;樻ezium;揢ƀcht㝲㝽㞁Āry㝷㝻;쀀𝓉;䑆cy;䑛rok;䅧Āio㞋㞎xô᝷headĀlr㞗㞠eftarro÷ࡏightarrow»ཝऀAHabcdfghlmoprstuw㟐㟓㟗㟤㟰㟼㠎㠜㠣㠴㡑㡝㡫㢩㣌㣒㣪㣶ròϭar;楣Ācr㟜㟢ute耻ú䃺òᅐrǣ㟪\\0㟭y;䑞ve;䅭Āiy㟵㟺rc耻û䃻;䑃ƀabh㠃㠆㠋ròᎭlac;䅱aòᏃĀir㠓㠘sht;楾;쀀𝔲rave耻ù䃹š㠧㠱rĀlr㠬㠮»ॗ»ႃlk;斀Āct㠹㡍ɯ㠿\\0\\0㡊rnĀ;e㡅㡆挜r»㡆op;挏ri;旸Āal㡖㡚cr;䅫肻¨͉Āgp㡢㡦on;䅳f;쀀𝕦̀adhlsuᅋ㡸㡽፲㢑㢠ownáᎳarpoonĀlr㢈㢌efô㠭ighô㠯iƀ;hl㢙㢚㢜䏅»ᏺon»㢚parrows;懈ƀcit㢰㣄㣈ɯ㢶\\0\\0㣁rnĀ;e㢼㢽挝r»㢽op;挎ng;䅯ri;旹cr;쀀𝓊ƀdir㣙㣝㣢ot;拰lde;䅩iĀ;f㜰㣨»᠓Āam㣯㣲rò㢨l耻ü䃼angle;榧ހABDacdeflnoprsz㤜㤟㤩㤭㦵㦸㦽㧟㧤㧨㧳㧹㧽㨁㨠ròϷarĀ;v㤦㤧櫨;櫩asèϡĀnr㤲㤷grt;榜΀eknprst㓣㥆㥋㥒㥝㥤㦖appá␕othinçẖƀhir㓫⻈㥙opô⾵Ā;hᎷ㥢ïㆍĀiu㥩㥭gmá㎳Ābp㥲㦄setneqĀ;q㥽㦀쀀⊊︀;쀀⫋︀setneqĀ;q㦏㦒쀀⊋︀;쀀⫌︀Āhr㦛㦟etá㚜iangleĀlr㦪㦯eft»थight»ၑy;䐲ash»ံƀelr㧄㧒㧗ƀ;beⷪ㧋㧏ar;抻q;扚lip;拮Ābt㧜ᑨaòᑩr;쀀𝔳tré㦮suĀbp㧯㧱»ജ»൙pf;쀀𝕧roð໻tré㦴Ācu㨆㨋r;쀀𝓋Ābp㨐㨘nĀEe㦀㨖»㥾nĀEe㦒㨞»㦐igzag;榚΀cefoprs㨶㨻㩖㩛㩔㩡㩪irc;䅵Ādi㩀㩑Ābg㩅㩉ar;機eĀ;qᗺ㩏;扙erp;愘r;쀀𝔴pf;쀀𝕨Ā;eᑹ㩦atèᑹcr;쀀𝓌ૣណ㪇\\0㪋\\0㪐㪛\\0\\0㪝㪨㪫㪯\\0\\0㫃㫎\\0㫘ៜ៟tré៑r;쀀𝔵ĀAa㪔㪗ròσrò৶;䎾ĀAa㪡㪤ròθrò৫að✓is;拻ƀdptឤ㪵㪾Āfl㪺ឩ;쀀𝕩imåឲĀAa㫇㫊ròώròਁĀcq㫒ីr;쀀𝓍Āpt៖㫜ré។Ѐacefiosu㫰㫽㬈㬌㬑㬕㬛㬡cĀuy㫶㫻te耻ý䃽;䑏Āiy㬂㬆rc;䅷;䑋n耻¥䂥r;쀀𝔶cy;䑗pf;쀀𝕪cr;쀀𝓎Ācm㬦㬩y;䑎l耻ÿ䃿Ԁacdefhiosw㭂㭈㭔㭘㭤㭩㭭㭴㭺㮀cute;䅺Āay㭍㭒ron;䅾;䐷ot;䅼Āet㭝㭡træᕟa;䎶r;쀀𝔷cy;䐶grarr;懝pf;쀀𝕫cr;쀀𝓏Ājn㮅㮇;怍j;怌'.split(\"\").map((c) => c.charCodeAt(0))\n);\n\n// node_modules/.pnpm/entities@4.5.0/node_modules/entities/lib/esm/generated/decode-data-xml.js\nvar decode_data_xml_default = new Uint16Array(\n // prettier-ignore\n \"Ȁaglq\t\u0015\u0018\\x1Bɭ\u000f\\0\\0\u0012p;䀦os;䀧t;䀾t;䀼uot;䀢\".split(\"\").map((c) => c.charCodeAt(0))\n);\n\n// node_modules/.pnpm/entities@4.5.0/node_modules/entities/lib/esm/decode_codepoint.js\nvar _a2;\nvar decodeMap = /* @__PURE__ */ new Map([\n [0, 65533],\n // C1 Unicode control character reference replacements\n [128, 8364],\n [130, 8218],\n [131, 402],\n [132, 8222],\n [133, 8230],\n [134, 8224],\n [135, 8225],\n [136, 710],\n [137, 8240],\n [138, 352],\n [139, 8249],\n [140, 338],\n [142, 381],\n [145, 8216],\n [146, 8217],\n [147, 8220],\n [148, 8221],\n [149, 8226],\n [150, 8211],\n [151, 8212],\n [152, 732],\n [153, 8482],\n [154, 353],\n [155, 8250],\n [156, 339],\n [158, 382],\n [159, 376]\n]);\nvar fromCodePoint = (\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition, node/no-unsupported-features/es-builtins\n (_a2 = String.fromCodePoint) !== null && _a2 !== void 0 ? _a2 : function(codePoint) {\n let output = \"\";\n if (codePoint > 65535) {\n codePoint -= 65536;\n output += String.fromCharCode(codePoint >>> 10 & 1023 | 55296);\n codePoint = 56320 | codePoint & 1023;\n }\n output += String.fromCharCode(codePoint);\n return output;\n }\n);\nfunction replaceCodePoint(codePoint) {\n var _a3;\n if (codePoint >= 55296 && codePoint <= 57343 || codePoint > 1114111) {\n return 65533;\n }\n return (_a3 = decodeMap.get(codePoint)) !== null && _a3 !== void 0 ? _a3 : codePoint;\n}\n\n// node_modules/.pnpm/entities@4.5.0/node_modules/entities/lib/esm/decode.js\nvar CharCodes;\n(function(CharCodes2) {\n CharCodes2[CharCodes2[\"NUM\"] = 35] = \"NUM\";\n CharCodes2[CharCodes2[\"SEMI\"] = 59] = \"SEMI\";\n CharCodes2[CharCodes2[\"EQUALS\"] = 61] = \"EQUALS\";\n CharCodes2[CharCodes2[\"ZERO\"] = 48] = \"ZERO\";\n CharCodes2[CharCodes2[\"NINE\"] = 57] = \"NINE\";\n CharCodes2[CharCodes2[\"LOWER_A\"] = 97] = \"LOWER_A\";\n CharCodes2[CharCodes2[\"LOWER_F\"] = 102] = \"LOWER_F\";\n CharCodes2[CharCodes2[\"LOWER_X\"] = 120] = \"LOWER_X\";\n CharCodes2[CharCodes2[\"LOWER_Z\"] = 122] = \"LOWER_Z\";\n CharCodes2[CharCodes2[\"UPPER_A\"] = 65] = \"UPPER_A\";\n CharCodes2[CharCodes2[\"UPPER_F\"] = 70] = \"UPPER_F\";\n CharCodes2[CharCodes2[\"UPPER_Z\"] = 90] = \"UPPER_Z\";\n})(CharCodes || (CharCodes = {}));\nvar TO_LOWER_BIT = 32;\nvar BinTrieFlags;\n(function(BinTrieFlags2) {\n BinTrieFlags2[BinTrieFlags2[\"VALUE_LENGTH\"] = 49152] = \"VALUE_LENGTH\";\n BinTrieFlags2[BinTrieFlags2[\"BRANCH_LENGTH\"] = 16256] = \"BRANCH_LENGTH\";\n BinTrieFlags2[BinTrieFlags2[\"JUMP_TABLE\"] = 127] = \"JUMP_TABLE\";\n})(BinTrieFlags || (BinTrieFlags = {}));\nfunction isNumber(code2) {\n return code2 >= CharCodes.ZERO && code2 <= CharCodes.NINE;\n}\nfunction isHexadecimalCharacter(code2) {\n return code2 >= CharCodes.UPPER_A && code2 <= CharCodes.UPPER_F || code2 >= CharCodes.LOWER_A && code2 <= CharCodes.LOWER_F;\n}\nfunction isAsciiAlphaNumeric(code2) {\n return code2 >= CharCodes.UPPER_A && code2 <= CharCodes.UPPER_Z || code2 >= CharCodes.LOWER_A && code2 <= CharCodes.LOWER_Z || isNumber(code2);\n}\nfunction isEntityInAttributeInvalidEnd(code2) {\n return code2 === CharCodes.EQUALS || isAsciiAlphaNumeric(code2);\n}\nvar EntityDecoderState;\n(function(EntityDecoderState2) {\n EntityDecoderState2[EntityDecoderState2[\"EntityStart\"] = 0] = \"EntityStart\";\n EntityDecoderState2[EntityDecoderState2[\"NumericStart\"] = 1] = \"NumericStart\";\n EntityDecoderState2[EntityDecoderState2[\"NumericDecimal\"] = 2] = \"NumericDecimal\";\n EntityDecoderState2[EntityDecoderState2[\"NumericHex\"] = 3] = \"NumericHex\";\n EntityDecoderState2[EntityDecoderState2[\"NamedEntity\"] = 4] = \"NamedEntity\";\n})(EntityDecoderState || (EntityDecoderState = {}));\nvar DecodingMode;\n(function(DecodingMode2) {\n DecodingMode2[DecodingMode2[\"Legacy\"] = 0] = \"Legacy\";\n DecodingMode2[DecodingMode2[\"Strict\"] = 1] = \"Strict\";\n DecodingMode2[DecodingMode2[\"Attribute\"] = 2] = \"Attribute\";\n})(DecodingMode || (DecodingMode = {}));\nvar EntityDecoder = class {\n constructor(decodeTree, emitCodePoint, errors2) {\n this.decodeTree = decodeTree;\n this.emitCodePoint = emitCodePoint;\n this.errors = errors2;\n this.state = EntityDecoderState.EntityStart;\n this.consumed = 1;\n this.result = 0;\n this.treeIndex = 0;\n this.excess = 1;\n this.decodeMode = DecodingMode.Strict;\n }\n /** Resets the instance to make it reusable. */\n startEntity(decodeMode) {\n this.decodeMode = decodeMode;\n this.state = EntityDecoderState.EntityStart;\n this.result = 0;\n this.treeIndex = 0;\n this.excess = 1;\n this.consumed = 1;\n }\n /**\n * Write an entity to the decoder. This can be called multiple times with partial entities.\n * If the entity is incomplete, the decoder will return -1.\n *\n * Mirrors the implementation of `getDecoder`, but with the ability to stop decoding if the\n * entity is incomplete, and resume when the next string is written.\n *\n * @param string The string containing the entity (or a continuation of the entity).\n * @param offset The offset at which the entity begins. Should be 0 if this is not the first call.\n * @returns The number of characters that were consumed, or -1 if the entity is incomplete.\n */\n write(str, offset) {\n switch (this.state) {\n case EntityDecoderState.EntityStart: {\n if (str.charCodeAt(offset) === CharCodes.NUM) {\n this.state = EntityDecoderState.NumericStart;\n this.consumed += 1;\n return this.stateNumericStart(str, offset + 1);\n }\n this.state = EntityDecoderState.NamedEntity;\n return this.stateNamedEntity(str, offset);\n }\n case EntityDecoderState.NumericStart: {\n return this.stateNumericStart(str, offset);\n }\n case EntityDecoderState.NumericDecimal: {\n return this.stateNumericDecimal(str, offset);\n }\n case EntityDecoderState.NumericHex: {\n return this.stateNumericHex(str, offset);\n }\n case EntityDecoderState.NamedEntity: {\n return this.stateNamedEntity(str, offset);\n }\n }\n }\n /**\n * Switches between the numeric decimal and hexadecimal states.\n *\n * Equivalent to the `Numeric character reference state` in the HTML spec.\n *\n * @param str The string containing the entity (or a continuation of the entity).\n * @param offset The current offset.\n * @returns The number of characters that were consumed, or -1 if the entity is incomplete.\n */\n stateNumericStart(str, offset) {\n if (offset >= str.length) {\n return -1;\n }\n if ((str.charCodeAt(offset) | TO_LOWER_BIT) === CharCodes.LOWER_X) {\n this.state = EntityDecoderState.NumericHex;\n this.consumed += 1;\n return this.stateNumericHex(str, offset + 1);\n }\n this.state = EntityDecoderState.NumericDecimal;\n return this.stateNumericDecimal(str, offset);\n }\n addToNumericResult(str, start, end, base2) {\n if (start !== end) {\n const digitCount = end - start;\n this.result = this.result * Math.pow(base2, digitCount) + parseInt(str.substr(start, digitCount), base2);\n this.consumed += digitCount;\n }\n }\n /**\n * Parses a hexadecimal numeric entity.\n *\n * Equivalent to the `Hexademical character reference state` in the HTML spec.\n *\n * @param str The string containing the entity (or a continuation of the entity).\n * @param offset The current offset.\n * @returns The number of characters that were consumed, or -1 if the entity is incomplete.\n */\n stateNumericHex(str, offset) {\n const startIdx = offset;\n while (offset < str.length) {\n const char = str.charCodeAt(offset);\n if (isNumber(char) || isHexadecimalCharacter(char)) {\n offset += 1;\n } else {\n this.addToNumericResult(str, startIdx, offset, 16);\n return this.emitNumericEntity(char, 3);\n }\n }\n this.addToNumericResult(str, startIdx, offset, 16);\n return -1;\n }\n /**\n * Parses a decimal numeric entity.\n *\n * Equivalent to the `Decimal character reference state` in the HTML spec.\n *\n * @param str The string containing the entity (or a continuation of the entity).\n * @param offset The current offset.\n * @returns The number of characters that were consumed, or -1 if the entity is incomplete.\n */\n stateNumericDecimal(str, offset) {\n const startIdx = offset;\n while (offset < str.length) {\n const char = str.charCodeAt(offset);\n if (isNumber(char)) {\n offset += 1;\n } else {\n this.addToNumericResult(str, startIdx, offset, 10);\n return this.emitNumericEntity(char, 2);\n }\n }\n this.addToNumericResult(str, startIdx, offset, 10);\n return -1;\n }\n /**\n * Validate and emit a numeric entity.\n *\n * Implements the logic from the `Hexademical character reference start\n * state` and `Numeric character reference end state` in the HTML spec.\n *\n * @param lastCp The last code point of the entity. Used to see if the\n * entity was terminated with a semicolon.\n * @param expectedLength The minimum number of characters that should be\n * consumed. Used to validate that at least one digit\n * was consumed.\n * @returns The number of characters that were consumed.\n */\n emitNumericEntity(lastCp, expectedLength) {\n var _a3;\n if (this.consumed <= expectedLength) {\n (_a3 = this.errors) === null || _a3 === void 0 ? void 0 : _a3.absenceOfDigitsInNumericCharacterReference(this.consumed);\n return 0;\n }\n if (lastCp === CharCodes.SEMI) {\n this.consumed += 1;\n } else if (this.decodeMode === DecodingMode.Strict) {\n return 0;\n }\n this.emitCodePoint(replaceCodePoint(this.result), this.consumed);\n if (this.errors) {\n if (lastCp !== CharCodes.SEMI) {\n this.errors.missingSemicolonAfterCharacterReference();\n }\n this.errors.validateNumericCharacterReference(this.result);\n }\n return this.consumed;\n }\n /**\n * Parses a named entity.\n *\n * Equivalent to the `Named character reference state` in the HTML spec.\n *\n * @param str The string containing the entity (or a continuation of the entity).\n * @param offset The current offset.\n * @returns The number of characters that were consumed, or -1 if the entity is incomplete.\n */\n stateNamedEntity(str, offset) {\n const { decodeTree } = this;\n let current = decodeTree[this.treeIndex];\n let valueLength = (current & BinTrieFlags.VALUE_LENGTH) >> 14;\n for (; offset < str.length; offset++, this.excess++) {\n const char = str.charCodeAt(offset);\n this.treeIndex = determineBranch(decodeTree, current, this.treeIndex + Math.max(1, valueLength), char);\n if (this.treeIndex < 0) {\n return this.result === 0 || // If we are parsing an attribute\n this.decodeMode === DecodingMode.Attribute && // We shouldn't have consumed any characters after the entity,\n (valueLength === 0 || // And there should be no invalid characters.\n isEntityInAttributeInvalidEnd(char)) ? 0 : this.emitNotTerminatedNamedEntity();\n }\n current = decodeTree[this.treeIndex];\n valueLength = (current & BinTrieFlags.VALUE_LENGTH) >> 14;\n if (valueLength !== 0) {\n if (char === CharCodes.SEMI) {\n return this.emitNamedEntityData(this.treeIndex, valueLength, this.consumed + this.excess);\n }\n if (this.decodeMode !== DecodingMode.Strict) {\n this.result = this.treeIndex;\n this.consumed += this.excess;\n this.excess = 0;\n }\n }\n }\n return -1;\n }\n /**\n * Emit a named entity that was not terminated with a semicolon.\n *\n * @returns The number of characters consumed.\n */\n emitNotTerminatedNamedEntity() {\n var _a3;\n const { result, decodeTree } = this;\n const valueLength = (decodeTree[result] & BinTrieFlags.VALUE_LENGTH) >> 14;\n this.emitNamedEntityData(result, valueLength, this.consumed);\n (_a3 = this.errors) === null || _a3 === void 0 ? void 0 : _a3.missingSemicolonAfterCharacterReference();\n return this.consumed;\n }\n /**\n * Emit a named entity.\n *\n * @param result The index of the entity in the decode tree.\n * @param valueLength The number of bytes in the entity.\n * @param consumed The number of characters consumed.\n *\n * @returns The number of characters consumed.\n */\n emitNamedEntityData(result, valueLength, consumed) {\n const { decodeTree } = this;\n this.emitCodePoint(valueLength === 1 ? decodeTree[result] & ~BinTrieFlags.VALUE_LENGTH : decodeTree[result + 1], consumed);\n if (valueLength === 3) {\n this.emitCodePoint(decodeTree[result + 2], consumed);\n }\n return consumed;\n }\n /**\n * Signal to the parser that the end of the input was reached.\n *\n * Remaining data will be emitted and relevant errors will be produced.\n *\n * @returns The number of characters consumed.\n */\n end() {\n var _a3;\n switch (this.state) {\n case EntityDecoderState.NamedEntity: {\n return this.result !== 0 && (this.decodeMode !== DecodingMode.Attribute || this.result === this.treeIndex) ? this.emitNotTerminatedNamedEntity() : 0;\n }\n // Otherwise, emit a numeric entity if we have one.\n case EntityDecoderState.NumericDecimal: {\n return this.emitNumericEntity(0, 2);\n }\n case EntityDecoderState.NumericHex: {\n return this.emitNumericEntity(0, 3);\n }\n case EntityDecoderState.NumericStart: {\n (_a3 = this.errors) === null || _a3 === void 0 ? void 0 : _a3.absenceOfDigitsInNumericCharacterReference(this.consumed);\n return 0;\n }\n case EntityDecoderState.EntityStart: {\n return 0;\n }\n }\n }\n};\nfunction getDecoder(decodeTree) {\n let ret = \"\";\n const decoder = new EntityDecoder(decodeTree, (str) => ret += fromCodePoint(str));\n return function decodeWithTrie(str, decodeMode) {\n let lastIndex = 0;\n let offset = 0;\n while ((offset = str.indexOf(\"&\", offset)) >= 0) {\n ret += str.slice(lastIndex, offset);\n decoder.startEntity(decodeMode);\n const len = decoder.write(\n str,\n // Skip the \"&\"\n offset + 1\n );\n if (len < 0) {\n lastIndex = offset + decoder.end();\n break;\n }\n lastIndex = offset + len;\n offset = len === 0 ? lastIndex + 1 : lastIndex;\n }\n const result = ret + str.slice(lastIndex);\n ret = \"\";\n return result;\n };\n}\nfunction determineBranch(decodeTree, current, nodeIdx, char) {\n const branchCount = (current & BinTrieFlags.BRANCH_LENGTH) >> 7;\n const jumpOffset = current & BinTrieFlags.JUMP_TABLE;\n if (branchCount === 0) {\n return jumpOffset !== 0 && char === jumpOffset ? nodeIdx : -1;\n }\n if (jumpOffset) {\n const value = char - jumpOffset;\n return value < 0 || value >= branchCount ? -1 : decodeTree[nodeIdx + value] - 1;\n }\n let lo = nodeIdx;\n let hi = lo + branchCount - 1;\n while (lo <= hi) {\n const mid = lo + hi >>> 1;\n const midVal = decodeTree[mid];\n if (midVal < char) {\n lo = mid + 1;\n } else if (midVal > char) {\n hi = mid - 1;\n } else {\n return decodeTree[mid + branchCount];\n }\n }\n return -1;\n}\nvar htmlDecoder = getDecoder(decode_data_html_default);\nvar xmlDecoder = getDecoder(decode_data_xml_default);\nfunction decodeHTML(str, mode = DecodingMode.Legacy) {\n return htmlDecoder(str, mode);\n}\n\n// node_modules/.pnpm/entities@4.5.0/node_modules/entities/lib/esm/generated/encode-html.js\nfunction restoreDiff(arr) {\n for (let i = 1; i < arr.length; i++) {\n arr[i][0] += arr[i - 1][0] + 1;\n }\n return arr;\n}\nvar encode_html_default = new Map(/* @__PURE__ */ restoreDiff([[9, \" \"], [0, \" \"], [22, \"!\"], [0, \""\"], [0, \"#\"], [0, \"$\"], [0, \"%\"], [0, \"&\"], [0, \"'\"], [0, \"(\"], [0, \")\"], [0, \"*\"], [0, \"+\"], [0, \",\"], [1, \".\"], [0, \"/\"], [10, \":\"], [0, \";\"], [0, { v: \"<\", n: 8402, o: \"<⃒\" }], [0, { v: \"=\", n: 8421, o: \"=⃥\" }], [0, { v: \">\", n: 8402, o: \">⃒\" }], [0, \"?\"], [0, \"@\"], [26, \"[\"], [0, \"\\"], [0, \"]\"], [0, \"^\"], [0, \"_\"], [0, \"`\"], [5, { n: 106, o: \"fj\" }], [20, \"{\"], [0, \"|\"], [0, \"}\"], [34, \" \"], [0, \"¡\"], [0, \"¢\"], [0, \"£\"], [0, \"¤\"], [0, \"¥\"], [0, \"¦\"], [0, \"§\"], [0, \"¨\"], [0, \"©\"], [0, \"ª\"], [0, \"«\"], [0, \"¬\"], [0, \"­\"], [0, \"®\"], [0, \"¯\"], [0, \"°\"], [0, \"±\"], [0, \"²\"], [0, \"³\"], [0, \"´\"], [0, \"µ\"], [0, \"¶\"], [0, \"·\"], [0, \"¸\"], [0, \"¹\"], [0, \"º\"], [0, \"»\"], [0, \"¼\"], [0, \"½\"], [0, \"¾\"], [0, \"¿\"], [0, \"À\"], [0, \"Á\"], [0, \"Â\"], [0, \"Ã\"], [0, \"Ä\"], [0, \"Å\"], [0, \"Æ\"], [0, \"Ç\"], [0, \"È\"], [0, \"É\"], [0, \"Ê\"], [0, \"Ë\"], [0, \"Ì\"], [0, \"Í\"], [0, \"Î\"], [0, \"Ï\"], [0, \"Ð\"], [0, \"Ñ\"], [0, \"Ò\"], [0, \"Ó\"], [0, \"Ô\"], [0, \"Õ\"], [0, \"Ö\"], [0, \"×\"], [0, \"Ø\"], [0, \"Ù\"], [0, \"Ú\"], [0, \"Û\"], [0, \"Ü\"], [0, \"Ý\"], [0, \"Þ\"], [0, \"ß\"], [0, \"à\"], [0, \"á\"], [0, \"â\"], [0, \"ã\"], [0, \"ä\"], [0, \"å\"], [0, \"æ\"], [0, \"ç\"], [0, \"è\"], [0, \"é\"], [0, \"ê\"], [0, \"ë\"], [0, \"ì\"], [0, \"í\"], [0, \"î\"], [0, \"ï\"], [0, \"ð\"], [0, \"ñ\"], [0, \"ò\"], [0, \"ó\"], [0, \"ô\"], [0, \"õ\"], [0, \"ö\"], [0, \"÷\"], [0, \"ø\"], [0, \"ù\"], [0, \"ú\"], [0, \"û\"], [0, \"ü\"], [0, \"ý\"], [0, \"þ\"], [0, \"ÿ\"], [0, \"Ā\"], [0, \"ā\"], [0, \"Ă\"], [0, \"ă\"], [0, \"Ą\"], [0, \"ą\"], [0, \"Ć\"], [0, \"ć\"], [0, \"Ĉ\"], [0, \"ĉ\"], [0, \"Ċ\"], [0, \"ċ\"], [0, \"Č\"], [0, \"č\"], [0, \"Ď\"], [0, \"ď\"], [0, \"Đ\"], [0, \"đ\"], [0, \"Ē\"], [0, \"ē\"], [2, \"Ė\"], [0, \"ė\"], [0, \"Ę\"], [0, \"ę\"], [0, \"Ě\"], [0, \"ě\"], [0, \"Ĝ\"], [0, \"ĝ\"], [0, \"Ğ\"], [0, \"ğ\"], [0, \"Ġ\"], [0, \"ġ\"], [0, \"Ģ\"], [1, \"Ĥ\"], [0, \"ĥ\"], [0, \"Ħ\"], [0, \"ħ\"], [0, \"Ĩ\"], [0, \"ĩ\"], [0, \"Ī\"], [0, \"ī\"], [2, \"Į\"], [0, \"į\"], [0, \"İ\"], [0, \"ı\"], [0, \"IJ\"], [0, \"ij\"], [0, \"Ĵ\"], [0, \"ĵ\"], [0, \"Ķ\"], [0, \"ķ\"], [0, \"ĸ\"], [0, \"Ĺ\"], [0, \"ĺ\"], [0, \"Ļ\"], [0, \"ļ\"], [0, \"Ľ\"], [0, \"ľ\"], [0, \"Ŀ\"], [0, \"ŀ\"], [0, \"Ł\"], [0, \"ł\"], [0, \"Ń\"], [0, \"ń\"], [0, \"Ņ\"], [0, \"ņ\"], [0, \"Ň\"], [0, \"ň\"], [0, \"ʼn\"], [0, \"Ŋ\"], [0, \"ŋ\"], [0, \"Ō\"], [0, \"ō\"], [2, \"Ő\"], [0, \"ő\"], [0, \"Œ\"], [0, \"œ\"], [0, \"Ŕ\"], [0, \"ŕ\"], [0, \"Ŗ\"], [0, \"ŗ\"], [0, \"Ř\"], [0, \"ř\"], [0, \"Ś\"], [0, \"ś\"], [0, \"Ŝ\"], [0, \"ŝ\"], [0, \"Ş\"], [0, \"ş\"], [0, \"Š\"], [0, \"š\"], [0, \"Ţ\"], [0, \"ţ\"], [0, \"Ť\"], [0, \"ť\"], [0, \"Ŧ\"], [0, \"ŧ\"], [0, \"Ũ\"], [0, \"ũ\"], [0, \"Ū\"], [0, \"ū\"], [0, \"Ŭ\"], [0, \"ŭ\"], [0, \"Ů\"], [0, \"ů\"], [0, \"Ű\"], [0, \"ű\"], [0, \"Ų\"], [0, \"ų\"], [0, \"Ŵ\"], [0, \"ŵ\"], [0, \"Ŷ\"], [0, \"ŷ\"], [0, \"Ÿ\"], [0, \"Ź\"], [0, \"ź\"], [0, \"Ż\"], [0, \"ż\"], [0, \"Ž\"], [0, \"ž\"], [19, \"ƒ\"], [34, \"Ƶ\"], [63, \"ǵ\"], [65, \"ȷ\"], [142, \"ˆ\"], [0, \"ˇ\"], [16, \"˘\"], [0, \"˙\"], [0, \"˚\"], [0, \"˛\"], [0, \"˜\"], [0, \"˝\"], [51, \"̑\"], [127, \"Α\"], [0, \"Β\"], [0, \"Γ\"], [0, \"Δ\"], [0, \"Ε\"], [0, \"Ζ\"], [0, \"Η\"], [0, \"Θ\"], [0, \"Ι\"], [0, \"Κ\"], [0, \"Λ\"], [0, \"Μ\"], [0, \"Ν\"], [0, \"Ξ\"], [0, \"Ο\"], [0, \"Π\"], [0, \"Ρ\"], [1, \"Σ\"], [0, \"Τ\"], [0, \"Υ\"], [0, \"Φ\"], [0, \"Χ\"], [0, \"Ψ\"], [0, \"Ω\"], [7, \"α\"], [0, \"β\"], [0, \"γ\"], [0, \"δ\"], [0, \"ε\"], [0, \"ζ\"], [0, \"η\"], [0, \"θ\"], [0, \"ι\"], [0, \"κ\"], [0, \"λ\"], [0, \"μ\"], [0, \"ν\"], [0, \"ξ\"], [0, \"ο\"], [0, \"π\"], [0, \"ρ\"], [0, \"ς\"], [0, \"σ\"], [0, \"τ\"], [0, \"υ\"], [0, \"φ\"], [0, \"χ\"], [0, \"ψ\"], [0, \"ω\"], [7, \"ϑ\"], [0, \"ϒ\"], [2, \"ϕ\"], [0, \"ϖ\"], [5, \"Ϝ\"], [0, \"ϝ\"], [18, \"ϰ\"], [0, \"ϱ\"], [3, \"ϵ\"], [0, \"϶\"], [10, \"Ё\"], [0, \"Ђ\"], [0, \"Ѓ\"], [0, \"Є\"], [0, \"Ѕ\"], [0, \"І\"], [0, \"Ї\"], [0, \"Ј\"], [0, \"Љ\"], [0, \"Њ\"], [0, \"Ћ\"], [0, \"Ќ\"], [1, \"Ў\"], [0, \"Џ\"], [0, \"А\"], [0, \"Б\"], [0, \"В\"], [0, \"Г\"], [0, \"Д\"], [0, \"Е\"], [0, \"Ж\"], [0, \"З\"], [0, \"И\"], [0, \"Й\"], [0, \"К\"], [0, \"Л\"], [0, \"М\"], [0, \"Н\"], [0, \"О\"], [0, \"П\"], [0, \"Р\"], [0, \"С\"], [0, \"Т\"], [0, \"У\"], [0, \"Ф\"], [0, \"Х\"], [0, \"Ц\"], [0, \"Ч\"], [0, \"Ш\"], [0, \"Щ\"], [0, \"Ъ\"], [0, \"Ы\"], [0, \"Ь\"], [0, \"Э\"], [0, \"Ю\"], [0, \"Я\"], [0, \"а\"], [0, \"б\"], [0, \"в\"], [0, \"г\"], [0, \"д\"], [0, \"е\"], [0, \"ж\"], [0, \"з\"], [0, \"и\"], [0, \"й\"], [0, \"к\"], [0, \"л\"], [0, \"м\"], [0, \"н\"], [0, \"о\"], [0, \"п\"], [0, \"р\"], [0, \"с\"], [0, \"т\"], [0, \"у\"], [0, \"ф\"], [0, \"х\"], [0, \"ц\"], [0, \"ч\"], [0, \"ш\"], [0, \"щ\"], [0, \"ъ\"], [0, \"ы\"], [0, \"ь\"], [0, \"э\"], [0, \"ю\"], [0, \"я\"], [1, \"ё\"], [0, \"ђ\"], [0, \"ѓ\"], [0, \"є\"], [0, \"ѕ\"], [0, \"і\"], [0, \"ї\"], [0, \"ј\"], [0, \"љ\"], [0, \"њ\"], [0, \"ћ\"], [0, \"ќ\"], [1, \"ў\"], [0, \"џ\"], [7074, \" \"], [0, \" \"], [0, \" \"], [0, \" \"], [1, \" \"], [0, \" \"], [0, \" \"], [0, \" \"], [0, \"​\"], [0, \"‌\"], [0, \"‍\"], [0, \"‎\"], [0, \"‏\"], [0, \"‐\"], [2, \"–\"], [0, \"—\"], [0, \"―\"], [0, \"‖\"], [1, \"‘\"], [0, \"’\"], [0, \"‚\"], [1, \"“\"], [0, \"”\"], [0, \"„\"], [1, \"†\"], [0, \"‡\"], [0, \"•\"], [2, \"‥\"], [0, \"…\"], [9, \"‰\"], [0, \"‱\"], [0, \"′\"], [0, \"″\"], [0, \"‴\"], [0, \"‵\"], [3, \"‹\"], [0, \"›\"], [3, \"‾\"], [2, \"⁁\"], [1, \"⁃\"], [0, \"⁄\"], [10, \"⁏\"], [7, \"⁗\"], [7, { v: \" \", n: 8202, o: \"  \" }], [0, \"⁠\"], [0, \"⁡\"], [0, \"⁢\"], [0, \"⁣\"], [72, \"€\"], [46, \"⃛\"], [0, \"⃜\"], [37, \"ℂ\"], [2, \"℅\"], [4, \"ℊ\"], [0, \"ℋ\"], [0, \"ℌ\"], [0, \"ℍ\"], [0, \"ℎ\"], [0, \"ℏ\"], [0, \"ℐ\"], [0, \"ℑ\"], [0, \"ℒ\"], [0, \"ℓ\"], [1, \"ℕ\"], [0, \"№\"], [0, \"℗\"], [0, \"℘\"], [0, \"ℙ\"], [0, \"ℚ\"], [0, \"ℛ\"], [0, \"ℜ\"], [0, \"ℝ\"], [0, \"℞\"], [3, \"™\"], [1, \"ℤ\"], [2, \"℧\"], [0, \"ℨ\"], [0, \"℩\"], [2, \"ℬ\"], [0, \"ℭ\"], [1, \"ℯ\"], [0, \"ℰ\"], [0, \"ℱ\"], [1, \"ℳ\"], [0, \"ℴ\"], [0, \"ℵ\"], [0, \"ℶ\"], [0, \"ℷ\"], [0, \"ℸ\"], [12, \"ⅅ\"], [0, \"ⅆ\"], [0, \"ⅇ\"], [0, \"ⅈ\"], [10, \"⅓\"], [0, \"⅔\"], [0, \"⅕\"], [0, \"⅖\"], [0, \"⅗\"], [0, \"⅘\"], [0, \"⅙\"], [0, \"⅚\"], [0, \"⅛\"], [0, \"⅜\"], [0, \"⅝\"], [0, \"⅞\"], [49, \"←\"], [0, \"↑\"], [0, \"→\"], [0, \"↓\"], [0, \"↔\"], [0, \"↕\"], [0, \"↖\"], [0, \"↗\"], [0, \"↘\"], [0, \"↙\"], [0, \"↚\"], [0, \"↛\"], [1, { v: \"↝\", n: 824, o: \"↝̸\" }], [0, \"↞\"], [0, \"↟\"], [0, \"↠\"], [0, \"↡\"], [0, \"↢\"], [0, \"↣\"], [0, \"↤\"], [0, \"↥\"], [0, \"↦\"], [0, \"↧\"], [1, \"↩\"], [0, \"↪\"], [0, \"↫\"], [0, \"↬\"], [0, \"↭\"], [0, \"↮\"], [1, \"↰\"], [0, \"↱\"], [0, \"↲\"], [0, \"↳\"], [1, \"↵\"], [0, \"↶\"], [0, \"↷\"], [2, \"↺\"], [0, \"↻\"], [0, \"↼\"], [0, \"↽\"], [0, \"↾\"], [0, \"↿\"], [0, \"⇀\"], [0, \"⇁\"], [0, \"⇂\"], [0, \"⇃\"], [0, \"⇄\"], [0, \"⇅\"], [0, \"⇆\"], [0, \"⇇\"], [0, \"⇈\"], [0, \"⇉\"], [0, \"⇊\"], [0, \"⇋\"], [0, \"⇌\"], [0, \"⇍\"], [0, \"⇎\"], [0, \"⇏\"], [0, \"⇐\"], [0, \"⇑\"], [0, \"⇒\"], [0, \"⇓\"], [0, \"⇔\"], [0, \"⇕\"], [0, \"⇖\"], [0, \"⇗\"], [0, \"⇘\"], [0, \"⇙\"], [0, \"⇚\"], [0, \"⇛\"], [1, \"⇝\"], [6, \"⇤\"], [0, \"⇥\"], [15, \"⇵\"], [7, \"⇽\"], [0, \"⇾\"], [0, \"⇿\"], [0, \"∀\"], [0, \"∁\"], [0, { v: \"∂\", n: 824, o: \"∂̸\" }], [0, \"∃\"], [0, \"∄\"], [0, \"∅\"], [1, \"∇\"], [0, \"∈\"], [0, \"∉\"], [1, \"∋\"], [0, \"∌\"], [2, \"∏\"], [0, \"∐\"], [0, \"∑\"], [0, \"−\"], [0, \"∓\"], [0, \"∔\"], [1, \"∖\"], [0, \"∗\"], [0, \"∘\"], [1, \"√\"], [2, \"∝\"], [0, \"∞\"], [0, \"∟\"], [0, { v: \"∠\", n: 8402, o: \"∠⃒\" }], [0, \"∡\"], [0, \"∢\"], [0, \"∣\"], [0, \"∤\"], [0, \"∥\"], [0, \"∦\"], [0, \"∧\"], [0, \"∨\"], [0, { v: \"∩\", n: 65024, o: \"∩︀\" }], [0, { v: \"∪\", n: 65024, o: \"∪︀\" }], [0, \"∫\"], [0, \"∬\"], [0, \"∭\"], [0, \"∮\"], [0, \"∯\"], [0, \"∰\"], [0, \"∱\"], [0, \"∲\"], [0, \"∳\"], [0, \"∴\"], [0, \"∵\"], [0, \"∶\"], [0, \"∷\"], [0, \"∸\"], [1, \"∺\"], [0, \"∻\"], [0, { v: \"∼\", n: 8402, o: \"∼⃒\" }], [0, { v: \"∽\", n: 817, o: \"∽̱\" }], [0, { v: \"∾\", n: 819, o: \"∾̳\" }], [0, \"∿\"], [0, \"≀\"], [0, \"≁\"], [0, { v: \"≂\", n: 824, o: \"≂̸\" }], [0, \"≃\"], [0, \"≄\"], [0, \"≅\"], [0, \"≆\"], [0, \"≇\"], [0, \"≈\"], [0, \"≉\"], [0, \"≊\"], [0, { v: \"≋\", n: 824, o: \"≋̸\" }], [0, \"≌\"], [0, { v: \"≍\", n: 8402, o: \"≍⃒\" }], [0, { v: \"≎\", n: 824, o: \"≎̸\" }], [0, { v: \"≏\", n: 824, o: \"≏̸\" }], [0, { v: \"≐\", n: 824, o: \"≐̸\" }], [0, \"≑\"], [0, \"≒\"], [0, \"≓\"], [0, \"≔\"], [0, \"≕\"], [0, \"≖\"], [0, \"≗\"], [1, \"≙\"], [0, \"≚\"], [1, \"≜\"], [2, \"≟\"], [0, \"≠\"], [0, { v: \"≡\", n: 8421, o: \"≡⃥\" }], [0, \"≢\"], [1, { v: \"≤\", n: 8402, o: \"≤⃒\" }], [0, { v: \"≥\", n: 8402, o: \"≥⃒\" }], [0, { v: \"≦\", n: 824, o: \"≦̸\" }], [0, { v: \"≧\", n: 824, o: \"≧̸\" }], [0, { v: \"≨\", n: 65024, o: \"≨︀\" }], [0, { v: \"≩\", n: 65024, o: \"≩︀\" }], [0, { v: \"≪\", n: new Map(/* @__PURE__ */ restoreDiff([[824, \"≪̸\"], [7577, \"≪⃒\"]])) }], [0, { v: \"≫\", n: new Map(/* @__PURE__ */ restoreDiff([[824, \"≫̸\"], [7577, \"≫⃒\"]])) }], [0, \"≬\"], [0, \"≭\"], [0, \"≮\"], [0, \"≯\"], [0, \"≰\"], [0, \"≱\"], [0, \"≲\"], [0, \"≳\"], [0, \"≴\"], [0, \"≵\"], [0, \"≶\"], [0, \"≷\"], [0, \"≸\"], [0, \"≹\"], [0, \"≺\"], [0, \"≻\"], [0, \"≼\"], [0, \"≽\"], [0, \"≾\"], [0, { v: \"≿\", n: 824, o: \"≿̸\" }], [0, \"⊀\"], [0, \"⊁\"], [0, { v: \"⊂\", n: 8402, o: \"⊂⃒\" }], [0, { v: \"⊃\", n: 8402, o: \"⊃⃒\" }], [0, \"⊄\"], [0, \"⊅\"], [0, \"⊆\"], [0, \"⊇\"], [0, \"⊈\"], [0, \"⊉\"], [0, { v: \"⊊\", n: 65024, o: \"⊊︀\" }], [0, { v: \"⊋\", n: 65024, o: \"⊋︀\" }], [1, \"⊍\"], [0, \"⊎\"], [0, { v: \"⊏\", n: 824, o: \"⊏̸\" }], [0, { v: \"⊐\", n: 824, o: \"⊐̸\" }], [0, \"⊑\"], [0, \"⊒\"], [0, { v: \"⊓\", n: 65024, o: \"⊓︀\" }], [0, { v: \"⊔\", n: 65024, o: \"⊔︀\" }], [0, \"⊕\"], [0, \"⊖\"], [0, \"⊗\"], [0, \"⊘\"], [0, \"⊙\"], [0, \"⊚\"], [0, \"⊛\"], [1, \"⊝\"], [0, \"⊞\"], [0, \"⊟\"], [0, \"⊠\"], [0, \"⊡\"], [0, \"⊢\"], [0, \"⊣\"], [0, \"⊤\"], [0, \"⊥\"], [1, \"⊧\"], [0, \"⊨\"], [0, \"⊩\"], [0, \"⊪\"], [0, \"⊫\"], [0, \"⊬\"], [0, \"⊭\"], [0, \"⊮\"], [0, \"⊯\"], [0, \"⊰\"], [1, \"⊲\"], [0, \"⊳\"], [0, { v: \"⊴\", n: 8402, o: \"⊴⃒\" }], [0, { v: \"⊵\", n: 8402, o: \"⊵⃒\" }], [0, \"⊶\"], [0, \"⊷\"], [0, \"⊸\"], [0, \"⊹\"], [0, \"⊺\"], [0, \"⊻\"], [1, \"⊽\"], [0, \"⊾\"], [0, \"⊿\"], [0, \"⋀\"], [0, \"⋁\"], [0, \"⋂\"], [0, \"⋃\"], [0, \"⋄\"], [0, \"⋅\"], [0, \"⋆\"], [0, \"⋇\"], [0, \"⋈\"], [0, \"⋉\"], [0, \"⋊\"], [0, \"⋋\"], [0, \"⋌\"], [0, \"⋍\"], [0, \"⋎\"], [0, \"⋏\"], [0, \"⋐\"], [0, \"⋑\"], [0, \"⋒\"], [0, \"⋓\"], [0, \"⋔\"], [0, \"⋕\"], [0, \"⋖\"], [0, \"⋗\"], [0, { v: \"⋘\", n: 824, o: \"⋘̸\" }], [0, { v: \"⋙\", n: 824, o: \"⋙̸\" }], [0, { v: \"⋚\", n: 65024, o: \"⋚︀\" }], [0, { v: \"⋛\", n: 65024, o: \"⋛︀\" }], [2, \"⋞\"], [0, \"⋟\"], [0, \"⋠\"], [0, \"⋡\"], [0, \"⋢\"], [0, \"⋣\"], [2, \"⋦\"], [0, \"⋧\"], [0, \"⋨\"], [0, \"⋩\"], [0, \"⋪\"], [0, \"⋫\"], [0, \"⋬\"], [0, \"⋭\"], [0, \"⋮\"], [0, \"⋯\"], [0, \"⋰\"], [0, \"⋱\"], [0, \"⋲\"], [0, \"⋳\"], [0, \"⋴\"], [0, { v: \"⋵\", n: 824, o: \"⋵̸\" }], [0, \"⋶\"], [0, \"⋷\"], [1, { v: \"⋹\", n: 824, o: \"⋹̸\" }], [0, \"⋺\"], [0, \"⋻\"], [0, \"⋼\"], [0, \"⋽\"], [0, \"⋾\"], [6, \"⌅\"], [0, \"⌆\"], [1, \"⌈\"], [0, \"⌉\"], [0, \"⌊\"], [0, \"⌋\"], [0, \"⌌\"], [0, \"⌍\"], [0, \"⌎\"], [0, \"⌏\"], [0, \"⌐\"], [1, \"⌒\"], [0, \"⌓\"], [1, \"⌕\"], [0, \"⌖\"], [5, \"⌜\"], [0, \"⌝\"], [0, \"⌞\"], [0, \"⌟\"], [2, \"⌢\"], [0, \"⌣\"], [9, \"⌭\"], [0, \"⌮\"], [7, \"⌶\"], [6, \"⌽\"], [1, \"⌿\"], [60, \"⍼\"], [51, \"⎰\"], [0, \"⎱\"], [2, \"⎴\"], [0, \"⎵\"], [0, \"⎶\"], [37, \"⏜\"], [0, \"⏝\"], [0, \"⏞\"], [0, \"⏟\"], [2, \"⏢\"], [4, \"⏧\"], [59, \"␣\"], [164, \"Ⓢ\"], [55, \"─\"], [1, \"│\"], [9, \"┌\"], [3, \"┐\"], [3, \"└\"], [3, \"┘\"], [3, \"├\"], [7, \"┤\"], [7, \"┬\"], [7, \"┴\"], [7, \"┼\"], [19, \"═\"], [0, \"║\"], [0, \"╒\"], [0, \"╓\"], [0, \"╔\"], [0, \"╕\"], [0, \"╖\"], [0, \"╗\"], [0, \"╘\"], [0, \"╙\"], [0, \"╚\"], [0, \"╛\"], [0, \"╜\"], [0, \"╝\"], [0, \"╞\"], [0, \"╟\"], [0, \"╠\"], [0, \"╡\"], [0, \"╢\"], [0, \"╣\"], [0, \"╤\"], [0, \"╥\"], [0, \"╦\"], [0, \"╧\"], [0, \"╨\"], [0, \"╩\"], [0, \"╪\"], [0, \"╫\"], [0, \"╬\"], [19, \"▀\"], [3, \"▄\"], [3, \"█\"], [8, \"░\"], [0, \"▒\"], [0, \"▓\"], [13, \"□\"], [8, \"▪\"], [0, \"▫\"], [1, \"▭\"], [0, \"▮\"], [2, \"▱\"], [1, \"△\"], [0, \"▴\"], [0, \"▵\"], [2, \"▸\"], [0, \"▹\"], [3, \"▽\"], [0, \"▾\"], [0, \"▿\"], [2, \"◂\"], [0, \"◃\"], [6, \"◊\"], [0, \"○\"], [32, \"◬\"], [2, \"◯\"], [8, \"◸\"], [0, \"◹\"], [0, \"◺\"], [0, \"◻\"], [0, \"◼\"], [8, \"★\"], [0, \"☆\"], [7, \"☎\"], [49, \"♀\"], [1, \"♂\"], [29, \"♠\"], [2, \"♣\"], [1, \"♥\"], [0, \"♦\"], [3, \"♪\"], [2, \"♭\"], [0, \"♮\"], [0, \"♯\"], [163, \"✓\"], [3, \"✗\"], [8, \"✠\"], [21, \"✶\"], [33, \"❘\"], [25, \"❲\"], [0, \"❳\"], [84, \"⟈\"], [0, \"⟉\"], [28, \"⟦\"], [0, \"⟧\"], [0, \"⟨\"], [0, \"⟩\"], [0, \"⟪\"], [0, \"⟫\"], [0, \"⟬\"], [0, \"⟭\"], [7, \"⟵\"], [0, \"⟶\"], [0, \"⟷\"], [0, \"⟸\"], [0, \"⟹\"], [0, \"⟺\"], [1, \"⟼\"], [2, \"⟿\"], [258, \"⤂\"], [0, \"⤃\"], [0, \"⤄\"], [0, \"⤅\"], [6, \"⤌\"], [0, \"⤍\"], [0, \"⤎\"], [0, \"⤏\"], [0, \"⤐\"], [0, \"⤑\"], [0, \"⤒\"], [0, \"⤓\"], [2, \"⤖\"], [2, \"⤙\"], [0, \"⤚\"], [0, \"⤛\"], [0, \"⤜\"], [0, \"⤝\"], [0, \"⤞\"], [0, \"⤟\"], [0, \"⤠\"], [2, \"⤣\"], [0, \"⤤\"], [0, \"⤥\"], [0, \"⤦\"], [0, \"⤧\"], [0, \"⤨\"], [0, \"⤩\"], [0, \"⤪\"], [8, { v: \"⤳\", n: 824, o: \"⤳̸\" }], [1, \"⤵\"], [0, \"⤶\"], [0, \"⤷\"], [0, \"⤸\"], [0, \"⤹\"], [2, \"⤼\"], [0, \"⤽\"], [7, \"⥅\"], [2, \"⥈\"], [0, \"⥉\"], [0, \"⥊\"], [0, \"⥋\"], [2, \"⥎\"], [0, \"⥏\"], [0, \"⥐\"], [0, \"⥑\"], [0, \"⥒\"], [0, \"⥓\"], [0, \"⥔\"], [0, \"⥕\"], [0, \"⥖\"], [0, \"⥗\"], [0, \"⥘\"], [0, \"⥙\"], [0, \"⥚\"], [0, \"⥛\"], [0, \"⥜\"], [0, \"⥝\"], [0, \"⥞\"], [0, \"⥟\"], [0, \"⥠\"], [0, \"⥡\"], [0, \"⥢\"], [0, \"⥣\"], [0, \"⥤\"], [0, \"⥥\"], [0, \"⥦\"], [0, \"⥧\"], [0, \"⥨\"], [0, \"⥩\"], [0, \"⥪\"], [0, \"⥫\"], [0, \"⥬\"], [0, \"⥭\"], [0, \"⥮\"], [0, \"⥯\"], [0, \"⥰\"], [0, \"⥱\"], [0, \"⥲\"], [0, \"⥳\"], [0, \"⥴\"], [0, \"⥵\"], [0, \"⥶\"], [1, \"⥸\"], [0, \"⥹\"], [1, \"⥻\"], [0, \"⥼\"], [0, \"⥽\"], [0, \"⥾\"], [0, \"⥿\"], [5, \"⦅\"], [0, \"⦆\"], [4, \"⦋\"], [0, \"⦌\"], [0, \"⦍\"], [0, \"⦎\"], [0, \"⦏\"], [0, \"⦐\"], [0, \"⦑\"], [0, \"⦒\"], [0, \"⦓\"], [0, \"⦔\"], [0, \"⦕\"], [0, \"⦖\"], [3, \"⦚\"], [1, \"⦜\"], [0, \"⦝\"], [6, \"⦤\"], [0, \"⦥\"], [0, \"⦦\"], [0, \"⦧\"], [0, \"⦨\"], [0, \"⦩\"], [0, \"⦪\"], [0, \"⦫\"], [0, \"⦬\"], [0, \"⦭\"], [0, \"⦮\"], [0, \"⦯\"], [0, \"⦰\"], [0, \"⦱\"], [0, \"⦲\"], [0, \"⦳\"], [0, \"⦴\"], [0, \"⦵\"], [0, \"⦶\"], [0, \"⦷\"], [1, \"⦹\"], [1, \"⦻\"], [0, \"⦼\"], [1, \"⦾\"], [0, \"⦿\"], [0, \"⧀\"], [0, \"⧁\"], [0, \"⧂\"], [0, \"⧃\"], [0, \"⧄\"], [0, \"⧅\"], [3, \"⧉\"], [3, \"⧍\"], [0, \"⧎\"], [0, { v: \"⧏\", n: 824, o: \"⧏̸\" }], [0, { v: \"⧐\", n: 824, o: \"⧐̸\" }], [11, \"⧜\"], [0, \"⧝\"], [0, \"⧞\"], [4, \"⧣\"], [0, \"⧤\"], [0, \"⧥\"], [5, \"⧫\"], [8, \"⧴\"], [1, \"⧶\"], [9, \"⨀\"], [0, \"⨁\"], [0, \"⨂\"], [1, \"⨄\"], [1, \"⨆\"], [5, \"⨌\"], [0, \"⨍\"], [2, \"⨐\"], [0, \"⨑\"], [0, \"⨒\"], [0, \"⨓\"], [0, \"⨔\"], [0, \"⨕\"], [0, \"⨖\"], [0, \"⨗\"], [10, \"⨢\"], [0, \"⨣\"], [0, \"⨤\"], [0, \"⨥\"], [0, \"⨦\"], [0, \"⨧\"], [1, \"⨩\"], [0, \"⨪\"], [2, \"⨭\"], [0, \"⨮\"], [0, \"⨯\"], [0, \"⨰\"], [0, \"⨱\"], [1, \"⨳\"], [0, \"⨴\"], [0, \"⨵\"], [0, \"⨶\"], [0, \"⨷\"], [0, \"⨸\"], [0, \"⨹\"], [0, \"⨺\"], [0, \"⨻\"], [0, \"⨼\"], [2, \"⨿\"], [0, \"⩀\"], [1, \"⩂\"], [0, \"⩃\"], [0, \"⩄\"], [0, \"⩅\"], [0, \"⩆\"], [0, \"⩇\"], [0, \"⩈\"], [0, \"⩉\"], [0, \"⩊\"], [0, \"⩋\"], [0, \"⩌\"], [0, \"⩍\"], [2, \"⩐\"], [2, \"⩓\"], [0, \"⩔\"], [0, \"⩕\"], [0, \"⩖\"], [0, \"⩗\"], [0, \"⩘\"], [1, \"⩚\"], [0, \"⩛\"], [0, \"⩜\"], [0, \"⩝\"], [1, \"⩟\"], [6, \"⩦\"], [3, \"⩪\"], [2, { v: \"⩭\", n: 824, o: \"⩭̸\" }], [0, \"⩮\"], [0, \"⩯\"], [0, { v: \"⩰\", n: 824, o: \"⩰̸\" }], [0, \"⩱\"], [0, \"⩲\"], [0, \"⩳\"], [0, \"⩴\"], [0, \"⩵\"], [1, \"⩷\"], [0, \"⩸\"], [0, \"⩹\"], [0, \"⩺\"], [0, \"⩻\"], [0, \"⩼\"], [0, { v: \"⩽\", n: 824, o: \"⩽̸\" }], [0, { v: \"⩾\", n: 824, o: \"⩾̸\" }], [0, \"⩿\"], [0, \"⪀\"], [0, \"⪁\"], [0, \"⪂\"], [0, \"⪃\"], [0, \"⪄\"], [0, \"⪅\"], [0, \"⪆\"], [0, \"⪇\"], [0, \"⪈\"], [0, \"⪉\"], [0, \"⪊\"], [0, \"⪋\"], [0, \"⪌\"], [0, \"⪍\"], [0, \"⪎\"], [0, \"⪏\"], [0, \"⪐\"], [0, \"⪑\"], [0, \"⪒\"], [0, \"⪓\"], [0, \"⪔\"], [0, \"⪕\"], [0, \"⪖\"], [0, \"⪗\"], [0, \"⪘\"], [0, \"⪙\"], [0, \"⪚\"], [2, \"⪝\"], [0, \"⪞\"], [0, \"⪟\"], [0, \"⪠\"], [0, { v: \"⪡\", n: 824, o: \"⪡̸\" }], [0, { v: \"⪢\", n: 824, o: \"⪢̸\" }], [1, \"⪤\"], [0, \"⪥\"], [0, \"⪦\"], [0, \"⪧\"], [0, \"⪨\"], [0, \"⪩\"], [0, \"⪪\"], [0, \"⪫\"], [0, { v: \"⪬\", n: 65024, o: \"⪬︀\" }], [0, { v: \"⪭\", n: 65024, o: \"⪭︀\" }], [0, \"⪮\"], [0, { v: \"⪯\", n: 824, o: \"⪯̸\" }], [0, { v: \"⪰\", n: 824, o: \"⪰̸\" }], [2, \"⪳\"], [0, \"⪴\"], [0, \"⪵\"], [0, \"⪶\"], [0, \"⪷\"], [0, \"⪸\"], [0, \"⪹\"], [0, \"⪺\"], [0, \"⪻\"], [0, \"⪼\"], [0, \"⪽\"], [0, \"⪾\"], [0, \"⪿\"], [0, \"⫀\"], [0, \"⫁\"], [0, \"⫂\"], [0, \"⫃\"], [0, \"⫄\"], [0, { v: \"⫅\", n: 824, o: \"⫅̸\" }], [0, { v: \"⫆\", n: 824, o: \"⫆̸\" }], [0, \"⫇\"], [0, \"⫈\"], [2, { v: \"⫋\", n: 65024, o: \"⫋︀\" }], [0, { v: \"⫌\", n: 65024, o: \"⫌︀\" }], [2, \"⫏\"], [0, \"⫐\"], [0, \"⫑\"], [0, \"⫒\"], [0, \"⫓\"], [0, \"⫔\"], [0, \"⫕\"], [0, \"⫖\"], [0, \"⫗\"], [0, \"⫘\"], [0, \"⫙\"], [0, \"⫚\"], [0, \"⫛\"], [8, \"⫤\"], [1, \"⫦\"], [0, \"⫧\"], [0, \"⫨\"], [0, \"⫩\"], [1, \"⫫\"], [0, \"⫬\"], [0, \"⫭\"], [0, \"⫮\"], [0, \"⫯\"], [0, \"⫰\"], [0, \"⫱\"], [0, \"⫲\"], [0, \"⫳\"], [9, { v: \"⫽\", n: 8421, o: \"⫽⃥\" }], [44343, { n: new Map(/* @__PURE__ */ restoreDiff([[56476, \"𝒜\"], [1, \"𝒞\"], [0, \"𝒟\"], [2, \"𝒢\"], [2, \"𝒥\"], [0, \"𝒦\"], [2, \"𝒩\"], [0, \"𝒪\"], [0, \"𝒫\"], [0, \"𝒬\"], [1, \"𝒮\"], [0, \"𝒯\"], [0, \"𝒰\"], [0, \"𝒱\"], [0, \"𝒲\"], [0, \"𝒳\"], [0, \"𝒴\"], [0, \"𝒵\"], [0, \"𝒶\"], [0, \"𝒷\"], [0, \"𝒸\"], [0, \"𝒹\"], [1, \"𝒻\"], [1, \"𝒽\"], [0, \"𝒾\"], [0, \"𝒿\"], [0, \"𝓀\"], [0, \"𝓁\"], [0, \"𝓂\"], [0, \"𝓃\"], [1, \"𝓅\"], [0, \"𝓆\"], [0, \"𝓇\"], [0, \"𝓈\"], [0, \"𝓉\"], [0, \"𝓊\"], [0, \"𝓋\"], [0, \"𝓌\"], [0, \"𝓍\"], [0, \"𝓎\"], [0, \"𝓏\"], [52, \"𝔄\"], [0, \"𝔅\"], [1, \"𝔇\"], [0, \"𝔈\"], [0, \"𝔉\"], [0, \"𝔊\"], [2, \"𝔍\"], [0, \"𝔎\"], [0, \"𝔏\"], [0, \"𝔐\"], [0, \"𝔑\"], [0, \"𝔒\"], [0, \"𝔓\"], [0, \"𝔔\"], [1, \"𝔖\"], [0, \"𝔗\"], [0, \"𝔘\"], [0, \"𝔙\"], [0, \"𝔚\"], [0, \"𝔛\"], [0, \"𝔜\"], [1, \"𝔞\"], [0, \"𝔟\"], [0, \"𝔠\"], [0, \"𝔡\"], [0, \"𝔢\"], [0, \"𝔣\"], [0, \"𝔤\"], [0, \"𝔥\"], [0, \"𝔦\"], [0, \"𝔧\"], [0, \"𝔨\"], [0, \"𝔩\"], [0, \"𝔪\"], [0, \"𝔫\"], [0, \"𝔬\"], [0, \"𝔭\"], [0, \"𝔮\"], [0, \"𝔯\"], [0, \"𝔰\"], [0, \"𝔱\"], [0, \"𝔲\"], [0, \"𝔳\"], [0, \"𝔴\"], [0, \"𝔵\"], [0, \"𝔶\"], [0, \"𝔷\"], [0, \"𝔸\"], [0, \"𝔹\"], [1, \"𝔻\"], [0, \"𝔼\"], [0, \"𝔽\"], [0, \"𝔾\"], [1, \"𝕀\"], [0, \"𝕁\"], [0, \"𝕂\"], [0, \"𝕃\"], [0, \"𝕄\"], [1, \"𝕆\"], [3, \"𝕊\"], [0, \"𝕋\"], [0, \"𝕌\"], [0, \"𝕍\"], [0, \"𝕎\"], [0, \"𝕏\"], [0, \"𝕐\"], [1, \"𝕒\"], [0, \"𝕓\"], [0, \"𝕔\"], [0, \"𝕕\"], [0, \"𝕖\"], [0, \"𝕗\"], [0, \"𝕘\"], [0, \"𝕙\"], [0, \"𝕚\"], [0, \"𝕛\"], [0, \"𝕜\"], [0, \"𝕝\"], [0, \"𝕞\"], [0, \"𝕟\"], [0, \"𝕠\"], [0, \"𝕡\"], [0, \"𝕢\"], [0, \"𝕣\"], [0, \"𝕤\"], [0, \"𝕥\"], [0, \"𝕦\"], [0, \"𝕧\"], [0, \"𝕨\"], [0, \"𝕩\"], [0, \"𝕪\"], [0, \"𝕫\"]])) }], [8906, \"ff\"], [0, \"fi\"], [0, \"fl\"], [0, \"ffi\"], [0, \"ffl\"]]));\n\n// node_modules/.pnpm/entities@4.5.0/node_modules/entities/lib/esm/escape.js\nvar xmlCodeMap = /* @__PURE__ */ new Map([\n [34, \""\"],\n [38, \"&\"],\n [39, \"'\"],\n [60, \"<\"],\n [62, \">\"]\n]);\nvar getCodePoint = (\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n String.prototype.codePointAt != null ? (str, index) => str.codePointAt(index) : (\n // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae\n (c, index) => (c.charCodeAt(index) & 64512) === 55296 ? (c.charCodeAt(index) - 55296) * 1024 + c.charCodeAt(index + 1) - 56320 + 65536 : c.charCodeAt(index)\n )\n);\nfunction getEscaper(regex, map2) {\n return function escape3(data) {\n let match2;\n let lastIdx = 0;\n let result = \"\";\n while (match2 = regex.exec(data)) {\n if (lastIdx !== match2.index) {\n result += data.substring(lastIdx, match2.index);\n }\n result += map2.get(match2[0].charCodeAt(0));\n lastIdx = match2.index + 1;\n }\n return result + data.substring(lastIdx);\n };\n}\nvar escapeUTF8 = getEscaper(/[&<>'\"]/g, xmlCodeMap);\nvar escapeAttribute = getEscaper(/[\"&\\u00A0]/g, /* @__PURE__ */ new Map([\n [34, \""\"],\n [38, \"&\"],\n [160, \" \"]\n]));\nvar escapeText = getEscaper(/[&<>\\u00A0]/g, /* @__PURE__ */ new Map([\n [38, \"&\"],\n [60, \"<\"],\n [62, \">\"],\n [160, \" \"]\n]));\n\n// node_modules/.pnpm/entities@4.5.0/node_modules/entities/lib/esm/index.js\nvar EntityLevel;\n(function(EntityLevel2) {\n EntityLevel2[EntityLevel2[\"XML\"] = 0] = \"XML\";\n EntityLevel2[EntityLevel2[\"HTML\"] = 1] = \"HTML\";\n})(EntityLevel || (EntityLevel = {}));\nvar EncodingMode;\n(function(EncodingMode2) {\n EncodingMode2[EncodingMode2[\"UTF8\"] = 0] = \"UTF8\";\n EncodingMode2[EncodingMode2[\"ASCII\"] = 1] = \"ASCII\";\n EncodingMode2[EncodingMode2[\"Extensive\"] = 2] = \"Extensive\";\n EncodingMode2[EncodingMode2[\"Attribute\"] = 3] = \"Attribute\";\n EncodingMode2[EncodingMode2[\"Text\"] = 4] = \"Text\";\n})(EncodingMode || (EncodingMode = {}));\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/common/utils.mjs\nfunction _class2(obj) {\n return Object.prototype.toString.call(obj);\n}\nfunction isString2(obj) {\n return _class2(obj) === \"[object String]\";\n}\nvar _hasOwnProperty = Object.prototype.hasOwnProperty;\nfunction has(object, key) {\n return _hasOwnProperty.call(object, key);\n}\nfunction assign2(obj) {\n const sources = Array.prototype.slice.call(arguments, 1);\n sources.forEach(function(source) {\n if (!source) {\n return;\n }\n if (typeof source !== \"object\") {\n throw new TypeError(source + \"must be object\");\n }\n Object.keys(source).forEach(function(key) {\n obj[key] = source[key];\n });\n });\n return obj;\n}\nfunction arrayReplaceAt(src, pos, newElements) {\n return [].concat(src.slice(0, pos), newElements, src.slice(pos + 1));\n}\nfunction isValidEntityCode(c) {\n if (c >= 55296 && c <= 57343) {\n return false;\n }\n if (c >= 64976 && c <= 65007) {\n return false;\n }\n if ((c & 65535) === 65535 || (c & 65535) === 65534) {\n return false;\n }\n if (c >= 0 && c <= 8) {\n return false;\n }\n if (c === 11) {\n return false;\n }\n if (c >= 14 && c <= 31) {\n return false;\n }\n if (c >= 127 && c <= 159) {\n return false;\n }\n if (c > 1114111) {\n return false;\n }\n return true;\n}\nfunction fromCodePoint2(c) {\n if (c > 65535) {\n c -= 65536;\n const surrogate1 = 55296 + (c >> 10);\n const surrogate2 = 56320 + (c & 1023);\n return String.fromCharCode(surrogate1, surrogate2);\n }\n return String.fromCharCode(c);\n}\nvar UNESCAPE_MD_RE = /\\\\([!\"#$%&'()*+,\\-./:;<=>?@[\\\\\\]^_`{|}~])/g;\nvar ENTITY_RE = /&([a-z#][a-z0-9]{1,31});/gi;\nvar UNESCAPE_ALL_RE = new RegExp(UNESCAPE_MD_RE.source + \"|\" + ENTITY_RE.source, \"gi\");\nvar DIGITAL_ENTITY_TEST_RE = /^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))$/i;\nfunction replaceEntityPattern(match2, name) {\n if (name.charCodeAt(0) === 35 && DIGITAL_ENTITY_TEST_RE.test(name)) {\n const code2 = name[1].toLowerCase() === \"x\" ? parseInt(name.slice(2), 16) : parseInt(name.slice(1), 10);\n if (isValidEntityCode(code2)) {\n return fromCodePoint2(code2);\n }\n return match2;\n }\n const decoded = decodeHTML(match2);\n if (decoded !== match2) {\n return decoded;\n }\n return match2;\n}\nfunction unescapeMd(str) {\n if (str.indexOf(\"\\\\\") < 0) {\n return str;\n }\n return str.replace(UNESCAPE_MD_RE, \"$1\");\n}\nfunction unescapeAll(str) {\n if (str.indexOf(\"\\\\\") < 0 && str.indexOf(\"&\") < 0) {\n return str;\n }\n return str.replace(UNESCAPE_ALL_RE, function(match2, escaped, entity2) {\n if (escaped) {\n return escaped;\n }\n return replaceEntityPattern(match2, entity2);\n });\n}\nvar HTML_ESCAPE_TEST_RE = /[&<>\"]/;\nvar HTML_ESCAPE_REPLACE_RE = /[&<>\"]/g;\nvar HTML_REPLACEMENTS = {\n \"&\": \"&\",\n \"<\": \"<\",\n \">\": \">\",\n '\"': \""\"\n};\nfunction replaceUnsafeChar(ch) {\n return HTML_REPLACEMENTS[ch];\n}\nfunction escapeHtml(str) {\n if (HTML_ESCAPE_TEST_RE.test(str)) {\n return str.replace(HTML_ESCAPE_REPLACE_RE, replaceUnsafeChar);\n }\n return str;\n}\nvar REGEXP_ESCAPE_RE = /[.?*+^$[\\]\\\\(){}|-]/g;\nfunction escapeRE2(str) {\n return str.replace(REGEXP_ESCAPE_RE, \"\\\\$&\");\n}\nfunction isSpace(code2) {\n switch (code2) {\n case 9:\n case 32:\n return true;\n }\n return false;\n}\nfunction isWhiteSpace(code2) {\n if (code2 >= 8192 && code2 <= 8202) {\n return true;\n }\n switch (code2) {\n case 9:\n // \\t\n case 10:\n // \\n\n case 11:\n // \\v\n case 12:\n // \\f\n case 13:\n // \\r\n case 32:\n case 160:\n case 5760:\n case 8239:\n case 8287:\n case 12288:\n return true;\n }\n return false;\n}\nfunction isPunctChar(ch) {\n return regex_default4.test(ch) || regex_default5.test(ch);\n}\nfunction isMdAsciiPunct(ch) {\n switch (ch) {\n case 33:\n case 34:\n case 35:\n case 36:\n case 37:\n case 38:\n case 39:\n case 40:\n case 41:\n case 42:\n case 43:\n case 44:\n case 45:\n case 46:\n case 47:\n case 58:\n case 59:\n case 60:\n case 61:\n case 62:\n case 63:\n case 64:\n case 91:\n case 92:\n case 93:\n case 94:\n case 95:\n case 96:\n case 123:\n case 124:\n case 125:\n case 126:\n return true;\n default:\n return false;\n }\n}\nfunction normalizeReference(str) {\n str = str.trim().replace(/\\s+/g, \" \");\n if (\"ẞ\".toLowerCase() === \"Ṿ\") {\n str = str.replace(/ẞ/g, \"ß\");\n }\n return str.toLowerCase().toUpperCase();\n}\nvar lib = { mdurl: mdurl_exports, ucmicro: uc_exports };\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/helpers/index.mjs\nvar helpers_exports = {};\n__export(helpers_exports, {\n parseLinkDestination: () => parseLinkDestination,\n parseLinkLabel: () => parseLinkLabel,\n parseLinkTitle: () => parseLinkTitle\n});\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/helpers/parse_link_label.mjs\nfunction parseLinkLabel(state, start, disableNested) {\n let level, found, marker, prevPos;\n const max2 = state.posMax;\n const oldPos = state.pos;\n state.pos = start + 1;\n level = 1;\n while (state.pos < max2) {\n marker = state.src.charCodeAt(state.pos);\n if (marker === 93) {\n level--;\n if (level === 0) {\n found = true;\n break;\n }\n }\n prevPos = state.pos;\n state.md.inline.skipToken(state);\n if (marker === 91) {\n if (prevPos === state.pos - 1) {\n level++;\n } else if (disableNested) {\n state.pos = oldPos;\n return -1;\n }\n }\n }\n let labelEnd = -1;\n if (found) {\n labelEnd = state.pos;\n }\n state.pos = oldPos;\n return labelEnd;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/helpers/parse_link_destination.mjs\nfunction parseLinkDestination(str, start, max2) {\n let code2;\n let pos = start;\n const result = {\n ok: false,\n pos: 0,\n str: \"\"\n };\n if (str.charCodeAt(pos) === 60) {\n pos++;\n while (pos < max2) {\n code2 = str.charCodeAt(pos);\n if (code2 === 10) {\n return result;\n }\n if (code2 === 60) {\n return result;\n }\n if (code2 === 62) {\n result.pos = pos + 1;\n result.str = unescapeAll(str.slice(start + 1, pos));\n result.ok = true;\n return result;\n }\n if (code2 === 92 && pos + 1 < max2) {\n pos += 2;\n continue;\n }\n pos++;\n }\n return result;\n }\n let level = 0;\n while (pos < max2) {\n code2 = str.charCodeAt(pos);\n if (code2 === 32) {\n break;\n }\n if (code2 < 32 || code2 === 127) {\n break;\n }\n if (code2 === 92 && pos + 1 < max2) {\n if (str.charCodeAt(pos + 1) === 32) {\n break;\n }\n pos += 2;\n continue;\n }\n if (code2 === 40) {\n level++;\n if (level > 32) {\n return result;\n }\n }\n if (code2 === 41) {\n if (level === 0) {\n break;\n }\n level--;\n }\n pos++;\n }\n if (start === pos) {\n return result;\n }\n if (level !== 0) {\n return result;\n }\n result.str = unescapeAll(str.slice(start, pos));\n result.pos = pos;\n result.ok = true;\n return result;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/helpers/parse_link_title.mjs\nfunction parseLinkTitle(str, start, max2, prev_state) {\n let code2;\n let pos = start;\n const state = {\n // if `true`, this is a valid link title\n ok: false,\n // if `true`, this link can be continued on the next line\n can_continue: false,\n // if `ok`, it's the position of the first character after the closing marker\n pos: 0,\n // if `ok`, it's the unescaped title\n str: \"\",\n // expected closing marker character code\n marker: 0\n };\n if (prev_state) {\n state.str = prev_state.str;\n state.marker = prev_state.marker;\n } else {\n if (pos >= max2) {\n return state;\n }\n let marker = str.charCodeAt(pos);\n if (marker !== 34 && marker !== 39 && marker !== 40) {\n return state;\n }\n start++;\n pos++;\n if (marker === 40) {\n marker = 41;\n }\n state.marker = marker;\n }\n while (pos < max2) {\n code2 = str.charCodeAt(pos);\n if (code2 === state.marker) {\n state.pos = pos + 1;\n state.str += unescapeAll(str.slice(start, pos));\n state.ok = true;\n return state;\n } else if (code2 === 40 && state.marker === 41) {\n return state;\n } else if (code2 === 92 && pos + 1 < max2) {\n pos++;\n }\n pos++;\n }\n state.can_continue = true;\n state.str += unescapeAll(str.slice(start, pos));\n return state;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/renderer.mjs\nvar default_rules = {};\ndefault_rules.code_inline = function(tokens, idx, options, env, slf) {\n const token = tokens[idx];\n return \"\" + escapeHtml(token.content) + \"\";\n};\ndefault_rules.code_block = function(tokens, idx, options, env, slf) {\n const token = tokens[idx];\n return \"\" + escapeHtml(tokens[idx].content) + \"\\n\";\n};\ndefault_rules.fence = function(tokens, idx, options, env, slf) {\n const token = tokens[idx];\n const info = token.info ? unescapeAll(token.info).trim() : \"\";\n let langName = \"\";\n let langAttrs = \"\";\n if (info) {\n const arr = info.split(/(\\s+)/g);\n langName = arr[0];\n langAttrs = arr.slice(2).join(\"\");\n }\n let highlighted;\n if (options.highlight) {\n highlighted = options.highlight(token.content, langName, langAttrs) || escapeHtml(token.content);\n } else {\n highlighted = escapeHtml(token.content);\n }\n if (highlighted.indexOf(\"${highlighted}\n`;\n }\n return `

${highlighted}
\n`;\n};\ndefault_rules.image = function(tokens, idx, options, env, slf) {\n const token = tokens[idx];\n token.attrs[token.attrIndex(\"alt\")][1] = slf.renderInlineAsText(token.children, options, env);\n return slf.renderToken(tokens, idx, options);\n};\ndefault_rules.hardbreak = function(tokens, idx, options) {\n return options.xhtmlOut ? \"
\\n\" : \"
\\n\";\n};\ndefault_rules.softbreak = function(tokens, idx, options) {\n return options.breaks ? options.xhtmlOut ? \"
\\n\" : \"
\\n\" : \"\\n\";\n};\ndefault_rules.text = function(tokens, idx) {\n return escapeHtml(tokens[idx].content);\n};\ndefault_rules.html_block = function(tokens, idx) {\n return tokens[idx].content;\n};\ndefault_rules.html_inline = function(tokens, idx) {\n return tokens[idx].content;\n};\nfunction Renderer() {\n this.rules = assign2({}, default_rules);\n}\nRenderer.prototype.renderAttrs = function renderAttrs(token) {\n let i, l, result;\n if (!token.attrs) {\n return \"\";\n }\n result = \"\";\n for (i = 0, l = token.attrs.length; i < l; i++) {\n result += \" \" + escapeHtml(token.attrs[i][0]) + '=\"' + escapeHtml(token.attrs[i][1]) + '\"';\n }\n return result;\n};\nRenderer.prototype.renderToken = function renderToken(tokens, idx, options) {\n const token = tokens[idx];\n let result = \"\";\n if (token.hidden) {\n return \"\";\n }\n if (token.block && token.nesting !== -1 && idx && tokens[idx - 1].hidden) {\n result += \"\\n\";\n }\n result += (token.nesting === -1 ? \"\\n\" : \">\";\n return result;\n};\nRenderer.prototype.renderInline = function(tokens, options, env) {\n let result = \"\";\n const rules = this.rules;\n for (let i = 0, len = tokens.length; i < len; i++) {\n const type = tokens[i].type;\n if (typeof rules[type] !== \"undefined\") {\n result += rules[type](tokens, i, options, env, this);\n } else {\n result += this.renderToken(tokens, i, options);\n }\n }\n return result;\n};\nRenderer.prototype.renderInlineAsText = function(tokens, options, env) {\n let result = \"\";\n for (let i = 0, len = tokens.length; i < len; i++) {\n switch (tokens[i].type) {\n case \"text\":\n result += tokens[i].content;\n break;\n case \"image\":\n result += this.renderInlineAsText(tokens[i].children, options, env);\n break;\n case \"html_inline\":\n case \"html_block\":\n result += tokens[i].content;\n break;\n case \"softbreak\":\n case \"hardbreak\":\n result += \"\\n\";\n break;\n default:\n }\n }\n return result;\n};\nRenderer.prototype.render = function(tokens, options, env) {\n let result = \"\";\n const rules = this.rules;\n for (let i = 0, len = tokens.length; i < len; i++) {\n const type = tokens[i].type;\n if (type === \"inline\") {\n result += this.renderInline(tokens[i].children, options, env);\n } else if (typeof rules[type] !== \"undefined\") {\n result += rules[type](tokens, i, options, env, this);\n } else {\n result += this.renderToken(tokens, i, options, env);\n }\n }\n return result;\n};\nvar renderer_default = Renderer;\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/ruler.mjs\nfunction Ruler() {\n this.__rules__ = [];\n this.__cache__ = null;\n}\nRuler.prototype.__find__ = function(name) {\n for (let i = 0; i < this.__rules__.length; i++) {\n if (this.__rules__[i].name === name) {\n return i;\n }\n }\n return -1;\n};\nRuler.prototype.__compile__ = function() {\n const self = this;\n const chains = [\"\"];\n self.__rules__.forEach(function(rule) {\n if (!rule.enabled) {\n return;\n }\n rule.alt.forEach(function(altName) {\n if (chains.indexOf(altName) < 0) {\n chains.push(altName);\n }\n });\n });\n self.__cache__ = {};\n chains.forEach(function(chain) {\n self.__cache__[chain] = [];\n self.__rules__.forEach(function(rule) {\n if (!rule.enabled) {\n return;\n }\n if (chain && rule.alt.indexOf(chain) < 0) {\n return;\n }\n self.__cache__[chain].push(rule.fn);\n });\n });\n};\nRuler.prototype.at = function(name, fn, options) {\n const index = this.__find__(name);\n const opt = options || {};\n if (index === -1) {\n throw new Error(\"Parser rule not found: \" + name);\n }\n this.__rules__[index].fn = fn;\n this.__rules__[index].alt = opt.alt || [];\n this.__cache__ = null;\n};\nRuler.prototype.before = function(beforeName, ruleName, fn, options) {\n const index = this.__find__(beforeName);\n const opt = options || {};\n if (index === -1) {\n throw new Error(\"Parser rule not found: \" + beforeName);\n }\n this.__rules__.splice(index, 0, {\n name: ruleName,\n enabled: true,\n fn,\n alt: opt.alt || []\n });\n this.__cache__ = null;\n};\nRuler.prototype.after = function(afterName, ruleName, fn, options) {\n const index = this.__find__(afterName);\n const opt = options || {};\n if (index === -1) {\n throw new Error(\"Parser rule not found: \" + afterName);\n }\n this.__rules__.splice(index + 1, 0, {\n name: ruleName,\n enabled: true,\n fn,\n alt: opt.alt || []\n });\n this.__cache__ = null;\n};\nRuler.prototype.push = function(ruleName, fn, options) {\n const opt = options || {};\n this.__rules__.push({\n name: ruleName,\n enabled: true,\n fn,\n alt: opt.alt || []\n });\n this.__cache__ = null;\n};\nRuler.prototype.enable = function(list2, ignoreInvalid) {\n if (!Array.isArray(list2)) {\n list2 = [list2];\n }\n const result = [];\n list2.forEach(function(name) {\n const idx = this.__find__(name);\n if (idx < 0) {\n if (ignoreInvalid) {\n return;\n }\n throw new Error(\"Rules manager: invalid rule name \" + name);\n }\n this.__rules__[idx].enabled = true;\n result.push(name);\n }, this);\n this.__cache__ = null;\n return result;\n};\nRuler.prototype.enableOnly = function(list2, ignoreInvalid) {\n if (!Array.isArray(list2)) {\n list2 = [list2];\n }\n this.__rules__.forEach(function(rule) {\n rule.enabled = false;\n });\n this.enable(list2, ignoreInvalid);\n};\nRuler.prototype.disable = function(list2, ignoreInvalid) {\n if (!Array.isArray(list2)) {\n list2 = [list2];\n }\n const result = [];\n list2.forEach(function(name) {\n const idx = this.__find__(name);\n if (idx < 0) {\n if (ignoreInvalid) {\n return;\n }\n throw new Error(\"Rules manager: invalid rule name \" + name);\n }\n this.__rules__[idx].enabled = false;\n result.push(name);\n }, this);\n this.__cache__ = null;\n return result;\n};\nRuler.prototype.getRules = function(chainName) {\n if (this.__cache__ === null) {\n this.__compile__();\n }\n return this.__cache__[chainName] || [];\n};\nvar ruler_default = Ruler;\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/token.mjs\nfunction Token(type, tag, nesting) {\n this.type = type;\n this.tag = tag;\n this.attrs = null;\n this.map = null;\n this.nesting = nesting;\n this.level = 0;\n this.children = null;\n this.content = \"\";\n this.markup = \"\";\n this.info = \"\";\n this.meta = null;\n this.block = false;\n this.hidden = false;\n}\nToken.prototype.attrIndex = function attrIndex(name) {\n if (!this.attrs) {\n return -1;\n }\n const attrs = this.attrs;\n for (let i = 0, len = attrs.length; i < len; i++) {\n if (attrs[i][0] === name) {\n return i;\n }\n }\n return -1;\n};\nToken.prototype.attrPush = function attrPush(attrData) {\n if (this.attrs) {\n this.attrs.push(attrData);\n } else {\n this.attrs = [attrData];\n }\n};\nToken.prototype.attrSet = function attrSet(name, value) {\n const idx = this.attrIndex(name);\n const attrData = [name, value];\n if (idx < 0) {\n this.attrPush(attrData);\n } else {\n this.attrs[idx] = attrData;\n }\n};\nToken.prototype.attrGet = function attrGet(name) {\n const idx = this.attrIndex(name);\n let value = null;\n if (idx >= 0) {\n value = this.attrs[idx][1];\n }\n return value;\n};\nToken.prototype.attrJoin = function attrJoin(name, value) {\n const idx = this.attrIndex(name);\n if (idx < 0) {\n this.attrPush([name, value]);\n } else {\n this.attrs[idx][1] = this.attrs[idx][1] + \" \" + value;\n }\n};\nvar token_default = Token;\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_core/state_core.mjs\nfunction StateCore(src, md, env) {\n this.src = src;\n this.env = env;\n this.tokens = [];\n this.inlineMode = false;\n this.md = md;\n}\nStateCore.prototype.Token = token_default;\nvar state_core_default = StateCore;\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_core/normalize.mjs\nvar NEWLINES_RE = /\\r\\n?|\\n/g;\nvar NULL_RE = /\\0/g;\nfunction normalize2(state) {\n let str;\n str = state.src.replace(NEWLINES_RE, \"\\n\");\n str = str.replace(NULL_RE, \"�\");\n state.src = str;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_core/block.mjs\nfunction block(state) {\n let token;\n if (state.inlineMode) {\n token = new state.Token(\"inline\", \"\", 0);\n token.content = state.src;\n token.map = [0, 1];\n token.children = [];\n state.tokens.push(token);\n } else {\n state.md.block.parse(state.src, state.md, state.env, state.tokens);\n }\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_core/inline.mjs\nfunction inline(state) {\n const tokens = state.tokens;\n for (let i = 0, l = tokens.length; i < l; i++) {\n const tok = tokens[i];\n if (tok.type === \"inline\") {\n state.md.inline.parse(tok.content, state.md, state.env, tok.children);\n }\n }\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_core/linkify.mjs\nfunction isLinkOpen(str) {\n return /^\\s]/i.test(str);\n}\nfunction isLinkClose(str) {\n return /^<\\/a\\s*>/i.test(str);\n}\nfunction linkify(state) {\n const blockTokens = state.tokens;\n if (!state.md.options.linkify) {\n return;\n }\n for (let j = 0, l = blockTokens.length; j < l; j++) {\n if (blockTokens[j].type !== \"inline\" || !state.md.linkify.pretest(blockTokens[j].content)) {\n continue;\n }\n let tokens = blockTokens[j].children;\n let htmlLinkLevel = 0;\n for (let i = tokens.length - 1; i >= 0; i--) {\n const currentToken = tokens[i];\n if (currentToken.type === \"link_close\") {\n i--;\n while (tokens[i].level !== currentToken.level && tokens[i].type !== \"link_open\") {\n i--;\n }\n continue;\n }\n if (currentToken.type === \"html_inline\") {\n if (isLinkOpen(currentToken.content) && htmlLinkLevel > 0) {\n htmlLinkLevel--;\n }\n if (isLinkClose(currentToken.content)) {\n htmlLinkLevel++;\n }\n }\n if (htmlLinkLevel > 0) {\n continue;\n }\n if (currentToken.type === \"text\" && state.md.linkify.test(currentToken.content)) {\n const text2 = currentToken.content;\n let links = state.md.linkify.match(text2);\n const nodes = [];\n let level = currentToken.level;\n let lastPos = 0;\n if (links.length > 0 && links[0].index === 0 && i > 0 && tokens[i - 1].type === \"text_special\") {\n links = links.slice(1);\n }\n for (let ln = 0; ln < links.length; ln++) {\n const url = links[ln].url;\n const fullUrl = state.md.normalizeLink(url);\n if (!state.md.validateLink(fullUrl)) {\n continue;\n }\n let urlText = links[ln].text;\n if (!links[ln].schema) {\n urlText = state.md.normalizeLinkText(\"http://\" + urlText).replace(/^http:\\/\\//, \"\");\n } else if (links[ln].schema === \"mailto:\" && !/^mailto:/i.test(urlText)) {\n urlText = state.md.normalizeLinkText(\"mailto:\" + urlText).replace(/^mailto:/, \"\");\n } else {\n urlText = state.md.normalizeLinkText(urlText);\n }\n const pos = links[ln].index;\n if (pos > lastPos) {\n const token = new state.Token(\"text\", \"\", 0);\n token.content = text2.slice(lastPos, pos);\n token.level = level;\n nodes.push(token);\n }\n const token_o = new state.Token(\"link_open\", \"a\", 1);\n token_o.attrs = [[\"href\", fullUrl]];\n token_o.level = level++;\n token_o.markup = \"linkify\";\n token_o.info = \"auto\";\n nodes.push(token_o);\n const token_t = new state.Token(\"text\", \"\", 0);\n token_t.content = urlText;\n token_t.level = level;\n nodes.push(token_t);\n const token_c = new state.Token(\"link_close\", \"a\", -1);\n token_c.level = --level;\n token_c.markup = \"linkify\";\n token_c.info = \"auto\";\n nodes.push(token_c);\n lastPos = links[ln].lastIndex;\n }\n if (lastPos < text2.length) {\n const token = new state.Token(\"text\", \"\", 0);\n token.content = text2.slice(lastPos);\n token.level = level;\n nodes.push(token);\n }\n blockTokens[j].children = tokens = arrayReplaceAt(tokens, i, nodes);\n }\n }\n }\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_core/replacements.mjs\nvar RARE_RE = /\\+-|\\.\\.|\\?\\?\\?\\?|!!!!|,,|--/;\nvar SCOPED_ABBR_TEST_RE = /\\((c|tm|r)\\)/i;\nvar SCOPED_ABBR_RE = /\\((c|tm|r)\\)/ig;\nvar SCOPED_ABBR = {\n c: \"©\",\n r: \"®\",\n tm: \"™\"\n};\nfunction replaceFn(match2, name) {\n return SCOPED_ABBR[name.toLowerCase()];\n}\nfunction replace_scoped(inlineTokens) {\n let inside_autolink = 0;\n for (let i = inlineTokens.length - 1; i >= 0; i--) {\n const token = inlineTokens[i];\n if (token.type === \"text\" && !inside_autolink) {\n token.content = token.content.replace(SCOPED_ABBR_RE, replaceFn);\n }\n if (token.type === \"link_open\" && token.info === \"auto\") {\n inside_autolink--;\n }\n if (token.type === \"link_close\" && token.info === \"auto\") {\n inside_autolink++;\n }\n }\n}\nfunction replace_rare(inlineTokens) {\n let inside_autolink = 0;\n for (let i = inlineTokens.length - 1; i >= 0; i--) {\n const token = inlineTokens[i];\n if (token.type === \"text\" && !inside_autolink) {\n if (RARE_RE.test(token.content)) {\n token.content = token.content.replace(/\\+-/g, \"±\").replace(/\\.{2,}/g, \"…\").replace(/([?!])…/g, \"$1..\").replace(/([?!]){4,}/g, \"$1$1$1\").replace(/,{2,}/g, \",\").replace(/(^|[^-])---(?=[^-]|$)/mg, \"$1—\").replace(/(^|\\s)--(?=\\s|$)/mg, \"$1–\").replace(/(^|[^-\\s])--(?=[^-\\s]|$)/mg, \"$1–\");\n }\n }\n if (token.type === \"link_open\" && token.info === \"auto\") {\n inside_autolink--;\n }\n if (token.type === \"link_close\" && token.info === \"auto\") {\n inside_autolink++;\n }\n }\n}\nfunction replace(state) {\n let blkIdx;\n if (!state.md.options.typographer) {\n return;\n }\n for (blkIdx = state.tokens.length - 1; blkIdx >= 0; blkIdx--) {\n if (state.tokens[blkIdx].type !== \"inline\") {\n continue;\n }\n if (SCOPED_ABBR_TEST_RE.test(state.tokens[blkIdx].content)) {\n replace_scoped(state.tokens[blkIdx].children);\n }\n if (RARE_RE.test(state.tokens[blkIdx].content)) {\n replace_rare(state.tokens[blkIdx].children);\n }\n }\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_core/smartquotes.mjs\nvar QUOTE_TEST_RE = /['\"]/;\nvar QUOTE_RE = /['\"]/g;\nvar APOSTROPHE = \"’\";\nfunction replaceAt(str, index, ch) {\n return str.slice(0, index) + ch + str.slice(index + 1);\n}\nfunction process_inlines(tokens, state) {\n let j;\n const stack = [];\n for (let i = 0; i < tokens.length; i++) {\n const token = tokens[i];\n const thisLevel = tokens[i].level;\n for (j = stack.length - 1; j >= 0; j--) {\n if (stack[j].level <= thisLevel) {\n break;\n }\n }\n stack.length = j + 1;\n if (token.type !== \"text\") {\n continue;\n }\n let text2 = token.content;\n let pos = 0;\n let max2 = text2.length;\n OUTER:\n while (pos < max2) {\n QUOTE_RE.lastIndex = pos;\n const t = QUOTE_RE.exec(text2);\n if (!t) {\n break;\n }\n let canOpen = true;\n let canClose = true;\n pos = t.index + 1;\n const isSingle = t[0] === \"'\";\n let lastChar = 32;\n if (t.index - 1 >= 0) {\n lastChar = text2.charCodeAt(t.index - 1);\n } else {\n for (j = i - 1; j >= 0; j--) {\n if (tokens[j].type === \"softbreak\" || tokens[j].type === \"hardbreak\") break;\n if (!tokens[j].content) continue;\n lastChar = tokens[j].content.charCodeAt(tokens[j].content.length - 1);\n break;\n }\n }\n let nextChar = 32;\n if (pos < max2) {\n nextChar = text2.charCodeAt(pos);\n } else {\n for (j = i + 1; j < tokens.length; j++) {\n if (tokens[j].type === \"softbreak\" || tokens[j].type === \"hardbreak\") break;\n if (!tokens[j].content) continue;\n nextChar = tokens[j].content.charCodeAt(0);\n break;\n }\n }\n const isLastPunctChar = isMdAsciiPunct(lastChar) || isPunctChar(String.fromCharCode(lastChar));\n const isNextPunctChar = isMdAsciiPunct(nextChar) || isPunctChar(String.fromCharCode(nextChar));\n const isLastWhiteSpace = isWhiteSpace(lastChar);\n const isNextWhiteSpace = isWhiteSpace(nextChar);\n if (isNextWhiteSpace) {\n canOpen = false;\n } else if (isNextPunctChar) {\n if (!(isLastWhiteSpace || isLastPunctChar)) {\n canOpen = false;\n }\n }\n if (isLastWhiteSpace) {\n canClose = false;\n } else if (isLastPunctChar) {\n if (!(isNextWhiteSpace || isNextPunctChar)) {\n canClose = false;\n }\n }\n if (nextChar === 34 && t[0] === '\"') {\n if (lastChar >= 48 && lastChar <= 57) {\n canClose = canOpen = false;\n }\n }\n if (canOpen && canClose) {\n canOpen = isLastPunctChar;\n canClose = isNextPunctChar;\n }\n if (!canOpen && !canClose) {\n if (isSingle) {\n token.content = replaceAt(token.content, t.index, APOSTROPHE);\n }\n continue;\n }\n if (canClose) {\n for (j = stack.length - 1; j >= 0; j--) {\n let item = stack[j];\n if (stack[j].level < thisLevel) {\n break;\n }\n if (item.single === isSingle && stack[j].level === thisLevel) {\n item = stack[j];\n let openQuote;\n let closeQuote;\n if (isSingle) {\n openQuote = state.md.options.quotes[2];\n closeQuote = state.md.options.quotes[3];\n } else {\n openQuote = state.md.options.quotes[0];\n closeQuote = state.md.options.quotes[1];\n }\n token.content = replaceAt(token.content, t.index, closeQuote);\n tokens[item.token].content = replaceAt(\n tokens[item.token].content,\n item.pos,\n openQuote\n );\n pos += closeQuote.length - 1;\n if (item.token === i) {\n pos += openQuote.length - 1;\n }\n text2 = token.content;\n max2 = text2.length;\n stack.length = j;\n continue OUTER;\n }\n }\n }\n if (canOpen) {\n stack.push({\n token: i,\n pos: t.index,\n single: isSingle,\n level: thisLevel\n });\n } else if (canClose && isSingle) {\n token.content = replaceAt(token.content, t.index, APOSTROPHE);\n }\n }\n }\n}\nfunction smartquotes(state) {\n if (!state.md.options.typographer) {\n return;\n }\n for (let blkIdx = state.tokens.length - 1; blkIdx >= 0; blkIdx--) {\n if (state.tokens[blkIdx].type !== \"inline\" || !QUOTE_TEST_RE.test(state.tokens[blkIdx].content)) {\n continue;\n }\n process_inlines(state.tokens[blkIdx].children, state);\n }\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_core/text_join.mjs\nfunction text_join(state) {\n let curr, last;\n const blockTokens = state.tokens;\n const l = blockTokens.length;\n for (let j = 0; j < l; j++) {\n if (blockTokens[j].type !== \"inline\") continue;\n const tokens = blockTokens[j].children;\n const max2 = tokens.length;\n for (curr = 0; curr < max2; curr++) {\n if (tokens[curr].type === \"text_special\") {\n tokens[curr].type = \"text\";\n }\n }\n for (curr = last = 0; curr < max2; curr++) {\n if (tokens[curr].type === \"text\" && curr + 1 < max2 && tokens[curr + 1].type === \"text\") {\n tokens[curr + 1].content = tokens[curr].content + tokens[curr + 1].content;\n } else {\n if (curr !== last) {\n tokens[last] = tokens[curr];\n }\n last++;\n }\n }\n if (curr !== last) {\n tokens.length = last;\n }\n }\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/parser_core.mjs\nvar _rules = [\n [\"normalize\", normalize2],\n [\"block\", block],\n [\"inline\", inline],\n [\"linkify\", linkify],\n [\"replacements\", replace],\n [\"smartquotes\", smartquotes],\n // `text_join` finds `text_special` tokens (for escape sequences)\n // and joins them with the rest of the text\n [\"text_join\", text_join]\n];\nfunction Core() {\n this.ruler = new ruler_default();\n for (let i = 0; i < _rules.length; i++) {\n this.ruler.push(_rules[i][0], _rules[i][1]);\n }\n}\nCore.prototype.process = function(state) {\n const rules = this.ruler.getRules(\"\");\n for (let i = 0, l = rules.length; i < l; i++) {\n rules[i](state);\n }\n};\nCore.prototype.State = state_core_default;\nvar parser_core_default = Core;\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/state_block.mjs\nfunction StateBlock(src, md, env, tokens) {\n this.src = src;\n this.md = md;\n this.env = env;\n this.tokens = tokens;\n this.bMarks = [];\n this.eMarks = [];\n this.tShift = [];\n this.sCount = [];\n this.bsCount = [];\n this.blkIndent = 0;\n this.line = 0;\n this.lineMax = 0;\n this.tight = false;\n this.ddIndent = -1;\n this.listIndent = -1;\n this.parentType = \"root\";\n this.level = 0;\n const s = this.src;\n for (let start = 0, pos = 0, indent = 0, offset = 0, len = s.length, indent_found = false; pos < len; pos++) {\n const ch = s.charCodeAt(pos);\n if (!indent_found) {\n if (isSpace(ch)) {\n indent++;\n if (ch === 9) {\n offset += 4 - offset % 4;\n } else {\n offset++;\n }\n continue;\n } else {\n indent_found = true;\n }\n }\n if (ch === 10 || pos === len - 1) {\n if (ch !== 10) {\n pos++;\n }\n this.bMarks.push(start);\n this.eMarks.push(pos);\n this.tShift.push(indent);\n this.sCount.push(offset);\n this.bsCount.push(0);\n indent_found = false;\n indent = 0;\n offset = 0;\n start = pos + 1;\n }\n }\n this.bMarks.push(s.length);\n this.eMarks.push(s.length);\n this.tShift.push(0);\n this.sCount.push(0);\n this.bsCount.push(0);\n this.lineMax = this.bMarks.length - 1;\n}\nStateBlock.prototype.push = function(type, tag, nesting) {\n const token = new token_default(type, tag, nesting);\n token.block = true;\n if (nesting < 0) this.level--;\n token.level = this.level;\n if (nesting > 0) this.level++;\n this.tokens.push(token);\n return token;\n};\nStateBlock.prototype.isEmpty = function isEmpty(line) {\n return this.bMarks[line] + this.tShift[line] >= this.eMarks[line];\n};\nStateBlock.prototype.skipEmptyLines = function skipEmptyLines(from) {\n for (let max2 = this.lineMax; from < max2; from++) {\n if (this.bMarks[from] + this.tShift[from] < this.eMarks[from]) {\n break;\n }\n }\n return from;\n};\nStateBlock.prototype.skipSpaces = function skipSpaces(pos) {\n for (let max2 = this.src.length; pos < max2; pos++) {\n const ch = this.src.charCodeAt(pos);\n if (!isSpace(ch)) {\n break;\n }\n }\n return pos;\n};\nStateBlock.prototype.skipSpacesBack = function skipSpacesBack(pos, min) {\n if (pos <= min) {\n return pos;\n }\n while (pos > min) {\n if (!isSpace(this.src.charCodeAt(--pos))) {\n return pos + 1;\n }\n }\n return pos;\n};\nStateBlock.prototype.skipChars = function skipChars(pos, code2) {\n for (let max2 = this.src.length; pos < max2; pos++) {\n if (this.src.charCodeAt(pos) !== code2) {\n break;\n }\n }\n return pos;\n};\nStateBlock.prototype.skipCharsBack = function skipCharsBack(pos, code2, min) {\n if (pos <= min) {\n return pos;\n }\n while (pos > min) {\n if (code2 !== this.src.charCodeAt(--pos)) {\n return pos + 1;\n }\n }\n return pos;\n};\nStateBlock.prototype.getLines = function getLines(begin, end, indent, keepLastLF) {\n if (begin >= end) {\n return \"\";\n }\n const queue = new Array(end - begin);\n for (let i = 0, line = begin; line < end; line++, i++) {\n let lineIndent = 0;\n const lineStart = this.bMarks[line];\n let first = lineStart;\n let last;\n if (line + 1 < end || keepLastLF) {\n last = this.eMarks[line] + 1;\n } else {\n last = this.eMarks[line];\n }\n while (first < last && lineIndent < indent) {\n const ch = this.src.charCodeAt(first);\n if (isSpace(ch)) {\n if (ch === 9) {\n lineIndent += 4 - (lineIndent + this.bsCount[line]) % 4;\n } else {\n lineIndent++;\n }\n } else if (first - lineStart < this.tShift[line]) {\n lineIndent++;\n } else {\n break;\n }\n first++;\n }\n if (lineIndent > indent) {\n queue[i] = new Array(lineIndent - indent + 1).join(\" \") + this.src.slice(first, last);\n } else {\n queue[i] = this.src.slice(first, last);\n }\n }\n return queue.join(\"\");\n};\nStateBlock.prototype.Token = token_default;\nvar state_block_default = StateBlock;\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/table.mjs\nvar MAX_AUTOCOMPLETED_CELLS = 65536;\nfunction getLine(state, line) {\n const pos = state.bMarks[line] + state.tShift[line];\n const max2 = state.eMarks[line];\n return state.src.slice(pos, max2);\n}\nfunction escapedSplit(str) {\n const result = [];\n const max2 = str.length;\n let pos = 0;\n let ch = str.charCodeAt(pos);\n let isEscaped = false;\n let lastPos = 0;\n let current = \"\";\n while (pos < max2) {\n if (ch === 124) {\n if (!isEscaped) {\n result.push(current + str.substring(lastPos, pos));\n current = \"\";\n lastPos = pos + 1;\n } else {\n current += str.substring(lastPos, pos - 1);\n lastPos = pos;\n }\n }\n isEscaped = ch === 92;\n pos++;\n ch = str.charCodeAt(pos);\n }\n result.push(current + str.substring(lastPos));\n return result;\n}\nfunction table(state, startLine, endLine, silent) {\n if (startLine + 2 > endLine) {\n return false;\n }\n let nextLine = startLine + 1;\n if (state.sCount[nextLine] < state.blkIndent) {\n return false;\n }\n if (state.sCount[nextLine] - state.blkIndent >= 4) {\n return false;\n }\n let pos = state.bMarks[nextLine] + state.tShift[nextLine];\n if (pos >= state.eMarks[nextLine]) {\n return false;\n }\n const firstCh = state.src.charCodeAt(pos++);\n if (firstCh !== 124 && firstCh !== 45 && firstCh !== 58) {\n return false;\n }\n if (pos >= state.eMarks[nextLine]) {\n return false;\n }\n const secondCh = state.src.charCodeAt(pos++);\n if (secondCh !== 124 && secondCh !== 45 && secondCh !== 58 && !isSpace(secondCh)) {\n return false;\n }\n if (firstCh === 45 && isSpace(secondCh)) {\n return false;\n }\n while (pos < state.eMarks[nextLine]) {\n const ch = state.src.charCodeAt(pos);\n if (ch !== 124 && ch !== 45 && ch !== 58 && !isSpace(ch)) {\n return false;\n }\n pos++;\n }\n let lineText = getLine(state, startLine + 1);\n let columns = lineText.split(\"|\");\n const aligns = [];\n for (let i = 0; i < columns.length; i++) {\n const t = columns[i].trim();\n if (!t) {\n if (i === 0 || i === columns.length - 1) {\n continue;\n } else {\n return false;\n }\n }\n if (!/^:?-+:?$/.test(t)) {\n return false;\n }\n if (t.charCodeAt(t.length - 1) === 58) {\n aligns.push(t.charCodeAt(0) === 58 ? \"center\" : \"right\");\n } else if (t.charCodeAt(0) === 58) {\n aligns.push(\"left\");\n } else {\n aligns.push(\"\");\n }\n }\n lineText = getLine(state, startLine).trim();\n if (lineText.indexOf(\"|\") === -1) {\n return false;\n }\n if (state.sCount[startLine] - state.blkIndent >= 4) {\n return false;\n }\n columns = escapedSplit(lineText);\n if (columns.length && columns[0] === \"\") columns.shift();\n if (columns.length && columns[columns.length - 1] === \"\") columns.pop();\n const columnCount = columns.length;\n if (columnCount === 0 || columnCount !== aligns.length) {\n return false;\n }\n if (silent) {\n return true;\n }\n const oldParentType = state.parentType;\n state.parentType = \"table\";\n const terminatorRules = state.md.block.ruler.getRules(\"blockquote\");\n const token_to = state.push(\"table_open\", \"table\", 1);\n const tableLines = [startLine, 0];\n token_to.map = tableLines;\n const token_tho = state.push(\"thead_open\", \"thead\", 1);\n token_tho.map = [startLine, startLine + 1];\n const token_htro = state.push(\"tr_open\", \"tr\", 1);\n token_htro.map = [startLine, startLine + 1];\n for (let i = 0; i < columns.length; i++) {\n const token_ho = state.push(\"th_open\", \"th\", 1);\n if (aligns[i]) {\n token_ho.attrs = [[\"style\", \"text-align:\" + aligns[i]]];\n }\n const token_il = state.push(\"inline\", \"\", 0);\n token_il.content = columns[i].trim();\n token_il.children = [];\n state.push(\"th_close\", \"th\", -1);\n }\n state.push(\"tr_close\", \"tr\", -1);\n state.push(\"thead_close\", \"thead\", -1);\n let tbodyLines;\n let autocompletedCells = 0;\n for (nextLine = startLine + 2; nextLine < endLine; nextLine++) {\n if (state.sCount[nextLine] < state.blkIndent) {\n break;\n }\n let terminate = false;\n for (let i = 0, l = terminatorRules.length; i < l; i++) {\n if (terminatorRules[i](state, nextLine, endLine, true)) {\n terminate = true;\n break;\n }\n }\n if (terminate) {\n break;\n }\n lineText = getLine(state, nextLine).trim();\n if (!lineText) {\n break;\n }\n if (state.sCount[nextLine] - state.blkIndent >= 4) {\n break;\n }\n columns = escapedSplit(lineText);\n if (columns.length && columns[0] === \"\") columns.shift();\n if (columns.length && columns[columns.length - 1] === \"\") columns.pop();\n autocompletedCells += columnCount - columns.length;\n if (autocompletedCells > MAX_AUTOCOMPLETED_CELLS) {\n break;\n }\n if (nextLine === startLine + 2) {\n const token_tbo = state.push(\"tbody_open\", \"tbody\", 1);\n token_tbo.map = tbodyLines = [startLine + 2, 0];\n }\n const token_tro = state.push(\"tr_open\", \"tr\", 1);\n token_tro.map = [nextLine, nextLine + 1];\n for (let i = 0; i < columnCount; i++) {\n const token_tdo = state.push(\"td_open\", \"td\", 1);\n if (aligns[i]) {\n token_tdo.attrs = [[\"style\", \"text-align:\" + aligns[i]]];\n }\n const token_il = state.push(\"inline\", \"\", 0);\n token_il.content = columns[i] ? columns[i].trim() : \"\";\n token_il.children = [];\n state.push(\"td_close\", \"td\", -1);\n }\n state.push(\"tr_close\", \"tr\", -1);\n }\n if (tbodyLines) {\n state.push(\"tbody_close\", \"tbody\", -1);\n tbodyLines[1] = nextLine;\n }\n state.push(\"table_close\", \"table\", -1);\n tableLines[1] = nextLine;\n state.parentType = oldParentType;\n state.line = nextLine;\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/code.mjs\nfunction code(state, startLine, endLine) {\n if (state.sCount[startLine] - state.blkIndent < 4) {\n return false;\n }\n let nextLine = startLine + 1;\n let last = nextLine;\n while (nextLine < endLine) {\n if (state.isEmpty(nextLine)) {\n nextLine++;\n continue;\n }\n if (state.sCount[nextLine] - state.blkIndent >= 4) {\n nextLine++;\n last = nextLine;\n continue;\n }\n break;\n }\n state.line = last;\n const token = state.push(\"code_block\", \"code\", 0);\n token.content = state.getLines(startLine, last, 4 + state.blkIndent, false) + \"\\n\";\n token.map = [startLine, state.line];\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/fence.mjs\nfunction fence(state, startLine, endLine, silent) {\n let pos = state.bMarks[startLine] + state.tShift[startLine];\n let max2 = state.eMarks[startLine];\n if (state.sCount[startLine] - state.blkIndent >= 4) {\n return false;\n }\n if (pos + 3 > max2) {\n return false;\n }\n const marker = state.src.charCodeAt(pos);\n if (marker !== 126 && marker !== 96) {\n return false;\n }\n let mem = pos;\n pos = state.skipChars(pos, marker);\n let len = pos - mem;\n if (len < 3) {\n return false;\n }\n const markup = state.src.slice(mem, pos);\n const params = state.src.slice(pos, max2);\n if (marker === 96) {\n if (params.indexOf(String.fromCharCode(marker)) >= 0) {\n return false;\n }\n }\n if (silent) {\n return true;\n }\n let nextLine = startLine;\n let haveEndMarker = false;\n for (; ; ) {\n nextLine++;\n if (nextLine >= endLine) {\n break;\n }\n pos = mem = state.bMarks[nextLine] + state.tShift[nextLine];\n max2 = state.eMarks[nextLine];\n if (pos < max2 && state.sCount[nextLine] < state.blkIndent) {\n break;\n }\n if (state.src.charCodeAt(pos) !== marker) {\n continue;\n }\n if (state.sCount[nextLine] - state.blkIndent >= 4) {\n continue;\n }\n pos = state.skipChars(pos, marker);\n if (pos - mem < len) {\n continue;\n }\n pos = state.skipSpaces(pos);\n if (pos < max2) {\n continue;\n }\n haveEndMarker = true;\n break;\n }\n len = state.sCount[startLine];\n state.line = nextLine + (haveEndMarker ? 1 : 0);\n const token = state.push(\"fence\", \"code\", 0);\n token.info = params;\n token.content = state.getLines(startLine + 1, nextLine, len, true);\n token.markup = markup;\n token.map = [startLine, state.line];\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/blockquote.mjs\nfunction blockquote(state, startLine, endLine, silent) {\n let pos = state.bMarks[startLine] + state.tShift[startLine];\n let max2 = state.eMarks[startLine];\n const oldLineMax = state.lineMax;\n if (state.sCount[startLine] - state.blkIndent >= 4) {\n return false;\n }\n if (state.src.charCodeAt(pos) !== 62) {\n return false;\n }\n if (silent) {\n return true;\n }\n const oldBMarks = [];\n const oldBSCount = [];\n const oldSCount = [];\n const oldTShift = [];\n const terminatorRules = state.md.block.ruler.getRules(\"blockquote\");\n const oldParentType = state.parentType;\n state.parentType = \"blockquote\";\n let lastLineEmpty = false;\n let nextLine;\n for (nextLine = startLine; nextLine < endLine; nextLine++) {\n const isOutdented = state.sCount[nextLine] < state.blkIndent;\n pos = state.bMarks[nextLine] + state.tShift[nextLine];\n max2 = state.eMarks[nextLine];\n if (pos >= max2) {\n break;\n }\n if (state.src.charCodeAt(pos++) === 62 && !isOutdented) {\n let initial = state.sCount[nextLine] + 1;\n let spaceAfterMarker;\n let adjustTab;\n if (state.src.charCodeAt(pos) === 32) {\n pos++;\n initial++;\n adjustTab = false;\n spaceAfterMarker = true;\n } else if (state.src.charCodeAt(pos) === 9) {\n spaceAfterMarker = true;\n if ((state.bsCount[nextLine] + initial) % 4 === 3) {\n pos++;\n initial++;\n adjustTab = false;\n } else {\n adjustTab = true;\n }\n } else {\n spaceAfterMarker = false;\n }\n let offset = initial;\n oldBMarks.push(state.bMarks[nextLine]);\n state.bMarks[nextLine] = pos;\n while (pos < max2) {\n const ch = state.src.charCodeAt(pos);\n if (isSpace(ch)) {\n if (ch === 9) {\n offset += 4 - (offset + state.bsCount[nextLine] + (adjustTab ? 1 : 0)) % 4;\n } else {\n offset++;\n }\n } else {\n break;\n }\n pos++;\n }\n lastLineEmpty = pos >= max2;\n oldBSCount.push(state.bsCount[nextLine]);\n state.bsCount[nextLine] = state.sCount[nextLine] + 1 + (spaceAfterMarker ? 1 : 0);\n oldSCount.push(state.sCount[nextLine]);\n state.sCount[nextLine] = offset - initial;\n oldTShift.push(state.tShift[nextLine]);\n state.tShift[nextLine] = pos - state.bMarks[nextLine];\n continue;\n }\n if (lastLineEmpty) {\n break;\n }\n let terminate = false;\n for (let i = 0, l = terminatorRules.length; i < l; i++) {\n if (terminatorRules[i](state, nextLine, endLine, true)) {\n terminate = true;\n break;\n }\n }\n if (terminate) {\n state.lineMax = nextLine;\n if (state.blkIndent !== 0) {\n oldBMarks.push(state.bMarks[nextLine]);\n oldBSCount.push(state.bsCount[nextLine]);\n oldTShift.push(state.tShift[nextLine]);\n oldSCount.push(state.sCount[nextLine]);\n state.sCount[nextLine] -= state.blkIndent;\n }\n break;\n }\n oldBMarks.push(state.bMarks[nextLine]);\n oldBSCount.push(state.bsCount[nextLine]);\n oldTShift.push(state.tShift[nextLine]);\n oldSCount.push(state.sCount[nextLine]);\n state.sCount[nextLine] = -1;\n }\n const oldIndent = state.blkIndent;\n state.blkIndent = 0;\n const token_o = state.push(\"blockquote_open\", \"blockquote\", 1);\n token_o.markup = \">\";\n const lines = [startLine, 0];\n token_o.map = lines;\n state.md.block.tokenize(state, startLine, nextLine);\n const token_c = state.push(\"blockquote_close\", \"blockquote\", -1);\n token_c.markup = \">\";\n state.lineMax = oldLineMax;\n state.parentType = oldParentType;\n lines[1] = state.line;\n for (let i = 0; i < oldTShift.length; i++) {\n state.bMarks[i + startLine] = oldBMarks[i];\n state.tShift[i + startLine] = oldTShift[i];\n state.sCount[i + startLine] = oldSCount[i];\n state.bsCount[i + startLine] = oldBSCount[i];\n }\n state.blkIndent = oldIndent;\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/hr.mjs\nfunction hr(state, startLine, endLine, silent) {\n const max2 = state.eMarks[startLine];\n if (state.sCount[startLine] - state.blkIndent >= 4) {\n return false;\n }\n let pos = state.bMarks[startLine] + state.tShift[startLine];\n const marker = state.src.charCodeAt(pos++);\n if (marker !== 42 && marker !== 45 && marker !== 95) {\n return false;\n }\n let cnt = 1;\n while (pos < max2) {\n const ch = state.src.charCodeAt(pos++);\n if (ch !== marker && !isSpace(ch)) {\n return false;\n }\n if (ch === marker) {\n cnt++;\n }\n }\n if (cnt < 3) {\n return false;\n }\n if (silent) {\n return true;\n }\n state.line = startLine + 1;\n const token = state.push(\"hr\", \"hr\", 0);\n token.map = [startLine, state.line];\n token.markup = Array(cnt + 1).join(String.fromCharCode(marker));\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/list.mjs\nfunction skipBulletListMarker(state, startLine) {\n const max2 = state.eMarks[startLine];\n let pos = state.bMarks[startLine] + state.tShift[startLine];\n const marker = state.src.charCodeAt(pos++);\n if (marker !== 42 && marker !== 45 && marker !== 43) {\n return -1;\n }\n if (pos < max2) {\n const ch = state.src.charCodeAt(pos);\n if (!isSpace(ch)) {\n return -1;\n }\n }\n return pos;\n}\nfunction skipOrderedListMarker(state, startLine) {\n const start = state.bMarks[startLine] + state.tShift[startLine];\n const max2 = state.eMarks[startLine];\n let pos = start;\n if (pos + 1 >= max2) {\n return -1;\n }\n let ch = state.src.charCodeAt(pos++);\n if (ch < 48 || ch > 57) {\n return -1;\n }\n for (; ; ) {\n if (pos >= max2) {\n return -1;\n }\n ch = state.src.charCodeAt(pos++);\n if (ch >= 48 && ch <= 57) {\n if (pos - start >= 10) {\n return -1;\n }\n continue;\n }\n if (ch === 41 || ch === 46) {\n break;\n }\n return -1;\n }\n if (pos < max2) {\n ch = state.src.charCodeAt(pos);\n if (!isSpace(ch)) {\n return -1;\n }\n }\n return pos;\n}\nfunction markTightParagraphs(state, idx) {\n const level = state.level + 2;\n for (let i = idx + 2, l = state.tokens.length - 2; i < l; i++) {\n if (state.tokens[i].level === level && state.tokens[i].type === \"paragraph_open\") {\n state.tokens[i + 2].hidden = true;\n state.tokens[i].hidden = true;\n i += 2;\n }\n }\n}\nfunction list(state, startLine, endLine, silent) {\n let max2, pos, start, token;\n let nextLine = startLine;\n let tight = true;\n if (state.sCount[nextLine] - state.blkIndent >= 4) {\n return false;\n }\n if (state.listIndent >= 0 && state.sCount[nextLine] - state.listIndent >= 4 && state.sCount[nextLine] < state.blkIndent) {\n return false;\n }\n let isTerminatingParagraph = false;\n if (silent && state.parentType === \"paragraph\") {\n if (state.sCount[nextLine] >= state.blkIndent) {\n isTerminatingParagraph = true;\n }\n }\n let isOrdered;\n let markerValue;\n let posAfterMarker;\n if ((posAfterMarker = skipOrderedListMarker(state, nextLine)) >= 0) {\n isOrdered = true;\n start = state.bMarks[nextLine] + state.tShift[nextLine];\n markerValue = Number(state.src.slice(start, posAfterMarker - 1));\n if (isTerminatingParagraph && markerValue !== 1) return false;\n } else if ((posAfterMarker = skipBulletListMarker(state, nextLine)) >= 0) {\n isOrdered = false;\n } else {\n return false;\n }\n if (isTerminatingParagraph) {\n if (state.skipSpaces(posAfterMarker) >= state.eMarks[nextLine]) return false;\n }\n if (silent) {\n return true;\n }\n const markerCharCode = state.src.charCodeAt(posAfterMarker - 1);\n const listTokIdx = state.tokens.length;\n if (isOrdered) {\n token = state.push(\"ordered_list_open\", \"ol\", 1);\n if (markerValue !== 1) {\n token.attrs = [[\"start\", markerValue]];\n }\n } else {\n token = state.push(\"bullet_list_open\", \"ul\", 1);\n }\n const listLines = [nextLine, 0];\n token.map = listLines;\n token.markup = String.fromCharCode(markerCharCode);\n let prevEmptyEnd = false;\n const terminatorRules = state.md.block.ruler.getRules(\"list\");\n const oldParentType = state.parentType;\n state.parentType = \"list\";\n while (nextLine < endLine) {\n pos = posAfterMarker;\n max2 = state.eMarks[nextLine];\n const initial = state.sCount[nextLine] + posAfterMarker - (state.bMarks[nextLine] + state.tShift[nextLine]);\n let offset = initial;\n while (pos < max2) {\n const ch = state.src.charCodeAt(pos);\n if (ch === 9) {\n offset += 4 - (offset + state.bsCount[nextLine]) % 4;\n } else if (ch === 32) {\n offset++;\n } else {\n break;\n }\n pos++;\n }\n const contentStart = pos;\n let indentAfterMarker;\n if (contentStart >= max2) {\n indentAfterMarker = 1;\n } else {\n indentAfterMarker = offset - initial;\n }\n if (indentAfterMarker > 4) {\n indentAfterMarker = 1;\n }\n const indent = initial + indentAfterMarker;\n token = state.push(\"list_item_open\", \"li\", 1);\n token.markup = String.fromCharCode(markerCharCode);\n const itemLines = [nextLine, 0];\n token.map = itemLines;\n if (isOrdered) {\n token.info = state.src.slice(start, posAfterMarker - 1);\n }\n const oldTight = state.tight;\n const oldTShift = state.tShift[nextLine];\n const oldSCount = state.sCount[nextLine];\n const oldListIndent = state.listIndent;\n state.listIndent = state.blkIndent;\n state.blkIndent = indent;\n state.tight = true;\n state.tShift[nextLine] = contentStart - state.bMarks[nextLine];\n state.sCount[nextLine] = offset;\n if (contentStart >= max2 && state.isEmpty(nextLine + 1)) {\n state.line = Math.min(state.line + 2, endLine);\n } else {\n state.md.block.tokenize(state, nextLine, endLine, true);\n }\n if (!state.tight || prevEmptyEnd) {\n tight = false;\n }\n prevEmptyEnd = state.line - nextLine > 1 && state.isEmpty(state.line - 1);\n state.blkIndent = state.listIndent;\n state.listIndent = oldListIndent;\n state.tShift[nextLine] = oldTShift;\n state.sCount[nextLine] = oldSCount;\n state.tight = oldTight;\n token = state.push(\"list_item_close\", \"li\", -1);\n token.markup = String.fromCharCode(markerCharCode);\n nextLine = state.line;\n itemLines[1] = nextLine;\n if (nextLine >= endLine) {\n break;\n }\n if (state.sCount[nextLine] < state.blkIndent) {\n break;\n }\n if (state.sCount[nextLine] - state.blkIndent >= 4) {\n break;\n }\n let terminate = false;\n for (let i = 0, l = terminatorRules.length; i < l; i++) {\n if (terminatorRules[i](state, nextLine, endLine, true)) {\n terminate = true;\n break;\n }\n }\n if (terminate) {\n break;\n }\n if (isOrdered) {\n posAfterMarker = skipOrderedListMarker(state, nextLine);\n if (posAfterMarker < 0) {\n break;\n }\n start = state.bMarks[nextLine] + state.tShift[nextLine];\n } else {\n posAfterMarker = skipBulletListMarker(state, nextLine);\n if (posAfterMarker < 0) {\n break;\n }\n }\n if (markerCharCode !== state.src.charCodeAt(posAfterMarker - 1)) {\n break;\n }\n }\n if (isOrdered) {\n token = state.push(\"ordered_list_close\", \"ol\", -1);\n } else {\n token = state.push(\"bullet_list_close\", \"ul\", -1);\n }\n token.markup = String.fromCharCode(markerCharCode);\n listLines[1] = nextLine;\n state.line = nextLine;\n state.parentType = oldParentType;\n if (tight) {\n markTightParagraphs(state, listTokIdx);\n }\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/reference.mjs\nfunction reference(state, startLine, _endLine, silent) {\n let pos = state.bMarks[startLine] + state.tShift[startLine];\n let max2 = state.eMarks[startLine];\n let nextLine = startLine + 1;\n if (state.sCount[startLine] - state.blkIndent >= 4) {\n return false;\n }\n if (state.src.charCodeAt(pos) !== 91) {\n return false;\n }\n function getNextLine(nextLine2) {\n const endLine = state.lineMax;\n if (nextLine2 >= endLine || state.isEmpty(nextLine2)) {\n return null;\n }\n let isContinuation = false;\n if (state.sCount[nextLine2] - state.blkIndent > 3) {\n isContinuation = true;\n }\n if (state.sCount[nextLine2] < 0) {\n isContinuation = true;\n }\n if (!isContinuation) {\n const terminatorRules = state.md.block.ruler.getRules(\"reference\");\n const oldParentType = state.parentType;\n state.parentType = \"reference\";\n let terminate = false;\n for (let i = 0, l = terminatorRules.length; i < l; i++) {\n if (terminatorRules[i](state, nextLine2, endLine, true)) {\n terminate = true;\n break;\n }\n }\n state.parentType = oldParentType;\n if (terminate) {\n return null;\n }\n }\n const pos2 = state.bMarks[nextLine2] + state.tShift[nextLine2];\n const max3 = state.eMarks[nextLine2];\n return state.src.slice(pos2, max3 + 1);\n }\n let str = state.src.slice(pos, max2 + 1);\n max2 = str.length;\n let labelEnd = -1;\n for (pos = 1; pos < max2; pos++) {\n const ch = str.charCodeAt(pos);\n if (ch === 91) {\n return false;\n } else if (ch === 93) {\n labelEnd = pos;\n break;\n } else if (ch === 10) {\n const lineContent = getNextLine(nextLine);\n if (lineContent !== null) {\n str += lineContent;\n max2 = str.length;\n nextLine++;\n }\n } else if (ch === 92) {\n pos++;\n if (pos < max2 && str.charCodeAt(pos) === 10) {\n const lineContent = getNextLine(nextLine);\n if (lineContent !== null) {\n str += lineContent;\n max2 = str.length;\n nextLine++;\n }\n }\n }\n }\n if (labelEnd < 0 || str.charCodeAt(labelEnd + 1) !== 58) {\n return false;\n }\n for (pos = labelEnd + 2; pos < max2; pos++) {\n const ch = str.charCodeAt(pos);\n if (ch === 10) {\n const lineContent = getNextLine(nextLine);\n if (lineContent !== null) {\n str += lineContent;\n max2 = str.length;\n nextLine++;\n }\n } else if (isSpace(ch)) {\n } else {\n break;\n }\n }\n const destRes = state.md.helpers.parseLinkDestination(str, pos, max2);\n if (!destRes.ok) {\n return false;\n }\n const href = state.md.normalizeLink(destRes.str);\n if (!state.md.validateLink(href)) {\n return false;\n }\n pos = destRes.pos;\n const destEndPos = pos;\n const destEndLineNo = nextLine;\n const start = pos;\n for (; pos < max2; pos++) {\n const ch = str.charCodeAt(pos);\n if (ch === 10) {\n const lineContent = getNextLine(nextLine);\n if (lineContent !== null) {\n str += lineContent;\n max2 = str.length;\n nextLine++;\n }\n } else if (isSpace(ch)) {\n } else {\n break;\n }\n }\n let titleRes = state.md.helpers.parseLinkTitle(str, pos, max2);\n while (titleRes.can_continue) {\n const lineContent = getNextLine(nextLine);\n if (lineContent === null) break;\n str += lineContent;\n pos = max2;\n max2 = str.length;\n nextLine++;\n titleRes = state.md.helpers.parseLinkTitle(str, pos, max2, titleRes);\n }\n let title;\n if (pos < max2 && start !== pos && titleRes.ok) {\n title = titleRes.str;\n pos = titleRes.pos;\n } else {\n title = \"\";\n pos = destEndPos;\n nextLine = destEndLineNo;\n }\n while (pos < max2) {\n const ch = str.charCodeAt(pos);\n if (!isSpace(ch)) {\n break;\n }\n pos++;\n }\n if (pos < max2 && str.charCodeAt(pos) !== 10) {\n if (title) {\n title = \"\";\n pos = destEndPos;\n nextLine = destEndLineNo;\n while (pos < max2) {\n const ch = str.charCodeAt(pos);\n if (!isSpace(ch)) {\n break;\n }\n pos++;\n }\n }\n }\n if (pos < max2 && str.charCodeAt(pos) !== 10) {\n return false;\n }\n const label = normalizeReference(str.slice(1, labelEnd));\n if (!label) {\n return false;\n }\n if (silent) {\n return true;\n }\n if (typeof state.env.references === \"undefined\") {\n state.env.references = {};\n }\n if (typeof state.env.references[label] === \"undefined\") {\n state.env.references[label] = { title, href };\n }\n state.line = nextLine;\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/common/html_blocks.mjs\nvar html_blocks_default = [\n \"address\",\n \"article\",\n \"aside\",\n \"base\",\n \"basefont\",\n \"blockquote\",\n \"body\",\n \"caption\",\n \"center\",\n \"col\",\n \"colgroup\",\n \"dd\",\n \"details\",\n \"dialog\",\n \"dir\",\n \"div\",\n \"dl\",\n \"dt\",\n \"fieldset\",\n \"figcaption\",\n \"figure\",\n \"footer\",\n \"form\",\n \"frame\",\n \"frameset\",\n \"h1\",\n \"h2\",\n \"h3\",\n \"h4\",\n \"h5\",\n \"h6\",\n \"head\",\n \"header\",\n \"hr\",\n \"html\",\n \"iframe\",\n \"legend\",\n \"li\",\n \"link\",\n \"main\",\n \"menu\",\n \"menuitem\",\n \"nav\",\n \"noframes\",\n \"ol\",\n \"optgroup\",\n \"option\",\n \"p\",\n \"param\",\n \"search\",\n \"section\",\n \"summary\",\n \"table\",\n \"tbody\",\n \"td\",\n \"tfoot\",\n \"th\",\n \"thead\",\n \"title\",\n \"tr\",\n \"track\",\n \"ul\"\n];\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/common/html_re.mjs\nvar attr_name = \"[a-zA-Z_:][a-zA-Z0-9:._-]*\";\nvar unquoted = \"[^\\\"'=<>`\\\\x00-\\\\x20]+\";\nvar single_quoted = \"'[^']*'\";\nvar double_quoted = '\"[^\"]*\"';\nvar attr_value = \"(?:\" + unquoted + \"|\" + single_quoted + \"|\" + double_quoted + \")\";\nvar attribute = \"(?:\\\\s+\" + attr_name + \"(?:\\\\s*=\\\\s*\" + attr_value + \")?)\";\nvar open_tag = \"<[A-Za-z][A-Za-z0-9\\\\-]*\" + attribute + \"*\\\\s*\\\\/?>\";\nvar close_tag = \"<\\\\/[A-Za-z][A-Za-z0-9\\\\-]*\\\\s*>\";\nvar comment = \"\";\nvar processing = \"<[?][\\\\s\\\\S]*?[?]>\";\nvar declaration = \"]*>\";\nvar cdata = \"\";\nvar HTML_TAG_RE = new RegExp(\"^(?:\" + open_tag + \"|\" + close_tag + \"|\" + comment + \"|\" + processing + \"|\" + declaration + \"|\" + cdata + \")\");\nvar HTML_OPEN_CLOSE_TAG_RE = new RegExp(\"^(?:\" + open_tag + \"|\" + close_tag + \")\");\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/html_block.mjs\nvar HTML_SEQUENCES = [\n [/^<(script|pre|style|textarea)(?=(\\s|>|$))/i, /<\\/(script|pre|style|textarea)>/i, true],\n [/^/, true],\n [/^<\\?/, /\\?>/, true],\n [/^/, true],\n [/^/, true],\n [new RegExp(\"^|$))\", \"i\"), /^$/, true],\n [new RegExp(HTML_OPEN_CLOSE_TAG_RE.source + \"\\\\s*$\"), /^$/, false]\n];\nfunction html_block(state, startLine, endLine, silent) {\n let pos = state.bMarks[startLine] + state.tShift[startLine];\n let max2 = state.eMarks[startLine];\n if (state.sCount[startLine] - state.blkIndent >= 4) {\n return false;\n }\n if (!state.md.options.html) {\n return false;\n }\n if (state.src.charCodeAt(pos) !== 60) {\n return false;\n }\n let lineText = state.src.slice(pos, max2);\n let i = 0;\n for (; i < HTML_SEQUENCES.length; i++) {\n if (HTML_SEQUENCES[i][0].test(lineText)) {\n break;\n }\n }\n if (i === HTML_SEQUENCES.length) {\n return false;\n }\n if (silent) {\n return HTML_SEQUENCES[i][2];\n }\n let nextLine = startLine + 1;\n if (!HTML_SEQUENCES[i][1].test(lineText)) {\n for (; nextLine < endLine; nextLine++) {\n if (state.sCount[nextLine] < state.blkIndent) {\n break;\n }\n pos = state.bMarks[nextLine] + state.tShift[nextLine];\n max2 = state.eMarks[nextLine];\n lineText = state.src.slice(pos, max2);\n if (HTML_SEQUENCES[i][1].test(lineText)) {\n if (lineText.length !== 0) {\n nextLine++;\n }\n break;\n }\n }\n }\n state.line = nextLine;\n const token = state.push(\"html_block\", \"\", 0);\n token.map = [startLine, nextLine];\n token.content = state.getLines(startLine, nextLine, state.blkIndent, true);\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/heading.mjs\nfunction heading(state, startLine, endLine, silent) {\n let pos = state.bMarks[startLine] + state.tShift[startLine];\n let max2 = state.eMarks[startLine];\n if (state.sCount[startLine] - state.blkIndent >= 4) {\n return false;\n }\n let ch = state.src.charCodeAt(pos);\n if (ch !== 35 || pos >= max2) {\n return false;\n }\n let level = 1;\n ch = state.src.charCodeAt(++pos);\n while (ch === 35 && pos < max2 && level <= 6) {\n level++;\n ch = state.src.charCodeAt(++pos);\n }\n if (level > 6 || pos < max2 && !isSpace(ch)) {\n return false;\n }\n if (silent) {\n return true;\n }\n max2 = state.skipSpacesBack(max2, pos);\n const tmp = state.skipCharsBack(max2, 35, pos);\n if (tmp > pos && isSpace(state.src.charCodeAt(tmp - 1))) {\n max2 = tmp;\n }\n state.line = startLine + 1;\n const token_o = state.push(\"heading_open\", \"h\" + String(level), 1);\n token_o.markup = \"########\".slice(0, level);\n token_o.map = [startLine, state.line];\n const token_i = state.push(\"inline\", \"\", 0);\n token_i.content = state.src.slice(pos, max2).trim();\n token_i.map = [startLine, state.line];\n token_i.children = [];\n const token_c = state.push(\"heading_close\", \"h\" + String(level), -1);\n token_c.markup = \"########\".slice(0, level);\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/lheading.mjs\nfunction lheading(state, startLine, endLine) {\n const terminatorRules = state.md.block.ruler.getRules(\"paragraph\");\n if (state.sCount[startLine] - state.blkIndent >= 4) {\n return false;\n }\n const oldParentType = state.parentType;\n state.parentType = \"paragraph\";\n let level = 0;\n let marker;\n let nextLine = startLine + 1;\n for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) {\n if (state.sCount[nextLine] - state.blkIndent > 3) {\n continue;\n }\n if (state.sCount[nextLine] >= state.blkIndent) {\n let pos = state.bMarks[nextLine] + state.tShift[nextLine];\n const max2 = state.eMarks[nextLine];\n if (pos < max2) {\n marker = state.src.charCodeAt(pos);\n if (marker === 45 || marker === 61) {\n pos = state.skipChars(pos, marker);\n pos = state.skipSpaces(pos);\n if (pos >= max2) {\n level = marker === 61 ? 1 : 2;\n break;\n }\n }\n }\n }\n if (state.sCount[nextLine] < 0) {\n continue;\n }\n let terminate = false;\n for (let i = 0, l = terminatorRules.length; i < l; i++) {\n if (terminatorRules[i](state, nextLine, endLine, true)) {\n terminate = true;\n break;\n }\n }\n if (terminate) {\n break;\n }\n }\n if (!level) {\n return false;\n }\n const content = state.getLines(startLine, nextLine, state.blkIndent, false).trim();\n state.line = nextLine + 1;\n const token_o = state.push(\"heading_open\", \"h\" + String(level), 1);\n token_o.markup = String.fromCharCode(marker);\n token_o.map = [startLine, state.line];\n const token_i = state.push(\"inline\", \"\", 0);\n token_i.content = content;\n token_i.map = [startLine, state.line - 1];\n token_i.children = [];\n const token_c = state.push(\"heading_close\", \"h\" + String(level), -1);\n token_c.markup = String.fromCharCode(marker);\n state.parentType = oldParentType;\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/paragraph.mjs\nfunction paragraph(state, startLine, endLine) {\n const terminatorRules = state.md.block.ruler.getRules(\"paragraph\");\n const oldParentType = state.parentType;\n let nextLine = startLine + 1;\n state.parentType = \"paragraph\";\n for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) {\n if (state.sCount[nextLine] - state.blkIndent > 3) {\n continue;\n }\n if (state.sCount[nextLine] < 0) {\n continue;\n }\n let terminate = false;\n for (let i = 0, l = terminatorRules.length; i < l; i++) {\n if (terminatorRules[i](state, nextLine, endLine, true)) {\n terminate = true;\n break;\n }\n }\n if (terminate) {\n break;\n }\n }\n const content = state.getLines(startLine, nextLine, state.blkIndent, false).trim();\n state.line = nextLine;\n const token_o = state.push(\"paragraph_open\", \"p\", 1);\n token_o.map = [startLine, state.line];\n const token_i = state.push(\"inline\", \"\", 0);\n token_i.content = content;\n token_i.map = [startLine, state.line];\n token_i.children = [];\n state.push(\"paragraph_close\", \"p\", -1);\n state.parentType = oldParentType;\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/parser_block.mjs\nvar _rules2 = [\n // First 2 params - rule name & source. Secondary array - list of rules,\n // which can be terminated by this one.\n [\"table\", table, [\"paragraph\", \"reference\"]],\n [\"code\", code],\n [\"fence\", fence, [\"paragraph\", \"reference\", \"blockquote\", \"list\"]],\n [\"blockquote\", blockquote, [\"paragraph\", \"reference\", \"blockquote\", \"list\"]],\n [\"hr\", hr, [\"paragraph\", \"reference\", \"blockquote\", \"list\"]],\n [\"list\", list, [\"paragraph\", \"reference\", \"blockquote\"]],\n [\"reference\", reference],\n [\"html_block\", html_block, [\"paragraph\", \"reference\", \"blockquote\"]],\n [\"heading\", heading, [\"paragraph\", \"reference\", \"blockquote\"]],\n [\"lheading\", lheading],\n [\"paragraph\", paragraph]\n];\nfunction ParserBlock() {\n this.ruler = new ruler_default();\n for (let i = 0; i < _rules2.length; i++) {\n this.ruler.push(_rules2[i][0], _rules2[i][1], { alt: (_rules2[i][2] || []).slice() });\n }\n}\nParserBlock.prototype.tokenize = function(state, startLine, endLine) {\n const rules = this.ruler.getRules(\"\");\n const len = rules.length;\n const maxNesting = state.md.options.maxNesting;\n let line = startLine;\n let hasEmptyLines = false;\n while (line < endLine) {\n state.line = line = state.skipEmptyLines(line);\n if (line >= endLine) {\n break;\n }\n if (state.sCount[line] < state.blkIndent) {\n break;\n }\n if (state.level >= maxNesting) {\n state.line = endLine;\n break;\n }\n const prevLine = state.line;\n let ok = false;\n for (let i = 0; i < len; i++) {\n ok = rules[i](state, line, endLine, false);\n if (ok) {\n if (prevLine >= state.line) {\n throw new Error(\"block rule didn't increment state.line\");\n }\n break;\n }\n }\n if (!ok) throw new Error(\"none of the block rules matched\");\n state.tight = !hasEmptyLines;\n if (state.isEmpty(state.line - 1)) {\n hasEmptyLines = true;\n }\n line = state.line;\n if (line < endLine && state.isEmpty(line)) {\n hasEmptyLines = true;\n line++;\n state.line = line;\n }\n }\n};\nParserBlock.prototype.parse = function(src, md, env, outTokens) {\n if (!src) {\n return;\n }\n const state = new this.State(src, md, env, outTokens);\n this.tokenize(state, state.line, state.lineMax);\n};\nParserBlock.prototype.State = state_block_default;\nvar parser_block_default = ParserBlock;\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/state_inline.mjs\nfunction StateInline(src, md, env, outTokens) {\n this.src = src;\n this.env = env;\n this.md = md;\n this.tokens = outTokens;\n this.tokens_meta = Array(outTokens.length);\n this.pos = 0;\n this.posMax = this.src.length;\n this.level = 0;\n this.pending = \"\";\n this.pendingLevel = 0;\n this.cache = {};\n this.delimiters = [];\n this._prev_delimiters = [];\n this.backticks = {};\n this.backticksScanned = false;\n this.linkLevel = 0;\n}\nStateInline.prototype.pushPending = function() {\n const token = new token_default(\"text\", \"\", 0);\n token.content = this.pending;\n token.level = this.pendingLevel;\n this.tokens.push(token);\n this.pending = \"\";\n return token;\n};\nStateInline.prototype.push = function(type, tag, nesting) {\n if (this.pending) {\n this.pushPending();\n }\n const token = new token_default(type, tag, nesting);\n let token_meta = null;\n if (nesting < 0) {\n this.level--;\n this.delimiters = this._prev_delimiters.pop();\n }\n token.level = this.level;\n if (nesting > 0) {\n this.level++;\n this._prev_delimiters.push(this.delimiters);\n this.delimiters = [];\n token_meta = { delimiters: this.delimiters };\n }\n this.pendingLevel = this.level;\n this.tokens.push(token);\n this.tokens_meta.push(token_meta);\n return token;\n};\nStateInline.prototype.scanDelims = function(start, canSplitWord) {\n const max2 = this.posMax;\n const marker = this.src.charCodeAt(start);\n const lastChar = start > 0 ? this.src.charCodeAt(start - 1) : 32;\n let pos = start;\n while (pos < max2 && this.src.charCodeAt(pos) === marker) {\n pos++;\n }\n const count = pos - start;\n const nextChar = pos < max2 ? this.src.charCodeAt(pos) : 32;\n const isLastPunctChar = isMdAsciiPunct(lastChar) || isPunctChar(String.fromCharCode(lastChar));\n const isNextPunctChar = isMdAsciiPunct(nextChar) || isPunctChar(String.fromCharCode(nextChar));\n const isLastWhiteSpace = isWhiteSpace(lastChar);\n const isNextWhiteSpace = isWhiteSpace(nextChar);\n const left_flanking = !isNextWhiteSpace && (!isNextPunctChar || isLastWhiteSpace || isLastPunctChar);\n const right_flanking = !isLastWhiteSpace && (!isLastPunctChar || isNextWhiteSpace || isNextPunctChar);\n const can_open = left_flanking && (canSplitWord || !right_flanking || isLastPunctChar);\n const can_close = right_flanking && (canSplitWord || !left_flanking || isNextPunctChar);\n return { can_open, can_close, length: count };\n};\nStateInline.prototype.Token = token_default;\nvar state_inline_default = StateInline;\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/text.mjs\nfunction isTerminatorChar(ch) {\n switch (ch) {\n case 10:\n case 33:\n case 35:\n case 36:\n case 37:\n case 38:\n case 42:\n case 43:\n case 45:\n case 58:\n case 60:\n case 61:\n case 62:\n case 64:\n case 91:\n case 92:\n case 93:\n case 94:\n case 95:\n case 96:\n case 123:\n case 125:\n case 126:\n return true;\n default:\n return false;\n }\n}\nfunction text(state, silent) {\n let pos = state.pos;\n while (pos < state.posMax && !isTerminatorChar(state.src.charCodeAt(pos))) {\n pos++;\n }\n if (pos === state.pos) {\n return false;\n }\n if (!silent) {\n state.pending += state.src.slice(state.pos, pos);\n }\n state.pos = pos;\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/linkify.mjs\nvar SCHEME_RE = /(?:^|[^a-z0-9.+-])([a-z][a-z0-9.+-]*)$/i;\nfunction linkify2(state, silent) {\n if (!state.md.options.linkify) return false;\n if (state.linkLevel > 0) return false;\n const pos = state.pos;\n const max2 = state.posMax;\n if (pos + 3 > max2) return false;\n if (state.src.charCodeAt(pos) !== 58) return false;\n if (state.src.charCodeAt(pos + 1) !== 47) return false;\n if (state.src.charCodeAt(pos + 2) !== 47) return false;\n const match2 = state.pending.match(SCHEME_RE);\n if (!match2) return false;\n const proto = match2[1];\n const link2 = state.md.linkify.matchAtStart(state.src.slice(pos - proto.length));\n if (!link2) return false;\n let url = link2.url;\n if (url.length <= proto.length) return false;\n let urlEnd = url.length;\n while (urlEnd > 0 && url.charCodeAt(urlEnd - 1) === 42) {\n urlEnd--;\n }\n if (urlEnd !== url.length) {\n url = url.slice(0, urlEnd);\n }\n const fullUrl = state.md.normalizeLink(url);\n if (!state.md.validateLink(fullUrl)) return false;\n if (!silent) {\n state.pending = state.pending.slice(0, -proto.length);\n const token_o = state.push(\"link_open\", \"a\", 1);\n token_o.attrs = [[\"href\", fullUrl]];\n token_o.markup = \"linkify\";\n token_o.info = \"auto\";\n const token_t = state.push(\"text\", \"\", 0);\n token_t.content = state.md.normalizeLinkText(url);\n const token_c = state.push(\"link_close\", \"a\", -1);\n token_c.markup = \"linkify\";\n token_c.info = \"auto\";\n }\n state.pos += url.length - proto.length;\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/newline.mjs\nfunction newline(state, silent) {\n let pos = state.pos;\n if (state.src.charCodeAt(pos) !== 10) {\n return false;\n }\n const pmax = state.pending.length - 1;\n const max2 = state.posMax;\n if (!silent) {\n if (pmax >= 0 && state.pending.charCodeAt(pmax) === 32) {\n if (pmax >= 1 && state.pending.charCodeAt(pmax - 1) === 32) {\n let ws = pmax - 1;\n while (ws >= 1 && state.pending.charCodeAt(ws - 1) === 32) ws--;\n state.pending = state.pending.slice(0, ws);\n state.push(\"hardbreak\", \"br\", 0);\n } else {\n state.pending = state.pending.slice(0, -1);\n state.push(\"softbreak\", \"br\", 0);\n }\n } else {\n state.push(\"softbreak\", \"br\", 0);\n }\n }\n pos++;\n while (pos < max2 && isSpace(state.src.charCodeAt(pos))) {\n pos++;\n }\n state.pos = pos;\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/escape.mjs\nvar ESCAPED = [];\nfor (let i = 0; i < 256; i++) {\n ESCAPED.push(0);\n}\n\"\\\\!\\\"#$%&'()*+,./:;<=>?@[]^_`{|}~-\".split(\"\").forEach(function(ch) {\n ESCAPED[ch.charCodeAt(0)] = 1;\n});\nfunction escape2(state, silent) {\n let pos = state.pos;\n const max2 = state.posMax;\n if (state.src.charCodeAt(pos) !== 92) return false;\n pos++;\n if (pos >= max2) return false;\n let ch1 = state.src.charCodeAt(pos);\n if (ch1 === 10) {\n if (!silent) {\n state.push(\"hardbreak\", \"br\", 0);\n }\n pos++;\n while (pos < max2) {\n ch1 = state.src.charCodeAt(pos);\n if (!isSpace(ch1)) break;\n pos++;\n }\n state.pos = pos;\n return true;\n }\n let escapedStr = state.src[pos];\n if (ch1 >= 55296 && ch1 <= 56319 && pos + 1 < max2) {\n const ch2 = state.src.charCodeAt(pos + 1);\n if (ch2 >= 56320 && ch2 <= 57343) {\n escapedStr += state.src[pos + 1];\n pos++;\n }\n }\n const origStr = \"\\\\\" + escapedStr;\n if (!silent) {\n const token = state.push(\"text_special\", \"\", 0);\n if (ch1 < 256 && ESCAPED[ch1] !== 0) {\n token.content = escapedStr;\n } else {\n token.content = origStr;\n }\n token.markup = origStr;\n token.info = \"escape\";\n }\n state.pos = pos + 1;\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/backticks.mjs\nfunction backtick(state, silent) {\n let pos = state.pos;\n const ch = state.src.charCodeAt(pos);\n if (ch !== 96) {\n return false;\n }\n const start = pos;\n pos++;\n const max2 = state.posMax;\n while (pos < max2 && state.src.charCodeAt(pos) === 96) {\n pos++;\n }\n const marker = state.src.slice(start, pos);\n const openerLength = marker.length;\n if (state.backticksScanned && (state.backticks[openerLength] || 0) <= start) {\n if (!silent) state.pending += marker;\n state.pos += openerLength;\n return true;\n }\n let matchEnd = pos;\n let matchStart;\n while ((matchStart = state.src.indexOf(\"`\", matchEnd)) !== -1) {\n matchEnd = matchStart + 1;\n while (matchEnd < max2 && state.src.charCodeAt(matchEnd) === 96) {\n matchEnd++;\n }\n const closerLength = matchEnd - matchStart;\n if (closerLength === openerLength) {\n if (!silent) {\n const token = state.push(\"code_inline\", \"code\", 0);\n token.markup = marker;\n token.content = state.src.slice(pos, matchStart).replace(/\\n/g, \" \").replace(/^ (.+) $/, \"$1\");\n }\n state.pos = matchEnd;\n return true;\n }\n state.backticks[closerLength] = matchStart;\n }\n state.backticksScanned = true;\n if (!silent) state.pending += marker;\n state.pos += openerLength;\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/strikethrough.mjs\nfunction strikethrough_tokenize(state, silent) {\n const start = state.pos;\n const marker = state.src.charCodeAt(start);\n if (silent) {\n return false;\n }\n if (marker !== 126) {\n return false;\n }\n const scanned = state.scanDelims(state.pos, true);\n let len = scanned.length;\n const ch = String.fromCharCode(marker);\n if (len < 2) {\n return false;\n }\n let token;\n if (len % 2) {\n token = state.push(\"text\", \"\", 0);\n token.content = ch;\n len--;\n }\n for (let i = 0; i < len; i += 2) {\n token = state.push(\"text\", \"\", 0);\n token.content = ch + ch;\n state.delimiters.push({\n marker,\n length: 0,\n // disable \"rule of 3\" length checks meant for emphasis\n token: state.tokens.length - 1,\n end: -1,\n open: scanned.can_open,\n close: scanned.can_close\n });\n }\n state.pos += scanned.length;\n return true;\n}\nfunction postProcess(state, delimiters) {\n let token;\n const loneMarkers = [];\n const max2 = delimiters.length;\n for (let i = 0; i < max2; i++) {\n const startDelim = delimiters[i];\n if (startDelim.marker !== 126) {\n continue;\n }\n if (startDelim.end === -1) {\n continue;\n }\n const endDelim = delimiters[startDelim.end];\n token = state.tokens[startDelim.token];\n token.type = \"s_open\";\n token.tag = \"s\";\n token.nesting = 1;\n token.markup = \"~~\";\n token.content = \"\";\n token = state.tokens[endDelim.token];\n token.type = \"s_close\";\n token.tag = \"s\";\n token.nesting = -1;\n token.markup = \"~~\";\n token.content = \"\";\n if (state.tokens[endDelim.token - 1].type === \"text\" && state.tokens[endDelim.token - 1].content === \"~\") {\n loneMarkers.push(endDelim.token - 1);\n }\n }\n while (loneMarkers.length) {\n const i = loneMarkers.pop();\n let j = i + 1;\n while (j < state.tokens.length && state.tokens[j].type === \"s_close\") {\n j++;\n }\n j--;\n if (i !== j) {\n token = state.tokens[j];\n state.tokens[j] = state.tokens[i];\n state.tokens[i] = token;\n }\n }\n}\nfunction strikethrough_postProcess(state) {\n const tokens_meta = state.tokens_meta;\n const max2 = state.tokens_meta.length;\n postProcess(state, state.delimiters);\n for (let curr = 0; curr < max2; curr++) {\n if (tokens_meta[curr] && tokens_meta[curr].delimiters) {\n postProcess(state, tokens_meta[curr].delimiters);\n }\n }\n}\nvar strikethrough_default = {\n tokenize: strikethrough_tokenize,\n postProcess: strikethrough_postProcess\n};\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/emphasis.mjs\nfunction emphasis_tokenize(state, silent) {\n const start = state.pos;\n const marker = state.src.charCodeAt(start);\n if (silent) {\n return false;\n }\n if (marker !== 95 && marker !== 42) {\n return false;\n }\n const scanned = state.scanDelims(state.pos, marker === 42);\n for (let i = 0; i < scanned.length; i++) {\n const token = state.push(\"text\", \"\", 0);\n token.content = String.fromCharCode(marker);\n state.delimiters.push({\n // Char code of the starting marker (number).\n //\n marker,\n // Total length of these series of delimiters.\n //\n length: scanned.length,\n // A position of the token this delimiter corresponds to.\n //\n token: state.tokens.length - 1,\n // If this delimiter is matched as a valid opener, `end` will be\n // equal to its position, otherwise it's `-1`.\n //\n end: -1,\n // Boolean flags that determine if this delimiter could open or close\n // an emphasis.\n //\n open: scanned.can_open,\n close: scanned.can_close\n });\n }\n state.pos += scanned.length;\n return true;\n}\nfunction postProcess2(state, delimiters) {\n const max2 = delimiters.length;\n for (let i = max2 - 1; i >= 0; i--) {\n const startDelim = delimiters[i];\n if (startDelim.marker !== 95 && startDelim.marker !== 42) {\n continue;\n }\n if (startDelim.end === -1) {\n continue;\n }\n const endDelim = delimiters[startDelim.end];\n const isStrong = i > 0 && delimiters[i - 1].end === startDelim.end + 1 && // check that first two markers match and adjacent\n delimiters[i - 1].marker === startDelim.marker && delimiters[i - 1].token === startDelim.token - 1 && // check that last two markers are adjacent (we can safely assume they match)\n delimiters[startDelim.end + 1].token === endDelim.token + 1;\n const ch = String.fromCharCode(startDelim.marker);\n const token_o = state.tokens[startDelim.token];\n token_o.type = isStrong ? \"strong_open\" : \"em_open\";\n token_o.tag = isStrong ? \"strong\" : \"em\";\n token_o.nesting = 1;\n token_o.markup = isStrong ? ch + ch : ch;\n token_o.content = \"\";\n const token_c = state.tokens[endDelim.token];\n token_c.type = isStrong ? \"strong_close\" : \"em_close\";\n token_c.tag = isStrong ? \"strong\" : \"em\";\n token_c.nesting = -1;\n token_c.markup = isStrong ? ch + ch : ch;\n token_c.content = \"\";\n if (isStrong) {\n state.tokens[delimiters[i - 1].token].content = \"\";\n state.tokens[delimiters[startDelim.end + 1].token].content = \"\";\n i--;\n }\n }\n}\nfunction emphasis_post_process(state) {\n const tokens_meta = state.tokens_meta;\n const max2 = state.tokens_meta.length;\n postProcess2(state, state.delimiters);\n for (let curr = 0; curr < max2; curr++) {\n if (tokens_meta[curr] && tokens_meta[curr].delimiters) {\n postProcess2(state, tokens_meta[curr].delimiters);\n }\n }\n}\nvar emphasis_default = {\n tokenize: emphasis_tokenize,\n postProcess: emphasis_post_process\n};\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/link.mjs\nfunction link(state, silent) {\n let code2, label, res, ref;\n let href = \"\";\n let title = \"\";\n let start = state.pos;\n let parseReference = true;\n if (state.src.charCodeAt(state.pos) !== 91) {\n return false;\n }\n const oldPos = state.pos;\n const max2 = state.posMax;\n const labelStart = state.pos + 1;\n const labelEnd = state.md.helpers.parseLinkLabel(state, state.pos, true);\n if (labelEnd < 0) {\n return false;\n }\n let pos = labelEnd + 1;\n if (pos < max2 && state.src.charCodeAt(pos) === 40) {\n parseReference = false;\n pos++;\n for (; pos < max2; pos++) {\n code2 = state.src.charCodeAt(pos);\n if (!isSpace(code2) && code2 !== 10) {\n break;\n }\n }\n if (pos >= max2) {\n return false;\n }\n start = pos;\n res = state.md.helpers.parseLinkDestination(state.src, pos, state.posMax);\n if (res.ok) {\n href = state.md.normalizeLink(res.str);\n if (state.md.validateLink(href)) {\n pos = res.pos;\n } else {\n href = \"\";\n }\n start = pos;\n for (; pos < max2; pos++) {\n code2 = state.src.charCodeAt(pos);\n if (!isSpace(code2) && code2 !== 10) {\n break;\n }\n }\n res = state.md.helpers.parseLinkTitle(state.src, pos, state.posMax);\n if (pos < max2 && start !== pos && res.ok) {\n title = res.str;\n pos = res.pos;\n for (; pos < max2; pos++) {\n code2 = state.src.charCodeAt(pos);\n if (!isSpace(code2) && code2 !== 10) {\n break;\n }\n }\n }\n }\n if (pos >= max2 || state.src.charCodeAt(pos) !== 41) {\n parseReference = true;\n }\n pos++;\n }\n if (parseReference) {\n if (typeof state.env.references === \"undefined\") {\n return false;\n }\n if (pos < max2 && state.src.charCodeAt(pos) === 91) {\n start = pos + 1;\n pos = state.md.helpers.parseLinkLabel(state, pos);\n if (pos >= 0) {\n label = state.src.slice(start, pos++);\n } else {\n pos = labelEnd + 1;\n }\n } else {\n pos = labelEnd + 1;\n }\n if (!label) {\n label = state.src.slice(labelStart, labelEnd);\n }\n ref = state.env.references[normalizeReference(label)];\n if (!ref) {\n state.pos = oldPos;\n return false;\n }\n href = ref.href;\n title = ref.title;\n }\n if (!silent) {\n state.pos = labelStart;\n state.posMax = labelEnd;\n const token_o = state.push(\"link_open\", \"a\", 1);\n const attrs = [[\"href\", href]];\n token_o.attrs = attrs;\n if (title) {\n attrs.push([\"title\", title]);\n }\n state.linkLevel++;\n state.md.inline.tokenize(state);\n state.linkLevel--;\n state.push(\"link_close\", \"a\", -1);\n }\n state.pos = pos;\n state.posMax = max2;\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/image.mjs\nfunction image(state, silent) {\n let code2, content, label, pos, ref, res, title, start;\n let href = \"\";\n const oldPos = state.pos;\n const max2 = state.posMax;\n if (state.src.charCodeAt(state.pos) !== 33) {\n return false;\n }\n if (state.src.charCodeAt(state.pos + 1) !== 91) {\n return false;\n }\n const labelStart = state.pos + 2;\n const labelEnd = state.md.helpers.parseLinkLabel(state, state.pos + 1, false);\n if (labelEnd < 0) {\n return false;\n }\n pos = labelEnd + 1;\n if (pos < max2 && state.src.charCodeAt(pos) === 40) {\n pos++;\n for (; pos < max2; pos++) {\n code2 = state.src.charCodeAt(pos);\n if (!isSpace(code2) && code2 !== 10) {\n break;\n }\n }\n if (pos >= max2) {\n return false;\n }\n start = pos;\n res = state.md.helpers.parseLinkDestination(state.src, pos, state.posMax);\n if (res.ok) {\n href = state.md.normalizeLink(res.str);\n if (state.md.validateLink(href)) {\n pos = res.pos;\n } else {\n href = \"\";\n }\n }\n start = pos;\n for (; pos < max2; pos++) {\n code2 = state.src.charCodeAt(pos);\n if (!isSpace(code2) && code2 !== 10) {\n break;\n }\n }\n res = state.md.helpers.parseLinkTitle(state.src, pos, state.posMax);\n if (pos < max2 && start !== pos && res.ok) {\n title = res.str;\n pos = res.pos;\n for (; pos < max2; pos++) {\n code2 = state.src.charCodeAt(pos);\n if (!isSpace(code2) && code2 !== 10) {\n break;\n }\n }\n } else {\n title = \"\";\n }\n if (pos >= max2 || state.src.charCodeAt(pos) !== 41) {\n state.pos = oldPos;\n return false;\n }\n pos++;\n } else {\n if (typeof state.env.references === \"undefined\") {\n return false;\n }\n if (pos < max2 && state.src.charCodeAt(pos) === 91) {\n start = pos + 1;\n pos = state.md.helpers.parseLinkLabel(state, pos);\n if (pos >= 0) {\n label = state.src.slice(start, pos++);\n } else {\n pos = labelEnd + 1;\n }\n } else {\n pos = labelEnd + 1;\n }\n if (!label) {\n label = state.src.slice(labelStart, labelEnd);\n }\n ref = state.env.references[normalizeReference(label)];\n if (!ref) {\n state.pos = oldPos;\n return false;\n }\n href = ref.href;\n title = ref.title;\n }\n if (!silent) {\n content = state.src.slice(labelStart, labelEnd);\n const tokens = [];\n state.md.inline.parse(\n content,\n state.md,\n state.env,\n tokens\n );\n const token = state.push(\"image\", \"img\", 0);\n const attrs = [[\"src\", href], [\"alt\", \"\"]];\n token.attrs = attrs;\n token.children = tokens;\n token.content = content;\n if (title) {\n attrs.push([\"title\", title]);\n }\n }\n state.pos = pos;\n state.posMax = max2;\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/autolink.mjs\nvar EMAIL_RE = /^([a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)$/;\nvar AUTOLINK_RE = /^([a-zA-Z][a-zA-Z0-9+.-]{1,31}):([^<>\\x00-\\x20]*)$/;\nfunction autolink(state, silent) {\n let pos = state.pos;\n if (state.src.charCodeAt(pos) !== 60) {\n return false;\n }\n const start = state.pos;\n const max2 = state.posMax;\n for (; ; ) {\n if (++pos >= max2) return false;\n const ch = state.src.charCodeAt(pos);\n if (ch === 60) return false;\n if (ch === 62) break;\n }\n const url = state.src.slice(start + 1, pos);\n if (AUTOLINK_RE.test(url)) {\n const fullUrl = state.md.normalizeLink(url);\n if (!state.md.validateLink(fullUrl)) {\n return false;\n }\n if (!silent) {\n const token_o = state.push(\"link_open\", \"a\", 1);\n token_o.attrs = [[\"href\", fullUrl]];\n token_o.markup = \"autolink\";\n token_o.info = \"auto\";\n const token_t = state.push(\"text\", \"\", 0);\n token_t.content = state.md.normalizeLinkText(url);\n const token_c = state.push(\"link_close\", \"a\", -1);\n token_c.markup = \"autolink\";\n token_c.info = \"auto\";\n }\n state.pos += url.length + 2;\n return true;\n }\n if (EMAIL_RE.test(url)) {\n const fullUrl = state.md.normalizeLink(\"mailto:\" + url);\n if (!state.md.validateLink(fullUrl)) {\n return false;\n }\n if (!silent) {\n const token_o = state.push(\"link_open\", \"a\", 1);\n token_o.attrs = [[\"href\", fullUrl]];\n token_o.markup = \"autolink\";\n token_o.info = \"auto\";\n const token_t = state.push(\"text\", \"\", 0);\n token_t.content = state.md.normalizeLinkText(url);\n const token_c = state.push(\"link_close\", \"a\", -1);\n token_c.markup = \"autolink\";\n token_c.info = \"auto\";\n }\n state.pos += url.length + 2;\n return true;\n }\n return false;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/html_inline.mjs\nfunction isLinkOpen2(str) {\n return /^\\s]/i.test(str);\n}\nfunction isLinkClose2(str) {\n return /^<\\/a\\s*>/i.test(str);\n}\nfunction isLetter(ch) {\n const lc = ch | 32;\n return lc >= 97 && lc <= 122;\n}\nfunction html_inline(state, silent) {\n if (!state.md.options.html) {\n return false;\n }\n const max2 = state.posMax;\n const pos = state.pos;\n if (state.src.charCodeAt(pos) !== 60 || pos + 2 >= max2) {\n return false;\n }\n const ch = state.src.charCodeAt(pos + 1);\n if (ch !== 33 && ch !== 63 && ch !== 47 && !isLetter(ch)) {\n return false;\n }\n const match2 = state.src.slice(pos).match(HTML_TAG_RE);\n if (!match2) {\n return false;\n }\n if (!silent) {\n const token = state.push(\"html_inline\", \"\", 0);\n token.content = match2[0];\n if (isLinkOpen2(token.content)) state.linkLevel++;\n if (isLinkClose2(token.content)) state.linkLevel--;\n }\n state.pos += match2[0].length;\n return true;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/entity.mjs\nvar DIGITAL_RE = /^&#((?:x[a-f0-9]{1,6}|[0-9]{1,7}));/i;\nvar NAMED_RE = /^&([a-z][a-z0-9]{1,31});/i;\nfunction entity(state, silent) {\n const pos = state.pos;\n const max2 = state.posMax;\n if (state.src.charCodeAt(pos) !== 38) return false;\n if (pos + 1 >= max2) return false;\n const ch = state.src.charCodeAt(pos + 1);\n if (ch === 35) {\n const match2 = state.src.slice(pos).match(DIGITAL_RE);\n if (match2) {\n if (!silent) {\n const code2 = match2[1][0].toLowerCase() === \"x\" ? parseInt(match2[1].slice(1), 16) : parseInt(match2[1], 10);\n const token = state.push(\"text_special\", \"\", 0);\n token.content = isValidEntityCode(code2) ? fromCodePoint2(code2) : fromCodePoint2(65533);\n token.markup = match2[0];\n token.info = \"entity\";\n }\n state.pos += match2[0].length;\n return true;\n }\n } else {\n const match2 = state.src.slice(pos).match(NAMED_RE);\n if (match2) {\n const decoded = decodeHTML(match2[0]);\n if (decoded !== match2[0]) {\n if (!silent) {\n const token = state.push(\"text_special\", \"\", 0);\n token.content = decoded;\n token.markup = match2[0];\n token.info = \"entity\";\n }\n state.pos += match2[0].length;\n return true;\n }\n }\n }\n return false;\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/balance_pairs.mjs\nfunction processDelimiters(delimiters) {\n const openersBottom = {};\n const max2 = delimiters.length;\n if (!max2) return;\n let headerIdx = 0;\n let lastTokenIdx = -2;\n const jumps = [];\n for (let closerIdx = 0; closerIdx < max2; closerIdx++) {\n const closer = delimiters[closerIdx];\n jumps.push(0);\n if (delimiters[headerIdx].marker !== closer.marker || lastTokenIdx !== closer.token - 1) {\n headerIdx = closerIdx;\n }\n lastTokenIdx = closer.token;\n closer.length = closer.length || 0;\n if (!closer.close) continue;\n if (!openersBottom.hasOwnProperty(closer.marker)) {\n openersBottom[closer.marker] = [-1, -1, -1, -1, -1, -1];\n }\n const minOpenerIdx = openersBottom[closer.marker][(closer.open ? 3 : 0) + closer.length % 3];\n let openerIdx = headerIdx - jumps[headerIdx] - 1;\n let newMinOpenerIdx = openerIdx;\n for (; openerIdx > minOpenerIdx; openerIdx -= jumps[openerIdx] + 1) {\n const opener = delimiters[openerIdx];\n if (opener.marker !== closer.marker) continue;\n if (opener.open && opener.end < 0) {\n let isOddMatch = false;\n if (opener.close || closer.open) {\n if ((opener.length + closer.length) % 3 === 0) {\n if (opener.length % 3 !== 0 || closer.length % 3 !== 0) {\n isOddMatch = true;\n }\n }\n }\n if (!isOddMatch) {\n const lastJump = openerIdx > 0 && !delimiters[openerIdx - 1].open ? jumps[openerIdx - 1] + 1 : 0;\n jumps[closerIdx] = closerIdx - openerIdx + lastJump;\n jumps[openerIdx] = lastJump;\n closer.open = false;\n opener.end = closerIdx;\n opener.close = false;\n newMinOpenerIdx = -1;\n lastTokenIdx = -2;\n break;\n }\n }\n }\n if (newMinOpenerIdx !== -1) {\n openersBottom[closer.marker][(closer.open ? 3 : 0) + (closer.length || 0) % 3] = newMinOpenerIdx;\n }\n }\n}\nfunction link_pairs(state) {\n const tokens_meta = state.tokens_meta;\n const max2 = state.tokens_meta.length;\n processDelimiters(state.delimiters);\n for (let curr = 0; curr < max2; curr++) {\n if (tokens_meta[curr] && tokens_meta[curr].delimiters) {\n processDelimiters(tokens_meta[curr].delimiters);\n }\n }\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/fragments_join.mjs\nfunction fragments_join(state) {\n let curr, last;\n let level = 0;\n const tokens = state.tokens;\n const max2 = state.tokens.length;\n for (curr = last = 0; curr < max2; curr++) {\n if (tokens[curr].nesting < 0) level--;\n tokens[curr].level = level;\n if (tokens[curr].nesting > 0) level++;\n if (tokens[curr].type === \"text\" && curr + 1 < max2 && tokens[curr + 1].type === \"text\") {\n tokens[curr + 1].content = tokens[curr].content + tokens[curr + 1].content;\n } else {\n if (curr !== last) {\n tokens[last] = tokens[curr];\n }\n last++;\n }\n }\n if (curr !== last) {\n tokens.length = last;\n }\n}\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/parser_inline.mjs\nvar _rules3 = [\n [\"text\", text],\n [\"linkify\", linkify2],\n [\"newline\", newline],\n [\"escape\", escape2],\n [\"backticks\", backtick],\n [\"strikethrough\", strikethrough_default.tokenize],\n [\"emphasis\", emphasis_default.tokenize],\n [\"link\", link],\n [\"image\", image],\n [\"autolink\", autolink],\n [\"html_inline\", html_inline],\n [\"entity\", entity]\n];\nvar _rules22 = [\n [\"balance_pairs\", link_pairs],\n [\"strikethrough\", strikethrough_default.postProcess],\n [\"emphasis\", emphasis_default.postProcess],\n // rules for pairs separate '**' into its own text tokens, which may be left unused,\n // rule below merges unused segments back with the rest of the text\n [\"fragments_join\", fragments_join]\n];\nfunction ParserInline() {\n this.ruler = new ruler_default();\n for (let i = 0; i < _rules3.length; i++) {\n this.ruler.push(_rules3[i][0], _rules3[i][1]);\n }\n this.ruler2 = new ruler_default();\n for (let i = 0; i < _rules22.length; i++) {\n this.ruler2.push(_rules22[i][0], _rules22[i][1]);\n }\n}\nParserInline.prototype.skipToken = function(state) {\n const pos = state.pos;\n const rules = this.ruler.getRules(\"\");\n const len = rules.length;\n const maxNesting = state.md.options.maxNesting;\n const cache = state.cache;\n if (typeof cache[pos] !== \"undefined\") {\n state.pos = cache[pos];\n return;\n }\n let ok = false;\n if (state.level < maxNesting) {\n for (let i = 0; i < len; i++) {\n state.level++;\n ok = rules[i](state, true);\n state.level--;\n if (ok) {\n if (pos >= state.pos) {\n throw new Error(\"inline rule didn't increment state.pos\");\n }\n break;\n }\n }\n } else {\n state.pos = state.posMax;\n }\n if (!ok) {\n state.pos++;\n }\n cache[pos] = state.pos;\n};\nParserInline.prototype.tokenize = function(state) {\n const rules = this.ruler.getRules(\"\");\n const len = rules.length;\n const end = state.posMax;\n const maxNesting = state.md.options.maxNesting;\n while (state.pos < end) {\n const prevPos = state.pos;\n let ok = false;\n if (state.level < maxNesting) {\n for (let i = 0; i < len; i++) {\n ok = rules[i](state, false);\n if (ok) {\n if (prevPos >= state.pos) {\n throw new Error(\"inline rule didn't increment state.pos\");\n }\n break;\n }\n }\n }\n if (ok) {\n if (state.pos >= end) {\n break;\n }\n continue;\n }\n state.pending += state.src[state.pos++];\n }\n if (state.pending) {\n state.pushPending();\n }\n};\nParserInline.prototype.parse = function(str, md, env, outTokens) {\n const state = new this.State(str, md, env, outTokens);\n this.tokenize(state);\n const rules = this.ruler2.getRules(\"\");\n const len = rules.length;\n for (let i = 0; i < len; i++) {\n rules[i](state);\n }\n};\nParserInline.prototype.State = state_inline_default;\nvar parser_inline_default = ParserInline;\n\n// node_modules/.pnpm/punycode.js@2.3.1/node_modules/punycode.js/punycode.es6.js\nvar maxInt = 2147483647;\nvar base = 36;\nvar tMin = 1;\nvar tMax = 26;\nvar skew = 38;\nvar damp = 700;\nvar initialBias = 72;\nvar initialN = 128;\nvar delimiter = \"-\";\nvar regexPunycode = /^xn--/;\nvar regexNonASCII = /[^\\0-\\x7F]/;\nvar regexSeparators = /[\\x2E\\u3002\\uFF0E\\uFF61]/g;\nvar errors = {\n \"overflow\": \"Overflow: input needs wider integers to process\",\n \"not-basic\": \"Illegal input >= 0x80 (not a basic code point)\",\n \"invalid-input\": \"Invalid input\"\n};\nvar baseMinusTMin = base - tMin;\nvar floor = Math.floor;\nvar stringFromCharCode = String.fromCharCode;\nfunction error(type) {\n throw new RangeError(errors[type]);\n}\nfunction map(array, callback) {\n const result = [];\n let length = array.length;\n while (length--) {\n result[length] = callback(array[length]);\n }\n return result;\n}\nfunction mapDomain(domain, callback) {\n const parts = domain.split(\"@\");\n let result = \"\";\n if (parts.length > 1) {\n result = parts[0] + \"@\";\n domain = parts[1];\n }\n domain = domain.replace(regexSeparators, \".\");\n const labels = domain.split(\".\");\n const encoded = map(labels, callback).join(\".\");\n return result + encoded;\n}\nfunction ucs2decode(string) {\n const output = [];\n let counter = 0;\n const length = string.length;\n while (counter < length) {\n const value = string.charCodeAt(counter++);\n if (value >= 55296 && value <= 56319 && counter < length) {\n const extra = string.charCodeAt(counter++);\n if ((extra & 64512) == 56320) {\n output.push(((value & 1023) << 10) + (extra & 1023) + 65536);\n } else {\n output.push(value);\n counter--;\n }\n } else {\n output.push(value);\n }\n }\n return output;\n}\nvar ucs2encode = (codePoints) => String.fromCodePoint(...codePoints);\nvar basicToDigit = function(codePoint) {\n if (codePoint >= 48 && codePoint < 58) {\n return 26 + (codePoint - 48);\n }\n if (codePoint >= 65 && codePoint < 91) {\n return codePoint - 65;\n }\n if (codePoint >= 97 && codePoint < 123) {\n return codePoint - 97;\n }\n return base;\n};\nvar digitToBasic = function(digit, flag) {\n return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);\n};\nvar adapt = function(delta, numPoints, firstTime) {\n let k = 0;\n delta = firstTime ? floor(delta / damp) : delta >> 1;\n delta += floor(delta / numPoints);\n for (; delta > baseMinusTMin * tMax >> 1; k += base) {\n delta = floor(delta / baseMinusTMin);\n }\n return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));\n};\nvar decode2 = function(input) {\n const output = [];\n const inputLength = input.length;\n let i = 0;\n let n = initialN;\n let bias = initialBias;\n let basic = input.lastIndexOf(delimiter);\n if (basic < 0) {\n basic = 0;\n }\n for (let j = 0; j < basic; ++j) {\n if (input.charCodeAt(j) >= 128) {\n error(\"not-basic\");\n }\n output.push(input.charCodeAt(j));\n }\n for (let index = basic > 0 ? basic + 1 : 0; index < inputLength; ) {\n const oldi = i;\n for (let w = 1, k = base; ; k += base) {\n if (index >= inputLength) {\n error(\"invalid-input\");\n }\n const digit = basicToDigit(input.charCodeAt(index++));\n if (digit >= base) {\n error(\"invalid-input\");\n }\n if (digit > floor((maxInt - i) / w)) {\n error(\"overflow\");\n }\n i += digit * w;\n const t = k <= bias ? tMin : k >= bias + tMax ? tMax : k - bias;\n if (digit < t) {\n break;\n }\n const baseMinusT = base - t;\n if (w > floor(maxInt / baseMinusT)) {\n error(\"overflow\");\n }\n w *= baseMinusT;\n }\n const out = output.length + 1;\n bias = adapt(i - oldi, out, oldi == 0);\n if (floor(i / out) > maxInt - n) {\n error(\"overflow\");\n }\n n += floor(i / out);\n i %= out;\n output.splice(i++, 0, n);\n }\n return String.fromCodePoint(...output);\n};\nvar encode2 = function(input) {\n const output = [];\n input = ucs2decode(input);\n const inputLength = input.length;\n let n = initialN;\n let delta = 0;\n let bias = initialBias;\n for (const currentValue of input) {\n if (currentValue < 128) {\n output.push(stringFromCharCode(currentValue));\n }\n }\n const basicLength = output.length;\n let handledCPCount = basicLength;\n if (basicLength) {\n output.push(delimiter);\n }\n while (handledCPCount < inputLength) {\n let m = maxInt;\n for (const currentValue of input) {\n if (currentValue >= n && currentValue < m) {\n m = currentValue;\n }\n }\n const handledCPCountPlusOne = handledCPCount + 1;\n if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {\n error(\"overflow\");\n }\n delta += (m - n) * handledCPCountPlusOne;\n n = m;\n for (const currentValue of input) {\n if (currentValue < n && ++delta > maxInt) {\n error(\"overflow\");\n }\n if (currentValue === n) {\n let q = delta;\n for (let k = base; ; k += base) {\n const t = k <= bias ? tMin : k >= bias + tMax ? tMax : k - bias;\n if (q < t) {\n break;\n }\n const qMinusT = q - t;\n const baseMinusT = base - t;\n output.push(\n stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))\n );\n q = floor(qMinusT / baseMinusT);\n }\n output.push(stringFromCharCode(digitToBasic(q, 0)));\n bias = adapt(delta, handledCPCountPlusOne, handledCPCount === basicLength);\n delta = 0;\n ++handledCPCount;\n }\n }\n ++delta;\n ++n;\n }\n return output.join(\"\");\n};\nvar toUnicode = function(input) {\n return mapDomain(input, function(string) {\n return regexPunycode.test(string) ? decode2(string.slice(4).toLowerCase()) : string;\n });\n};\nvar toASCII = function(input) {\n return mapDomain(input, function(string) {\n return regexNonASCII.test(string) ? \"xn--\" + encode2(string) : string;\n });\n};\nvar punycode = {\n /**\n * A string representing the current Punycode.js version number.\n * @memberOf punycode\n * @type String\n */\n \"version\": \"2.3.1\",\n /**\n * An object of methods to convert from JavaScript's internal character\n * representation (UCS-2) to Unicode code points, and back.\n * @see \n * @memberOf punycode\n * @type Object\n */\n \"ucs2\": {\n \"decode\": ucs2decode,\n \"encode\": ucs2encode\n },\n \"decode\": decode2,\n \"encode\": encode2,\n \"toASCII\": toASCII,\n \"toUnicode\": toUnicode\n};\nvar punycode_es6_default = punycode;\n\n// node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/presets/default.mjs\nvar default_default = {\n options: {\n // Enable HTML tags in source\n html: false,\n // Use '/' to close single tags (
)\n xhtmlOut: false,\n // Convert '\\n' in paragraphs into
\n breaks: false,\n // CSS language prefix for fenced blocks\n langPrefix: \"language-\",\n // autoconvert URL-like texts to links\n linkify: false,\n // Enable some language-neutral replacements + quotes beautification\n typographer: false,\n // Double + single quotes replacement pairs, when typographer enabled,\n // and smartquotes on. Could be either a String or an Array.\n //\n // For example, you can use '«»„“' for Russian, '„“‚‘' for German,\n // and ['«\\xA0', '\\xA0»', '‹\\xA0', '\\xA0›'] for French (including nbsp).\n quotes: \"“”‘’\",\n /* “”‘’ */\n // Highlighter function. Should return escaped HTML,\n // or '' if the source string is not changed and should be escaped externaly.\n // If result starts with )\n xhtmlOut: false,\n // Convert '\\n' in paragraphs into
\n breaks: false,\n // CSS language prefix for fenced blocks\n langPrefix: \"language-\",\n // autoconvert URL-like texts to links\n linkify: false,\n // Enable some language-neutral replacements + quotes beautification\n typographer: false,\n // Double + single quotes replacement pairs, when typographer enabled,\n // and smartquotes on. Could be either a String or an Array.\n //\n // For example, you can use '«»„“' for Russian, '„“‚‘' for German,\n // and ['«\\xA0', '\\xA0»', '‹\\xA0', '\\xA0›'] for French (including nbsp).\n quotes: \"“”‘’\",\n /* “”‘’ */\n // Highlighter function. Should return escaped HTML,\n // or '' if the source string is not changed and should be escaped externaly.\n // If result starts with )\n xhtmlOut: true,\n // Convert '\\n' in paragraphs into
\n breaks: false,\n // CSS language prefix for fenced blocks\n langPrefix: \"language-\",\n // autoconvert URL-like texts to links\n linkify: false,\n // Enable some language-neutral replacements + quotes beautification\n typographer: false,\n // Double + single quotes replacement pairs, when typographer enabled,\n // and smartquotes on. Could be either a String or an Array.\n //\n // For example, you can use '«»„“' for Russian, '„“‚‘' for German,\n // and ['«\\xA0', '\\xA0»', '‹\\xA0', '\\xA0›'] for French (including nbsp).\n quotes: \"“”‘’\",\n /* “”‘’ */\n // Highlighter function. Should return escaped HTML,\n // or '' if the source string is not changed and should be escaped externaly.\n // If result starts with = 0) {\n try {\n parsed.hostname = punycode_es6_default.toASCII(parsed.hostname);\n } catch (er) {\n }\n }\n }\n return encode_default(format(parsed));\n}\nfunction normalizeLinkText(url) {\n const parsed = parse_default(url, true);\n if (parsed.hostname) {\n if (!parsed.protocol || RECODE_HOSTNAME_FOR.indexOf(parsed.protocol) >= 0) {\n try {\n parsed.hostname = punycode_es6_default.toUnicode(parsed.hostname);\n } catch (er) {\n }\n }\n }\n return decode_default(format(parsed), decode_default.defaultChars + \"%\");\n}\nfunction MarkdownIt(presetName, options) {\n if (!(this instanceof MarkdownIt)) {\n return new MarkdownIt(presetName, options);\n }\n if (!options) {\n if (!isString2(presetName)) {\n options = presetName || {};\n presetName = \"default\";\n }\n }\n this.inline = new parser_inline_default();\n this.block = new parser_block_default();\n this.core = new parser_core_default();\n this.renderer = new renderer_default();\n this.linkify = new linkify_it_default();\n this.validateLink = validateLink;\n this.normalizeLink = normalizeLink;\n this.normalizeLinkText = normalizeLinkText;\n this.utils = utils_exports;\n this.helpers = assign2({}, helpers_exports);\n this.options = {};\n this.configure(presetName);\n if (options) {\n this.set(options);\n }\n}\nMarkdownIt.prototype.set = function(options) {\n assign2(this.options, options);\n return this;\n};\nMarkdownIt.prototype.configure = function(presets) {\n const self = this;\n if (isString2(presets)) {\n const presetName = presets;\n presets = config[presetName];\n if (!presets) {\n throw new Error('Wrong `markdown-it` preset \"' + presetName + '\", check name');\n }\n }\n if (!presets) {\n throw new Error(\"Wrong `markdown-it` preset, can't be empty\");\n }\n if (presets.options) {\n self.set(presets.options);\n }\n if (presets.components) {\n Object.keys(presets.components).forEach(function(name) {\n if (presets.components[name].rules) {\n self[name].ruler.enableOnly(presets.components[name].rules);\n }\n if (presets.components[name].rules2) {\n self[name].ruler2.enableOnly(presets.components[name].rules2);\n }\n });\n }\n return this;\n};\nMarkdownIt.prototype.enable = function(list2, ignoreInvalid) {\n let result = [];\n if (!Array.isArray(list2)) {\n list2 = [list2];\n }\n [\"core\", \"block\", \"inline\"].forEach(function(chain) {\n result = result.concat(this[chain].ruler.enable(list2, true));\n }, this);\n result = result.concat(this.inline.ruler2.enable(list2, true));\n const missed = list2.filter(function(name) {\n return result.indexOf(name) < 0;\n });\n if (missed.length && !ignoreInvalid) {\n throw new Error(\"MarkdownIt. Failed to enable unknown rule(s): \" + missed);\n }\n return this;\n};\nMarkdownIt.prototype.disable = function(list2, ignoreInvalid) {\n let result = [];\n if (!Array.isArray(list2)) {\n list2 = [list2];\n }\n [\"core\", \"block\", \"inline\"].forEach(function(chain) {\n result = result.concat(this[chain].ruler.disable(list2, true));\n }, this);\n result = result.concat(this.inline.ruler2.disable(list2, true));\n const missed = list2.filter(function(name) {\n return result.indexOf(name) < 0;\n });\n if (missed.length && !ignoreInvalid) {\n throw new Error(\"MarkdownIt. Failed to disable unknown rule(s): \" + missed);\n }\n return this;\n};\nMarkdownIt.prototype.use = function(plugin) {\n const args = [this].concat(Array.prototype.slice.call(arguments, 1));\n plugin.apply(plugin, args);\n return this;\n};\nMarkdownIt.prototype.parse = function(src, env) {\n if (typeof src !== \"string\") {\n throw new Error(\"Input data should be a String\");\n }\n const state = new this.core.State(src, this, env);\n this.core.process(state);\n return state.tokens;\n};\nMarkdownIt.prototype.render = function(src, env) {\n env = env || {};\n return this.renderer.render(this.parse(src, env), this.options, env);\n};\nMarkdownIt.prototype.parseInline = function(src, env) {\n const state = new this.core.State(src, this, env);\n state.inlineMode = true;\n this.core.process(state);\n return state.tokens;\n};\nMarkdownIt.prototype.renderInline = function(src, env) {\n env = env || {};\n return this.renderer.render(this.parseInline(src, env), this.options, env);\n};\nvar lib_default = MarkdownIt;\n\n// node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/utils.js\nfunction isBytes(a) {\n return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === \"Uint8Array\";\n}\nfunction abytes(b, ...lengths) {\n if (!isBytes(b))\n throw new Error(\"Uint8Array expected\");\n if (lengths.length > 0 && !lengths.includes(b.length))\n throw new Error(\"Uint8Array expected of length \" + lengths + \", got length=\" + b.length);\n}\nfunction aexists(instance, checkFinished = true) {\n if (instance.destroyed)\n throw new Error(\"Hash instance has been destroyed\");\n if (checkFinished && instance.finished)\n throw new Error(\"Hash#digest() has already been called\");\n}\nfunction aoutput(out, instance) {\n abytes(out);\n const min = instance.outputLen;\n if (out.length < min) {\n throw new Error(\"digestInto() expects output buffer of length at least \" + min);\n }\n}\nfunction clean(...arrays) {\n for (let i = 0; i < arrays.length; i++) {\n arrays[i].fill(0);\n }\n}\nfunction createView(arr) {\n return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);\n}\nfunction rotr(word, shift) {\n return word << 32 - shift | word >>> shift;\n}\nvar hasHexBuiltin = /* @__PURE__ */ (() => (\n // @ts-ignore\n typeof Uint8Array.from([]).toHex === \"function\" && typeof Uint8Array.fromHex === \"function\"\n))();\nvar hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, \"0\"));\nfunction bytesToHex(bytes) {\n abytes(bytes);\n if (hasHexBuiltin)\n return bytes.toHex();\n let hex = \"\";\n for (let i = 0; i < bytes.length; i++) {\n hex += hexes[bytes[i]];\n }\n return hex;\n}\nfunction utf8ToBytes(str) {\n if (typeof str !== \"string\")\n throw new Error(\"string expected\");\n return new Uint8Array(new TextEncoder().encode(str));\n}\nfunction toBytes(data) {\n if (typeof data === \"string\")\n data = utf8ToBytes(data);\n abytes(data);\n return data;\n}\nvar Hash = class {\n};\nfunction createHasher(hashCons) {\n const hashC = (msg) => hashCons().update(toBytes(msg)).digest();\n const tmp = hashCons();\n hashC.outputLen = tmp.outputLen;\n hashC.blockLen = tmp.blockLen;\n hashC.create = () => hashCons();\n return hashC;\n}\n\n// node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/_md.js\nfunction setBigUint64(view, byteOffset, value, isLE) {\n if (typeof view.setBigUint64 === \"function\")\n return view.setBigUint64(byteOffset, value, isLE);\n const _32n = BigInt(32);\n const _u32_max = BigInt(4294967295);\n const wh = Number(value >> _32n & _u32_max);\n const wl = Number(value & _u32_max);\n const h = isLE ? 4 : 0;\n const l = isLE ? 0 : 4;\n view.setUint32(byteOffset + h, wh, isLE);\n view.setUint32(byteOffset + l, wl, isLE);\n}\nfunction Chi(a, b, c) {\n return a & b ^ ~a & c;\n}\nfunction Maj(a, b, c) {\n return a & b ^ a & c ^ b & c;\n}\nvar HashMD = class extends Hash {\n constructor(blockLen, outputLen, padOffset, isLE) {\n super();\n this.finished = false;\n this.length = 0;\n this.pos = 0;\n this.destroyed = false;\n this.blockLen = blockLen;\n this.outputLen = outputLen;\n this.padOffset = padOffset;\n this.isLE = isLE;\n this.buffer = new Uint8Array(blockLen);\n this.view = createView(this.buffer);\n }\n update(data) {\n aexists(this);\n data = toBytes(data);\n abytes(data);\n const { view, buffer, blockLen } = this;\n const len = data.length;\n for (let pos = 0; pos < len; ) {\n const take = Math.min(blockLen - this.pos, len - pos);\n if (take === blockLen) {\n const dataView = createView(data);\n for (; blockLen <= len - pos; pos += blockLen)\n this.process(dataView, pos);\n continue;\n }\n buffer.set(data.subarray(pos, pos + take), this.pos);\n this.pos += take;\n pos += take;\n if (this.pos === blockLen) {\n this.process(view, 0);\n this.pos = 0;\n }\n }\n this.length += data.length;\n this.roundClean();\n return this;\n }\n digestInto(out) {\n aexists(this);\n aoutput(out, this);\n this.finished = true;\n const { buffer, view, blockLen, isLE } = this;\n let { pos } = this;\n buffer[pos++] = 128;\n clean(this.buffer.subarray(pos));\n if (this.padOffset > blockLen - pos) {\n this.process(view, 0);\n pos = 0;\n }\n for (let i = pos; i < blockLen; i++)\n buffer[i] = 0;\n setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE);\n this.process(view, 0);\n const oview = createView(out);\n const len = this.outputLen;\n if (len % 4)\n throw new Error(\"_sha2: outputLen should be aligned to 32bit\");\n const outLen = len / 4;\n const state = this.get();\n if (outLen > state.length)\n throw new Error(\"_sha2: outputLen bigger than state\");\n for (let i = 0; i < outLen; i++)\n oview.setUint32(4 * i, state[i], isLE);\n }\n digest() {\n const { buffer, outputLen } = this;\n this.digestInto(buffer);\n const res = buffer.slice(0, outputLen);\n this.destroy();\n return res;\n }\n _cloneInto(to) {\n to || (to = new this.constructor());\n to.set(...this.get());\n const { blockLen, buffer, length, finished, destroyed, pos } = this;\n to.destroyed = destroyed;\n to.finished = finished;\n to.length = length;\n to.pos = pos;\n if (length % blockLen)\n to.buffer.set(buffer);\n return to;\n }\n clone() {\n return this._cloneInto();\n }\n};\nvar SHA256_IV = /* @__PURE__ */ Uint32Array.from([\n 1779033703,\n 3144134277,\n 1013904242,\n 2773480762,\n 1359893119,\n 2600822924,\n 528734635,\n 1541459225\n]);\n\n// node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/sha2.js\nvar SHA256_K = /* @__PURE__ */ Uint32Array.from([\n 1116352408,\n 1899447441,\n 3049323471,\n 3921009573,\n 961987163,\n 1508970993,\n 2453635748,\n 2870763221,\n 3624381080,\n 310598401,\n 607225278,\n 1426881987,\n 1925078388,\n 2162078206,\n 2614888103,\n 3248222580,\n 3835390401,\n 4022224774,\n 264347078,\n 604807628,\n 770255983,\n 1249150122,\n 1555081692,\n 1996064986,\n 2554220882,\n 2821834349,\n 2952996808,\n 3210313671,\n 3336571891,\n 3584528711,\n 113926993,\n 338241895,\n 666307205,\n 773529912,\n 1294757372,\n 1396182291,\n 1695183700,\n 1986661051,\n 2177026350,\n 2456956037,\n 2730485921,\n 2820302411,\n 3259730800,\n 3345764771,\n 3516065817,\n 3600352804,\n 4094571909,\n 275423344,\n 430227734,\n 506948616,\n 659060556,\n 883997877,\n 958139571,\n 1322822218,\n 1537002063,\n 1747873779,\n 1955562222,\n 2024104815,\n 2227730452,\n 2361852424,\n 2428436474,\n 2756734187,\n 3204031479,\n 3329325298\n]);\nvar SHA256_W = /* @__PURE__ */ new Uint32Array(64);\nvar SHA256 = class extends HashMD {\n constructor(outputLen = 32) {\n super(64, outputLen, 8, false);\n this.A = SHA256_IV[0] | 0;\n this.B = SHA256_IV[1] | 0;\n this.C = SHA256_IV[2] | 0;\n this.D = SHA256_IV[3] | 0;\n this.E = SHA256_IV[4] | 0;\n this.F = SHA256_IV[5] | 0;\n this.G = SHA256_IV[6] | 0;\n this.H = SHA256_IV[7] | 0;\n }\n get() {\n const { A, B, C, D, E, F, G, H } = this;\n return [A, B, C, D, E, F, G, H];\n }\n // prettier-ignore\n set(A, B, C, D, E, F, G, H) {\n this.A = A | 0;\n this.B = B | 0;\n this.C = C | 0;\n this.D = D | 0;\n this.E = E | 0;\n this.F = F | 0;\n this.G = G | 0;\n this.H = H | 0;\n }\n process(view, offset) {\n for (let i = 0; i < 16; i++, offset += 4)\n SHA256_W[i] = view.getUint32(offset, false);\n for (let i = 16; i < 64; i++) {\n const W15 = SHA256_W[i - 15];\n const W2 = SHA256_W[i - 2];\n const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ W15 >>> 3;\n const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ W2 >>> 10;\n SHA256_W[i] = s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16] | 0;\n }\n let { A, B, C, D, E, F, G, H } = this;\n for (let i = 0; i < 64; i++) {\n const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);\n const T1 = H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i] | 0;\n const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22);\n const T2 = sigma0 + Maj(A, B, C) | 0;\n H = G;\n G = F;\n F = E;\n E = D + T1 | 0;\n D = C;\n C = B;\n B = A;\n A = T1 + T2 | 0;\n }\n A = A + this.A | 0;\n B = B + this.B | 0;\n C = C + this.C | 0;\n D = D + this.D | 0;\n E = E + this.E | 0;\n F = F + this.F | 0;\n G = G + this.G | 0;\n H = H + this.H | 0;\n this.set(A, B, C, D, E, F, G, H);\n }\n roundClean() {\n clean(SHA256_W);\n }\n destroy() {\n this.set(0, 0, 0, 0, 0, 0, 0, 0);\n clean(this.buffer);\n }\n};\nvar sha256 = /* @__PURE__ */ createHasher(() => new SHA256());\n\n// node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/sha256.js\nvar sha2562 = sha256;\n\n// apps/ecosystem-certifier/fixtures/flagship/knowledge-pack-entry.ts\nvar import_path_to_regexp = __toESM(require_dist(), 1);\nvar import_semver = __toESM(require_semver2(), 1);\n\n// node_modules/.pnpm/tinyqueue@3.0.0/node_modules/tinyqueue/index.js\nvar TinyQueue = class {\n constructor(data = [], compare = (a, b) => a < b ? -1 : a > b ? 1 : 0) {\n this.data = data;\n this.length = this.data.length;\n this.compare = compare;\n if (this.length > 0) {\n for (let i = (this.length >> 1) - 1; i >= 0; i--) this._down(i);\n }\n }\n push(item) {\n this.data.push(item);\n this._up(this.length++);\n }\n pop() {\n if (this.length === 0) return void 0;\n const top = this.data[0];\n const bottom = this.data.pop();\n if (--this.length > 0) {\n this.data[0] = bottom;\n this._down(0);\n }\n return top;\n }\n peek() {\n return this.data[0];\n }\n _up(pos) {\n const { data, compare } = this;\n const item = data[pos];\n while (pos > 0) {\n const parent = pos - 1 >> 1;\n const current = data[parent];\n if (compare(item, current) >= 0) break;\n data[pos] = current;\n pos = parent;\n }\n data[pos] = item;\n }\n _down(pos) {\n const { data, compare } = this;\n const halfLength = this.length >> 1;\n const item = data[pos];\n while (pos < halfLength) {\n let bestChild = (pos << 1) + 1;\n const right = bestChild + 1;\n if (right < this.length && compare(data[right], data[bestChild]) < 0) {\n bestChild = right;\n }\n if (compare(data[bestChild], item) >= 0) break;\n data[pos] = data[bestChild];\n pos = bestChild;\n }\n data[pos] = item;\n }\n};\n\n// apps/ecosystem-certifier/fixtures/flagship/knowledge-pack-entry.ts\nvar import_crc_32 = __toESM(require_crc32(), 1);\nvar summary;\ntry {\n const metadataText = Host.v2.document.get(\"pack/metadata.json\");\n const ruleText = Host.v2.document.get(\"rules/findings.json\");\n const compressedAttachment = Host.v2.document.get(\"pack/attachment.deflated\");\n const payload = Host.v2.document.get(\"bytes/payload\");\n const extraPayload = Host.v2.document.get(\"bytes/flagship-extra\");\n const metadata = JSON.parse(metadataText);\n const docPaths = metadata.links ?? [\"docs/a.md\", \"docs/b.md\"];\n const docs = docPaths.map((docPath) => ({\n docPath,\n text: Host.v2.document.get(docPath)\n }));\n const markdown = new lib_default({ linkify: true });\n const linkify3 = new linkify_it_default();\n const markdownSource = docs.map((doc) => doc.text).join(\"\\n\");\n const markdownTokens = markdown.parse(markdownSource, {});\n const linkMatches = docs.flatMap((doc) => linkify3.match(doc.text) ?? []).map((item) => item.url);\n const releaseChecks = (metadata.requires ?? []).map(\n (range) => import_semver.default.satisfies(metadata.release, range)\n );\n const rules = JSON.parse(ruleText);\n const findingInput = {\n linkCount: linkMatches.length,\n releaseOk: releaseChecks.every(Boolean)\n };\n const ruleInputStable = (0, import_fast_deep_equal.default)(\n findingInput,\n JSON.parse((0, import_fast_json_stable_stringify.default)(findingInput))\n );\n const rulePasses = Boolean(import_json_logic_js.default.apply(rules, findingInput));\n const queue = new TinyQueue(\n [],\n (left, right) => left.priority - right.priority\n );\n for (const link2 of linkMatches) {\n queue.push({ link: link2, priority: link2.length });\n }\n const orderedLinks = [];\n while (queue.length > 0) {\n orderedLinks.push(queue.pop().link);\n }\n const decompressed = inflateSync(compressedAttachment);\n const attachmentRoundTrip = (0, import_base64_js.toByteArray)((0, import_base64_js.fromByteArray)(decompressed));\n const mergedBinary = new Uint8Array(\n attachmentRoundTrip.length + payload.length + extraPayload.length\n );\n mergedBinary.set(attachmentRoundTrip, 0);\n mergedBinary.set(payload, attachmentRoundTrip.length);\n mergedBinary.set(extraPayload, attachmentRoundTrip.length + payload.length);\n const digestHex = bytesToHex(sha2562(mergedBinary));\n const crc32 = (import_crc_32.default.buf(mergedBinary) >>> 0).toString(16).padStart(8, \"0\");\n const decodedEntities = import_he.default.decode(\"<b>safe</b>\");\n const versionCapture = (0, import_path_to_regexp.match)(\"/document/:id/version/:version\")(\n \"/document/42/version/1.2.3\"\n );\n const orderedFindings = [\n { id: \"links\", value: linkMatches.length },\n { id: \"rules\", value: Number(rulePasses) },\n { id: \"tokens\", value: markdownTokens.length }\n ].sort((left, right) => left.id.localeCompare(right.id));\n Promise.resolve(\"scheduled\").then(() => void 0);\n queueMicrotask(() => void 0);\n for (const doc of docs) {\n Host.v2.emit({\n type: \"knowledge-pack-doc\",\n docPath: doc.docPath,\n length: doc.text.length\n });\n }\n summary = {\n status: \"ok\",\n packId: metadata.packId,\n release: metadata.release,\n checks: releaseChecks,\n docTokenCount: markdownTokens.length,\n linkCount: linkMatches.length,\n uniqueLinks: [...new Set(orderedLinks)],\n binary: {\n byteLength: mergedBinary.length,\n digestHex,\n crc32\n },\n decodedEntities,\n versionCapture,\n findings: orderedFindings,\n ruleInputStable,\n rulePasses\n };\n} catch (error2) {\n summary = {\n status: \"error\",\n message: String(error2 instanceof Error ? error2.message : error2)\n };\n}\nHost.v2.emit({\n type: \"knowledge-pack-summary\",\n summaryHash: bytesToHex(\n sha2562(\n (0, import_base64_js.toByteArray)(\n (0, import_base64_js.fromByteArray)(\n new Uint8Array([\n ...Host.v2.document.get(\"bytes/payload\"),\n ...Host.v2.document.get(\"bytes/flagship-extra\")\n ])\n )\n )\n )\n ),\n status: summary.status\n});\nvar knowledge_pack_entry_default = summary;\nexport {\n knowledge_pack_entry_default as default\n};\n", + "sourceMap": "{\"mappings\":\";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAEA,YAAQ,aAAa;AACrB,YAAQ,cAAcA;AACtB,YAAQ,gBAAgBC;AAExB,QAAI,SAAS,CAAC;AACd,QAAI,YAAY,CAAC;AACjB,QAAI,MAAM,OAAO,eAAe,cAAc,aAAa;AAE3D,QAAIC,QAAO;AACX,SAAS,IAAI,GAAG,MAAMA,MAAK,QAAQ,IAAI,KAAK,EAAE,GAAG;AAC/C,aAAO,CAAC,IAAIA,MAAK,CAAC;AAClB,gBAAUA,MAAK,WAAW,CAAC,CAAC,IAAI;AAAA,IAClC;AAHS;AAAO;AAOhB,cAAU,IAAI,WAAW,CAAC,CAAC,IAAI;AAC/B,cAAU,IAAI,WAAW,CAAC,CAAC,IAAI;AAE/B,aAAS,QAAS,KAAK;AACrB,UAAIC,OAAM,IAAI;AAEd,UAAIA,OAAM,IAAI,GAAG;AACf,cAAM,IAAI,MAAM,gDAAgD;AAAA,MAClE;AAIA,UAAI,WAAW,IAAI,QAAQ,GAAG;AAC9B,UAAI,aAAa,GAAI,YAAWA;AAEhC,UAAI,kBAAkB,aAAaA,OAC/B,IACA,IAAK,WAAW;AAEpB,aAAO,CAAC,UAAU,eAAe;AAAA,IACnC;AAGA,aAAS,WAAY,KAAK;AACxB,UAAI,OAAO,QAAQ,GAAG;AACtB,UAAI,WAAW,KAAK,CAAC;AACrB,UAAI,kBAAkB,KAAK,CAAC;AAC5B,cAAS,WAAW,mBAAmB,IAAI,IAAK;AAAA,IAClD;AAEA,aAAS,YAAa,KAAK,UAAU,iBAAiB;AACpD,cAAS,WAAW,mBAAmB,IAAI,IAAK;AAAA,IAClD;AAEA,aAASH,aAAa,KAAK;AACzB,UAAI;AACJ,UAAI,OAAO,QAAQ,GAAG;AACtB,UAAI,WAAW,KAAK,CAAC;AACrB,UAAI,kBAAkB,KAAK,CAAC;AAE5B,UAAI,MAAM,IAAI,IAAI,YAAY,KAAK,UAAU,eAAe,CAAC;AAE7D,UAAI,UAAU;AAGd,UAAIG,OAAM,kBAAkB,IACxB,WAAW,IACX;AAEJ,UAAIC;AACJ,WAAKA,KAAI,GAAGA,KAAID,MAAKC,MAAK,GAAG;AAC3B,cACG,UAAU,IAAI,WAAWA,EAAC,CAAC,KAAK,KAChC,UAAU,IAAI,WAAWA,KAAI,CAAC,CAAC,KAAK,KACpC,UAAU,IAAI,WAAWA,KAAI,CAAC,CAAC,KAAK,IACrC,UAAU,IAAI,WAAWA,KAAI,CAAC,CAAC;AACjC,YAAI,SAAS,IAAK,OAAO,KAAM;AAC/B,YAAI,SAAS,IAAK,OAAO,IAAK;AAC9B,YAAI,SAAS,IAAI,MAAM;AAAA,MACzB;AAEA,UAAI,oBAAoB,GAAG;AACzB,cACG,UAAU,IAAI,WAAWA,EAAC,CAAC,KAAK,IAChC,UAAU,IAAI,WAAWA,KAAI,CAAC,CAAC,KAAK;AACvC,YAAI,SAAS,IAAI,MAAM;AAAA,MACzB;AAEA,UAAI,oBAAoB,GAAG;AACzB,cACG,UAAU,IAAI,WAAWA,EAAC,CAAC,KAAK,KAChC,UAAU,IAAI,WAAWA,KAAI,CAAC,CAAC,KAAK,IACpC,UAAU,IAAI,WAAWA,KAAI,CAAC,CAAC,KAAK;AACvC,YAAI,SAAS,IAAK,OAAO,IAAK;AAC9B,YAAI,SAAS,IAAI,MAAM;AAAA,MACzB;AAEA,aAAO;AAAA,IACT;AAEA,aAAS,gBAAiB,KAAK;AAC7B,aAAO,OAAO,OAAO,KAAK,EAAI,IAC5B,OAAO,OAAO,KAAK,EAAI,IACvB,OAAO,OAAO,IAAI,EAAI,IACtB,OAAO,MAAM,EAAI;AAAA,IACrB;AAEA,aAAS,YAAa,OAAO,OAAO,KAAK;AACvC,UAAI;AACJ,UAAI,SAAS,CAAC;AACd,eAASA,KAAI,OAAOA,KAAI,KAAKA,MAAK,GAAG;AACnC,eACI,MAAMA,EAAC,KAAK,KAAM,aAClB,MAAMA,KAAI,CAAC,KAAK,IAAK,UACtB,MAAMA,KAAI,CAAC,IAAI;AAClB,eAAO,KAAK,gBAAgB,GAAG,CAAC;AAAA,MAClC;AACA,aAAO,OAAO,KAAK,EAAE;AAAA,IACvB;AAEA,aAASH,eAAe,OAAO;AAC7B,UAAI;AACJ,UAAIE,OAAM,MAAM;AAChB,UAAI,aAAaA,OAAM;AACvB,UAAI,QAAQ,CAAC;AACb,UAAI,iBAAiB;AAGrB,eAASC,KAAI,GAAGC,QAAOF,OAAM,YAAYC,KAAIC,OAAMD,MAAK,gBAAgB;AACtE,cAAM,KAAK,YAAY,OAAOA,IAAIA,KAAI,iBAAkBC,QAAOA,QAAQD,KAAI,cAAe,CAAC;AAAA,MAC7F;AAGA,UAAI,eAAe,GAAG;AACpB,cAAM,MAAMD,OAAM,CAAC;AACnB,cAAM;AAAA,UACJ,OAAO,OAAO,CAAC,IACf,OAAQ,OAAO,IAAK,EAAI,IACxB;AAAA,QACF;AAAA,MACF,WAAW,eAAe,GAAG;AAC3B,eAAO,MAAMA,OAAM,CAAC,KAAK,KAAK,MAAMA,OAAM,CAAC;AAC3C,cAAM;AAAA,UACJ,OAAO,OAAO,EAAE,IAChB,OAAQ,OAAO,IAAK,EAAI,IACxB,OAAQ,OAAO,IAAK,EAAI,IACxB;AAAA,QACF;AAAA,MACF;AAEA,aAAO,MAAM,KAAK,EAAE;AAAA,IACtB;AAAA;AAAA;;;ACrJA;AAAA;AAAA;AAMA,WAAO,UAAU,SAAS,MAAM,GAAG,GAAG;AACpC,UAAI,MAAM,EAAG,QAAO;AAEpB,UAAI,KAAK,KAAK,OAAO,KAAK,YAAY,OAAO,KAAK,UAAU;AAC1D,YAAI,EAAE,gBAAgB,EAAE,YAAa,QAAO;AAE5C,YAAI,QAAQ,GAAG;AACf,YAAI,MAAM,QAAQ,CAAC,GAAG;AACpB,mBAAS,EAAE;AACX,cAAI,UAAU,EAAE,OAAQ,QAAO;AAC/B,eAAK,IAAI,QAAQ,QAAQ;AACvB,gBAAI,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,EAAG,QAAO;AACjC,iBAAO;AAAA,QACT;AAIA,YAAI,EAAE,gBAAgB,OAAQ,QAAO,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE;AAC5E,YAAI,EAAE,YAAY,OAAO,UAAU,QAAS,QAAO,EAAE,QAAQ,MAAM,EAAE,QAAQ;AAC7E,YAAI,EAAE,aAAa,OAAO,UAAU,SAAU,QAAO,EAAE,SAAS,MAAM,EAAE,SAAS;AAEjF,eAAO,OAAO,KAAK,CAAC;AACpB,iBAAS,KAAK;AACd,YAAI,WAAW,OAAO,KAAK,CAAC,EAAE,OAAQ,QAAO;AAE7C,aAAK,IAAI,QAAQ,QAAQ;AACvB,cAAI,CAAC,OAAO,UAAU,eAAe,KAAK,GAAG,KAAK,CAAC,CAAC,EAAG,QAAO;AAEhE,aAAK,IAAI,QAAQ,QAAQ,KAAI;AAC3B,cAAI,MAAM,KAAK,CAAC;AAEhB,cAAI,CAAC,MAAM,EAAE,GAAG,GAAG,EAAE,GAAG,CAAC,EAAG,QAAO;AAAA,QACrC;AAEA,eAAO;AAAA,MACT;AAGA,aAAO,MAAI,KAAK,MAAI;AAAA,IACtB;AAAA;AAAA;;;AC7CA;AAAA;AAAA;AAEA,WAAO,UAAU,SAAU,MAAM,MAAM;AACnC,UAAI,CAAC,KAAM,QAAO,CAAC;AACnB,UAAI,OAAO,SAAS,WAAY,QAAO,EAAE,KAAK,KAAK;AACnD,UAAI,SAAU,OAAO,KAAK,WAAW,YAAa,KAAK,SAAS;AAEhE,UAAI,MAAM,KAAK,OAAQ,0BAAU,GAAG;AAChC,eAAO,SAAU,MAAM;AACnB,iBAAO,SAAU,GAAG,GAAG;AACnB,gBAAI,OAAO,EAAE,KAAK,GAAG,OAAO,KAAK,CAAC,EAAE;AACpC,gBAAI,OAAO,EAAE,KAAK,GAAG,OAAO,KAAK,CAAC,EAAE;AACpC,mBAAO,EAAE,MAAM,IAAI;AAAA,UACvB;AAAA,QACJ;AAAA,MACJ,GAAG,KAAK,GAAG;AAEX,UAAI,OAAO,CAAC;AACZ,cAAQ,SAAS,UAAW,MAAM;AAC9B,YAAI,QAAQ,KAAK,UAAU,OAAO,KAAK,WAAW,YAAY;AAC1D,iBAAO,KAAK,OAAO;AAAA,QACvB;AAEA,YAAI,SAAS,OAAW;AACxB,YAAI,OAAO,QAAQ,SAAU,QAAO,SAAS,IAAI,IAAI,KAAK,OAAO;AACjE,YAAI,OAAO,SAAS,SAAU,QAAO,KAAK,UAAU,IAAI;AAExD,YAAI,GAAG;AACP,YAAI,MAAM,QAAQ,IAAI,GAAG;AACrB,gBAAM;AACN,eAAK,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AAC9B,gBAAI,EAAG,QAAO;AACd,mBAAO,UAAU,KAAK,CAAC,CAAC,KAAK;AAAA,UACjC;AACA,iBAAO,MAAM;AAAA,QACjB;AAEA,YAAI,SAAS,KAAM,QAAO;AAE1B,YAAI,KAAK,QAAQ,IAAI,MAAM,IAAI;AAC3B,cAAI,OAAQ,QAAO,KAAK,UAAU,WAAW;AAC7C,gBAAM,IAAI,UAAU,uCAAuC;AAAA,QAC/D;AAEA,YAAI,YAAY,KAAK,KAAK,IAAI,IAAI;AAClC,YAAI,OAAO,OAAO,KAAK,IAAI,EAAE,KAAK,OAAO,IAAI,IAAI,CAAC;AAClD,cAAM;AACN,aAAK,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AAC9B,cAAI,MAAM,KAAK,CAAC;AAChB,cAAI,QAAQ,UAAU,KAAK,GAAG,CAAC;AAE/B,cAAI,CAAC,MAAO;AACZ,cAAI,IAAK,QAAO;AAChB,iBAAO,KAAK,UAAU,GAAG,IAAI,MAAM;AAAA,QACvC;AACA,aAAK,OAAO,WAAW,CAAC;AACxB,eAAO,MAAM,MAAM;AAAA,MACvB,GAAG,IAAI;AAAA,IACX;AAAA;AAAA;;;AC1DA;AAAA;AACC,KAAC,SAAS,MAAM;AAGhB,UAAI,cAAc,OAAO,WAAW,YAAY;AAGhD,UAAI,aAAa,OAAO,UAAU,YAAY,UAC7C,OAAO,WAAW,eAAe;AAIlC,UAAI,aAAa,OAAO,UAAU,YAAY;AAC9C,UAAI,WAAW,WAAW,cAAc,WAAW,WAAW,YAAY;AACzE,eAAO;AAAA,MACR;AAKA,UAAI,qBAAqB;AAIzB,UAAI,sBAAsB;AAI1B,UAAI,oBAAoB;AAExB,UAAI,sBAAsB;AAC1B,UAAI,YAAY,EAAC,KAAO,OAAM,KAAS,QAAO,KAAS,OAAM,KAAS,OAAM,KAAS,MAAK,KAAS,MAAK,KAAS,MAAK,KAAS,OAAM,KAAS,kBAAiB,KAAS,WAAU,KAAS,aAAY,KAAS,QAAO,KAAS,UAAS,KAAK,OAAM,MAAK,WAAU,KAAS,UAAS,KAAS,eAAc,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,QAAO,KAAS,UAAS,KAAS,QAAO,KAAS,SAAQ,KAAO,QAAO,MAAe,cAAa,KAAS,SAAQ,KAAI,UAAS,KAAS,QAAO,KAAS,SAAQ,KAAS,SAAQ,KAAS,UAAS,KAAI,SAAQ,KAAI,QAAO,KAAS,SAAQ,KAAI,SAAQ,KAAS,UAAS,KAAI,QAAO,KAAO,SAAQ,KAAI,SAAQ,KAAO,UAAS,KAAI,UAAS,KAAS,QAAO,KAAS,QAAO,KAAO,UAAS,KAAK,QAAO,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,UAAS,KAAS,UAAS,KAAI,QAAO,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAO,SAAQ,KAAO,SAAQ,KAAI,QAAO,KAAI,QAAO,KAAI,QAAO,KAAI,QAAO,KAAI,QAAO,KAAI,QAAO,KAAS,SAAQ,KAAS,SAAQ,KAAS,UAAS,KAAS,UAAS,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,WAAU,KAAS,WAAU,KAAS,WAAU,KAAS,WAAU,KAAS,SAAQ,KAAS,SAAQ,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,SAAQ,KAAS,SAAQ,KAAS,QAAO,KAAS,QAAO,KAAS,QAAO,KAAS,QAAO,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,QAAO,KAAO,QAAO,KAAO,QAAO,KAAI,UAAS,KAAI,OAAM,KAAI,OAAM,aAAY,MAAK,KAAI,OAAM,KAAI,OAAM,KAAI,UAAS,KAAS,UAAS,KAAS,WAAU,KAAS,UAAS,KAAS,UAAS,KAAS,QAAO,KAAS,UAAS,KAAS,SAAQ,KAAS,SAAQ,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,SAAQ,KAAI,SAAQ,KAAO,SAAQ,KAAS,SAAQ,KAAI,OAAM,KAAO,QAAO,KAAS,SAAQ,KAAS,OAAM,KAAO,OAAM,KAAS,QAAO,KAAS,SAAQ,KAAO,SAAQ,KAAS,QAAO,KAAS,QAAO,KAAS,SAAQ,KAAO,OAAM,KAAO,QAAO,KAAO,OAAM,KAAS,UAAS,KAAS,MAAK,KAAS,MAAK,KAAS,OAAM,KAAS,SAAQ,KAAS,QAAO,KAAS,SAAQ,KAAS,QAAO,KAAS,SAAQ,KAAS,QAAO,KAAS,QAAO,KAAS,QAAO,KAAS,SAAQ,KAAS,QAAO,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,MAAe,UAAS,KAAS,QAAO,KAAS,QAAO,KAAS,QAAO,KAAS,QAAO,KAAS,UAAS,KAAS,UAAS,KAAS,cAAa,KAAS,YAAW,KAAS,OAAM,KAAS,cAAa,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,SAAQ,KAAS,OAAM,KAAS,OAAM,KAAS,QAAO,KAAS,QAAO,KAAS,SAAQ,KAAS,UAAS,KAAS,UAAS,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,QAAO,KAAS,SAAQ,KAAS,QAAO,KAAS,QAAO,KAAS,SAAQ,KAAS,QAAO,KAAS,OAAM,KAAS,SAAQ,KAAS,QAAO,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,WAAU,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,UAAS,KAAS,QAAO,KAAS,QAAO,MAAe,SAAQ,KAAS,SAAQ,KAAS,UAAS,KAAS,SAAQ,KAAS,OAAM,KAAS,MAAK,KAAS,SAAQ,KAAS,MAAK,KAAS,SAAQ,KAAS,SAAQ,KAAS,QAAO,KAAS,UAAS,KAAS,OAAM,KAAI,QAAO,KAAO,MAAK,KAAO,OAAM,KAAO,SAAQ,KAAI,MAAK,KAAS,OAAM,MAAU,QAAO,KAAI,UAAS,KAAS,MAAK,MAAU,OAAM,KAAS,SAAQ,KAAI,MAAK,KAAS,OAAM,MAAU,QAAO,KAAO,OAAM,KAAI,QAAO,KAAO,UAAS,KAAS,SAAQ,KAAS,MAAK,KAAS,UAAS,KAAS,SAAQ,KAAS,SAAQ,KAAS,UAAS,KAAS,UAAS,KAAS,QAAO,KAAS,QAAO,KAAS,SAAQ,KAAS,SAAQ,KAAS,OAAM,MAAe,QAAO,KAAS,UAAS,KAAS,UAAS,KAAS,OAAM,KAAS,QAAO,KAAS,OAAM,KAAS,QAAO,KAAS,OAAM,KAAS,MAAK,KAAS,OAAM,MAAe,QAAO,KAAS,OAAM,MAAe,QAAO,KAAS,OAAM,KAAS,OAAM,KAAS,QAAO,KAAS,QAAO,KAAS,QAAO,KAAS,UAAS,KAAS,WAAU,KAAS,SAAQ,KAAS,YAAW,KAAS,YAAW,KAAS,UAAS,KAAS,UAAS,KAAS,SAAQ,KAAS,SAAQ,KAAS,UAAS,KAAS,SAAQ,KAAS,UAAS,KAAS,OAAM,KAAS,QAAO,MAAe,SAAQ,KAAS,QAAO,MAAe,QAAO,KAAS,MAAK,MAAe,OAAM,KAAS,OAAM,KAAS,MAAK,KAAS,QAAO,MAAe,SAAQ,KAAS,QAAO,KAAS,SAAQ,KAAS,QAAO,KAAS,SAAQ,KAAS,SAAQ,KAAS,MAAK,KAAS,OAAM,KAAS,OAAM,KAAS,QAAO,MAAe,SAAQ,KAAS,SAAQ,KAAS,UAAS,KAAS,aAAY,MAAe,QAAO,KAAS,QAAO,MAAe,SAAQ,KAAS,SAAQ,MAAe,UAAS,KAAS,SAAQ,MAAe,SAAQ,KAAS,QAAO,KAAS,SAAQ,KAAS,SAAQ,KAAS,UAAS,KAAS,UAAS,KAAS,QAAO,KAAS,QAAO,KAAS,UAAS,KAAS,SAAQ,KAAS,QAAO,KAAS,UAAS,KAAS,SAAQ,KAAS,UAAS,MAAe,WAAU,KAAS,MAAK,KAAS,OAAM,MAAe,QAAO,KAAS,MAAK,KAAS,OAAM,MAAe,QAAO,KAAS,MAAK,MAAe,OAAM,KAAS,MAAK,MAAe,OAAM,MAAe,QAAO,KAAS,OAAM,KAAS,OAAM,MAAe,QAAO,KAAS,MAAK,MAAe,QAAO,MAAe,OAAM,KAAS,MAAK,MAAe,QAAO,MAAe,OAAM,KAAS,SAAQ,KAAS,QAAO,KAAS,SAAQ,KAAS,QAAO,KAAS,SAAQ,KAAS,MAAK,KAAS,QAAO,KAAS,MAAK,KAAS,QAAO,KAAS,MAAK,KAAS,OAAM,KAAS,MAAK,KAAS,OAAM,KAAS,SAAQ,KAAS,UAAS,KAAS,SAAQ,KAAS,UAAS,KAAS,SAAQ,KAAS,SAAQ,MAAe,oBAAmB,KAAS,OAAM,KAAS,QAAO,MAAe,SAAQ,KAAS,OAAM,KAAS,QAAO,MAAe,SAAQ,KAAS,QAAO,KAAS,SAAQ,KAAS,QAAO,KAAS,SAAQ,MAAe,UAAS,KAAS,SAAQ,MAAe,UAAS,KAAS,SAAQ,KAAS,UAAS,KAAS,SAAQ,KAAS,SAAQ,MAAe,mBAAkB,KAAS,SAAQ,MAAe,qBAAoB,KAAS,UAAS,KAAS,WAAU,KAAS,UAAS,KAAS,WAAU,KAAS,SAAQ,MAAe,UAAS,KAAS,SAAQ,MAAe,UAAS,KAAS,SAAQ,KAAS,UAAS,KAAS,UAAS,KAAS,QAAO,KAAS,QAAO,KAAS,QAAO,KAAS,QAAO,KAAS,SAAQ,KAAS,SAAQ,KAAS,UAAS,KAAS,UAAS,KAAS,SAAQ,KAAS,SAAQ,KAAS,UAAS,KAAS,SAAQ,KAAS,OAAM,KAAS,OAAM,KAAS,UAAS,KAAS,SAAQ,KAAS,UAAS,KAAS,SAAQ,KAAS,UAAS,KAAS,UAAS,KAAS,SAAQ,KAAS,UAAS,KAAS,UAAS,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,UAAS,MAAe,WAAU,KAAS,SAAQ,KAAS,UAAS,MAAe,WAAU,KAAS,UAAS,KAAS,QAAO,KAAS,SAAQ,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,WAAU,KAAS,SAAQ,KAAS,SAAQ,KAAS,OAAM,KAAS,QAAO,KAAS,QAAO,KAAS,QAAO,KAAS,QAAO,KAAS,QAAO,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,OAAM,KAAS,OAAM,KAAS,OAAM,KAAS,OAAM,KAAS,QAAO,KAAS,QAAO,KAAS,SAAQ,KAAS,SAAQ,KAAS,MAAK,MAAe,OAAM,KAAS,MAAK,MAAe,OAAM,MAAe,QAAO,KAAS,OAAM,KAAS,OAAM,MAAe,QAAO,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,UAAS,KAAS,SAAQ,KAAS,WAAU,MAAe,YAAW,KAAS,WAAU,KAAS,WAAU,KAAS,SAAQ,MAAe,UAAS,KAAS,QAAO,KAAS,QAAO,KAAS,OAAM,KAAS,WAAU,KAAS,WAAU,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,QAAO,KAAS,YAAW,KAAS,YAAW,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,SAAQ,KAAS,SAAQ,KAAS,UAAS,KAAS,YAAW,KAAS,UAAS,KAAS,SAAQ,KAAS,UAAS,KAAS,WAAU,KAAS,UAAS,KAAS,UAAS,KAAS,QAAO,KAAS,QAAO,KAAS,YAAW,KAAS,mBAAkB,KAAS,oBAAmB,KAAS,aAAY,KAAS,cAAa,KAAS,YAAW,KAAS,YAAW,KAAS,SAAQ,KAAS,QAAO,KAAS,QAAO,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,QAAO,KAAS,QAAO,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,OAAM,KAAS,QAAO,KAAS,wBAAuB,KAAS,QAAO,KAAS,UAAS,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,QAAO,KAAS,SAAQ,KAAS,QAAO,KAAS,SAAQ,KAAS,SAAQ,KAAS,QAAO,KAAS,SAAQ,KAAS,QAAO,KAAS,OAAM,KAAS,OAAM,KAAS,UAAS,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,oBAAmB,KAAS,qBAAoB,KAAS,SAAQ,KAAS,QAAO,KAAS,SAAQ,KAAS,UAAS,KAAS,QAAO,KAAS,UAAS,KAAS,SAAQ,KAAS,UAAS,KAAS,SAAQ,KAAS,QAAO,KAAS,SAAQ,KAAS,SAAQ,KAAS,QAAO,KAAS,QAAO,KAAS,qBAAoB,KAAS,YAAW,KAAS,WAAU,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,QAAO,KAAS,YAAW,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,OAAM,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,YAAW,KAAS,cAAa,KAAS,gBAAe,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,WAAU,KAAS,WAAU,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,QAAO,KAAS,QAAO,KAAS,UAAS,KAAS,SAAQ,MAAe,UAAS,KAAS,WAAU,KAAS,QAAO,KAAS,QAAO,KAAS,WAAU,KAAS,UAAS,KAAS,WAAU,KAAS,WAAU,KAAS,UAAS,KAAS,WAAU,KAAS,YAAW,KAAS,YAAW,KAAS,YAAW,KAAS,mBAAkB,KAAS,qBAAoB,KAAS,uBAAsB,KAAS,oBAAmB,KAAS,iBAAgB,KAAS,kBAAiB,KAAS,oBAAmB,KAAS,sBAAqB,KAAS,qBAAoB,KAAS,sBAAqB,KAAS,mBAAkB,KAAS,qBAAoB,KAAS,iBAAgB,KAAS,kBAAiB,KAAS,oBAAmB,KAAS,sBAAqB,KAAS,qBAAoB,KAAS,sBAAqB,KAAS,mBAAkB,KAAS,qBAAoB,KAAS,QAAO,KAAS,QAAO,KAAS,QAAO,KAAS,QAAO,KAAS,WAAU,KAAS,WAAU,KAAS,WAAU,KAAS,WAAU,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,SAAQ,KAAS,SAAQ,KAAS,gBAAe,KAAS,SAAQ,KAAS,WAAU,KAAS,WAAU,KAAS,WAAU,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,WAAU,KAAS,WAAU,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,WAAU,KAAS,UAAS,KAAS,YAAW,KAAS,QAAO,KAAS,SAAQ,KAAS,WAAU,KAAS,WAAU,KAAS,YAAW,KAAS,YAAW,KAAS,YAAW,KAAS,YAAW,KAAS,YAAW,KAAS,YAAW,KAAS,YAAW,KAAS,YAAW,KAAS,WAAU,KAAS,WAAU,KAAS,WAAU,KAAS,YAAW,KAAS,YAAW,KAAS,SAAQ,KAAS,QAAO,KAAS,QAAO,KAAS,SAAQ,KAAS,WAAU,KAAS,UAAS,KAAS,SAAQ,KAAS,SAAQ,KAAS,OAAM,KAAS,OAAM,KAAS,WAAU,KAAS,QAAO,KAAS,QAAO,KAAS,SAAQ,KAAS,UAAS,KAAS,SAAQ,KAAS,YAAW,KAAS,mBAAkB,MAAe,sBAAqB,KAAS,oBAAmB,MAAe,uBAAsB,KAAS,UAAS,KAAS,YAAW,KAAS,WAAU,KAAS,UAAS,KAAS,YAAW,KAAS,YAAW,KAAS,QAAO,KAAS,eAAc,KAAS,QAAO,KAAS,SAAQ,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,YAAW,KAAS,YAAW,KAAS,SAAQ,KAAS,YAAW,KAAS,YAAW,KAAS,WAAU,KAAS,YAAW,KAAS,WAAU,KAAS,YAAW,KAAS,WAAU,KAAS,YAAW,KAAS,WAAU,KAAS,UAAS,KAAS,WAAU,KAAS,WAAU,KAAS,UAAS,KAAS,WAAU,KAAS,UAAS,KAAS,UAAS,KAAS,SAAQ,KAAS,UAAS,KAAS,YAAW,KAAS,UAAS,KAAS,WAAU,KAAS,WAAU,KAAS,YAAW,KAAS,UAAS,KAAS,QAAO,KAAS,WAAU,KAAS,YAAW,KAAS,WAAU,KAAS,SAAQ,KAAS,SAAQ,KAAS,UAAS,KAAS,QAAO,KAAS,QAAO,KAAS,UAAS,KAAS,SAAQ,KAAS,UAAS,KAAS,UAAS,KAAS,YAAW,KAAS,YAAW,KAAS,UAAS,KAAS,UAAS,KAAS,SAAQ,KAAS,SAAQ,KAAS,WAAU,KAAS,OAAM,KAAS,MAAK,KAAS,UAAS,KAAS,QAAO,KAAS,WAAU,KAAS,YAAW,KAAS,QAAO,KAAS,OAAM,KAAS,QAAO,KAAS,OAAM,KAAS,UAAS,KAAS,SAAQ,KAAS,UAAS,KAAS,WAAU,MAAe,YAAW,KAAS,UAAS,KAAS,UAAS,KAAS,OAAM,MAAe,QAAO,KAAS,SAAQ,KAAS,SAAQ,KAAS,QAAO,KAAS,SAAQ,KAAS,WAAU,KAAS,SAAQ,KAAS,SAAQ,KAAS,WAAU,KAAS,WAAU,KAAS,OAAM,MAAe,QAAO,KAAS,OAAM,MAAe,QAAO,KAAS,UAAS,KAAS,UAAS,KAAS,WAAU,KAAS,WAAU,KAAS,YAAW,KAAS,YAAW,KAAS,OAAM,KAAS,OAAM,KAAS,OAAM,KAAS,OAAM,KAAS,QAAO,KAAS,QAAO,KAAS,OAAM,KAAS,OAAM,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,OAAM,KAAS,OAAM,KAAS,UAAS,KAAS,UAAS,KAAS,OAAM,KAAS,OAAM,KAAS,UAAS,KAAS,UAAS,KAAS,MAAK,KAAS,MAAK,KAAS,QAAO,KAAS,QAAO,KAAS,SAAQ,KAAS,SAAQ,KAAS,YAAW,MAAe,qBAAoB,KAAS,kBAAiB,MAAe,2BAA0B,KAAS,OAAM,KAAS,OAAM,KAAS,QAAO,KAAS,QAAO,KAAS,SAAQ,KAAS,SAAQ,KAAS,OAAM,KAAS,OAAM,KAAS,QAAO,MAAe,SAAQ,KAAS,QAAO,MAAe,SAAQ,KAAS,SAAQ,KAAS,OAAM,MAAe,QAAO,KAAS,OAAM,MAAe,QAAO,KAAS,OAAM,KAAS,OAAM,KAAS,QAAO,KAAS,QAAO,KAAS,QAAO,KAAS,QAAO,KAAS,SAAQ,KAAS,SAAQ,KAAS,MAAK,KAAS,MAAK,KAAS,UAAS,KAAS,UAAS,KAAS,WAAU,KAAS,WAAU,KAAS,WAAU,KAAS,WAAU,KAAS,WAAU,KAAS,WAAU,KAAS,QAAO,MAAe,SAAQ,KAAS,QAAO,MAAe,SAAQ,KAAS,UAAS,KAAS,UAAS,MAAe,UAAS,KAAS,SAAQ,MAAe,UAAS,KAAS,SAAQ,KAAS,QAAO,KAAS,QAAO,KAAS,SAAQ,KAAS,SAAQ,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,WAAU,KAAS,WAAU,KAAS,SAAQ,KAAS,WAAU,KAAS,QAAO,KAAS,SAAQ,KAAS,UAAS,KAAS,QAAO,KAAS,QAAO,KAAS,SAAQ,KAAS,QAAO,KAAS,OAAM,KAAS,QAAO,KAAS,SAAQ,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,SAAQ,KAAS,UAAS,KAAS,SAAQ,MAAe,UAAS,KAAS,QAAO,KAAS,SAAQ,KAAS,SAAQ,KAAO,UAAS,KAAO,QAAO,KAAI,UAAS,KAAO,SAAQ,KAAO,OAAM,KAAS,QAAO,KAAO,QAAO,KAAO,QAAO,KAAS,UAAS,KAAO,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAO,QAAO,KAAS,UAAS,KAAS,UAAS,KAAO,QAAO,KAAO,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,MAAe,QAAO,MAAe,QAAO,MAAe,OAAM,MAAe,QAAO,MAAe,OAAM,MAAe,QAAO,KAAO,QAAO,KAAO,UAAS,KAAO,UAAS,KAAO,UAAS,KAAO,UAAS,KAAS,UAAS,KAAS,UAAS,KAAO,SAAQ,KAAO,SAAQ,KAAO,SAAQ,KAAO,SAAQ,KAAO,QAAO,KAAO,QAAO,KAAO,UAAS,KAAO,UAAS,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAO,SAAQ,KAAO,SAAQ,MAAe,QAAO,MAAe,QAAO,MAAe,OAAM,MAAe,QAAO,KAAS,QAAO,MAAe,OAAM,MAAe,OAAM,MAAe,QAAO,MAAe,QAAO,KAAS,OAAM,MAAe,QAAO,KAAS,QAAO,KAAS,UAAS,KAAS,UAAS,KAAS,SAAQ,KAAS,SAAQ,KAAS,UAAS,KAAS,UAAS,KAAS,QAAO,KAAS,QAAO,KAAO,UAAS,KAAO,UAAS,KAAS,UAAS,MAAe,OAAM,KAAS,MAAK,MAAe,QAAO,MAAe,QAAO,MAAe,QAAO,MAAe,OAAM,KAAS,MAAK,MAAe,QAAO,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAO,OAAM,KAAO,OAAM,KAAS,MAAK,KAAS,QAAO,MAAe,OAAM,MAAe,QAAO,KAAS,QAAO,MAAe,OAAM,MAAe,QAAO,KAAO,UAAS,KAAO,UAAS,KAAO,UAAS,KAAO,UAAS,KAAO,SAAQ,KAAO,SAAQ,KAAS,UAAS,KAAS,UAAS,KAAO,QAAO,KAAO,QAAO,KAAS,QAAO,KAAS,QAAO,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,MAAe,OAAM,MAAe,QAAO,MAAe,QAAO,MAAe,OAAM,MAAe,QAAO,KAAS,QAAO,KAAS,SAAQ,KAAS,UAAS,KAAS,UAAS,KAAS,SAAQ,MAAK,SAAQ,KAAS,SAAQ,KAAS,QAAO,KAAS,QAAO,MAAe,QAAO,MAAe,OAAM,MAAe,QAAO,MAAe,QAAO,MAAe,OAAM,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,SAAQ,KAAS,SAAQ,KAAS,QAAO,KAAS,QAAO,KAAS,UAAS,MAAe,OAAM,KAAS,WAAU,MAAe,QAAO,MAAe,QAAO,KAAS,QAAO,KAAS,OAAM,KAAS,QAAO,KAAS,SAAQ,KAAS,SAAQ,KAAS,QAAO,KAAS,UAAS,KAAS,UAAS,MAAe,QAAO,MAAe,OAAM,MAAe,QAAO,KAAS,MAAK,MAAe,QAAO,KAAS,QAAO,KAAS,MAAK,KAAO,UAAS,KAAO,UAAS,KAAO,UAAS,KAAO,UAAS,KAAO,SAAQ,KAAO,SAAQ,KAAO,QAAO,KAAO,QAAO,KAAS,UAAS,KAAS,UAAS,KAAS,QAAO,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,MAAe,QAAO,MAAe,QAAO,MAAe,OAAM,MAAe,QAAO,MAAe,OAAM,MAAe,QAAO,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,MAAe,QAAO,MAAe,QAAO,MAAe,OAAM,MAAe,QAAO,MAAe,QAAO,MAAe,OAAM,KAAS,UAAS,KAAS,UAAS,MAAe,OAAM,MAAe,QAAO,KAAS,OAAM,MAAe,QAAO,KAAS,QAAO,MAAe,OAAM,MAAe,QAAO,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,MAAe,OAAM,MAAe,QAAO,MAAe,QAAO,MAAe,OAAM,MAAe,QAAO,KAAS,QAAO,MAAe,OAAM,MAAe,QAAO,MAAe,QAAO,KAAS,QAAO,MAAe,QAAO,MAAe,OAAM,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAO,UAAS,KAAO,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,OAAM,KAAS,OAAM,MAAe,QAAO,MAAe,OAAM,KAAS,QAAO,MAAe,QAAO,MAAe,OAAM,MAAe,QAAO,KAAO,QAAO,KAAO,UAAS,KAAO,UAAS,KAAO,UAAS,KAAO,UAAS,KAAO,SAAQ,KAAO,SAAQ,KAAO,QAAO,KAAO,QAAO,KAAS,UAAS,KAAS,UAAS,KAAO,UAAS,KAAO,UAAS,KAAO,UAAS,KAAO,UAAS,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,MAAe,OAAM,MAAe,QAAO,MAAe,QAAO,KAAS,QAAO,MAAe,OAAM,MAAe,QAAO,MAAe,QAAO,MAAe,OAAM,MAAe,QAAO,MAAe,QAAO,MAAe,OAAM,KAAS,QAAO,KAAS,UAAS,MAAe,OAAM,MAAe,QAAO,MAAe,QAAO,KAAS,QAAO,KAAS,MAAK,KAAS,QAAO,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,MAAe,QAAO,MAAe,QAAO,MAAe,OAAM,MAAe,QAAO,MAAe,OAAM,MAAe,QAAO,KAAS,MAAK,KAAS,UAAS,KAAS,UAAS,KAAS,SAAQ,KAAS,SAAQ,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAO,SAAQ,MAAe,OAAM,MAAe,QAAO,MAAe,QAAO,MAAe,QAAO,MAAe,OAAM,MAAe,QAAO,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,SAAQ,KAAS,UAAS,KAAS,UAAS,MAAe,QAAO,MAAe,QAAO,MAAe,OAAM,MAAe,QAAO,MAAe,OAAM,MAAe,QAAO,KAAO,UAAS,KAAO,UAAS,KAAO,UAAS,KAAO,UAAS,KAAS,UAAS,KAAS,UAAS,KAAO,SAAQ,KAAO,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAO,QAAO,KAAO,QAAO,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,MAAe,OAAM,MAAe,QAAO,MAAe,QAAO,MAAe,OAAM,MAAe,QAAO,MAAe,QAAO,MAAe,QAAO,MAAe,QAAO,MAAe,OAAM,MAAe,QAAO,MAAe,QAAO,MAAe,OAAM,KAAS,SAAQ,KAAS,SAAQ,MAAe,OAAM,MAAe,QAAO,MAAe,QAAO,MAAe,QAAO,MAAe,OAAM,MAAe,QAAO,MAAe,OAAM,MAAe,QAAO,MAAe,QAAO,MAAe,QAAO,MAAe,OAAM,MAAe,QAAO,KAAO,UAAS,KAAO,UAAS,KAAS,SAAQ,KAAS,SAAQ,KAAO,QAAO,KAAS,QAAO,MAAe,QAAO,MAAe,OAAM,MAAe,QAAO,KAAS,OAAM,KAAS,QAAO,MAAe,QAAO,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,UAAS,KAAS,QAAO,KAAS,QAAO,KAAS,SAAQ,KAAO,SAAQ,KAAO,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,QAAO,KAAS,QAAO,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,SAAQ,KAAS,QAAO,KAAS,SAAQ,KAAS,WAAU,KAAS,UAAS,KAAS,UAAS,KAAS,QAAO,KAAS,QAAO,KAAS,OAAM,KAAS,OAAM,KAAS,SAAQ,KAAS,UAAS,KAAS,SAAQ,KAAS,QAAO,KAAS,QAAO,KAAS,SAAQ,KAAS,UAAS,KAAS,SAAQ,KAAS,UAAS,KAAS,UAAS,KAAS,MAAK,KAAO,SAAQ,KAAS,MAAK,KAAS,MAAK,KAAS,MAAK,KAAS,MAAK,KAAS,MAAK,KAAS,WAAU,KAAS,WAAU,KAAS,MAAK,KAAS,OAAM,KAAS,MAAK,KAAS,OAAM,KAAS,QAAO,KAAS,OAAM,KAAS,SAAQ,KAAS,SAAQ,KAAS,UAAS,KAAS,OAAM,KAAS,OAAM,KAAS,QAAO,KAAS,WAAU,KAAS,QAAO,KAAS,OAAM,KAAS,QAAO,KAAS,OAAM,KAAS,OAAM,KAAS,OAAM,KAAS,OAAM,KAAS,OAAM,KAAS,SAAQ,KAAS,OAAM,KAAS,OAAM,KAAS,OAAM,KAAS,OAAM,KAAS,OAAM,KAAS,OAAM,KAAS,OAAM,KAAS,OAAM,KAAS,OAAM,KAAS,QAAO,KAAS,QAAO,KAAS,OAAM,KAAS,OAAM,KAAS,QAAO,KAAS,QAAO,KAAS,QAAO,KAAS,QAAO,KAAS,QAAO,KAAS,QAAO,KAAS,SAAQ,KAAS,SAAQ,KAAS,QAAO,KAAS,QAAO,KAAS,OAAM,KAAS,OAAM,KAAS,QAAO,KAAS,QAAO,KAAS,OAAM,KAAS,OAAM,KAAS,SAAQ,KAAS,SAAQ,KAAS,QAAO,KAAS,QAAO,KAAS,OAAM,KAAS,OAAM,KAAS,UAAS,KAAS,UAAS,KAAS,OAAM,KAAS,OAAM,KAAS,QAAO,KAAS,QAAO,KAAS,OAAM,KAAS,OAAM,KAAS,QAAO,KAAS,QAAO,KAAS,OAAM,KAAS,OAAM,KAAS,OAAM,KAAS,OAAM,KAAS,QAAO,KAAS,QAAO,KAAS,OAAM,KAAS,OAAM,KAAS,OAAM,KAAS,OAAM,KAAS,OAAM,KAAS,OAAM,KAAS,OAAM,KAAS,OAAM,KAAS,OAAM,KAAS,OAAM,KAAS,SAAQ,KAAS,SAAQ,KAAS,OAAM,KAAS,OAAM,KAAS,SAAQ,KAAS,SAAQ,KAAS,OAAM,KAAS,OAAM,KAAS,QAAO,KAAS,QAAO,KAAS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AAE,CAAC,IAAG,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,IAAG,QAAQ,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,YAAY,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,aAAa,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,aAAa,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,G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AQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,SAAS,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,UAAU,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QA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AAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,IAAG,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,OAAO,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,GAAE,QAAQ,GAAE,CAAC,G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\",\"names\":[\"toByteArray\",\"fromByteArray\",\"code\",\"len\",\"i\",\"len2\",\"decodeMap\",\"stringFromCharCode\",\"has\",\"object\",\"key\",\"encode\",\"string\",\"decode\",\"reference\",\"escape\",\"he\",\"jsonLogic\",\"current\",\"code\",\"compile\",\"match\",\"escapeText\",\"escape\",\"text\",\"encode\",\"delimiter\",\"path\",\"value\",\"decode\",\"max\",\"match\",\"base\",\"clean\",\"list\",\"list\",\"match\",\"hr\",\"set\",\"max\",\"require_valid\",\"set\",\"max\",\"require_semver\",\"clean\",\"CRC32\",\"module\",\"table\",\"l\",\"add\",\"regex_default\",\"regex_default\",\"regex_default\",\"regex_default\",\"regex_default\",\"regex_default\",\"regex_default\",\"text\",\"match\",\"tlds\",\"list\",\"assign\",\"escapeRE\",\"fromCodePoint\",\"isString\",\"code\",\"_a\",\"CharCodes\",\"BinTrieFlags\",\"code\",\"EntityDecoderState\",\"DecodingMode\",\"errors\",\"base\",\"_a\",\"map\",\"escape\",\"match\",\"EntityLevel\",\"EncodingMode\",\"_class\",\"isString\",\"assign\",\"fromCodePoint\",\"match\",\"code\",\"entity\",\"escapeRE\",\"regex_default\",\"max\",\"max\",\"code\",\"max\",\"code\",\"assign\",\"list\",\"normalize\",\"text\",\"match\",\"text\",\"max\",\"max\",\"normalize\",\"max\",\"code\",\"max\",\"max\",\"max\",\"max\",\"max\",\"max\",\"nextLine\",\"pos\",\"max\",\"max\",\"max\",\"_rules\",\"max\",\"linkify\",\"max\",\"match\",\"link\",\"max\",\"escape\",\"max\",\"max\",\"max\",\"postProcess\",\"max\",\"code\",\"max\",\"code\",\"max\",\"max\",\"isLinkOpen\",\"isLinkClose\",\"max\",\"match\",\"max\",\"match\",\"code\",\"fromCodePoint\",\"max\",\"max\",\"_rules\",\"linkify\",\"escape\",\"_rules2\",\"decode\",\"encode\",\"isString\",\"assign\",\"list\",\"sha256\",\"linkify\",\"semver\",\"deepEqual\",\"stableStringify\",\"jsonLogic\",\"link\",\"sha256\",\"CRC32\",\"he\",\"pathMatch\",\"error\"],\"sources\":[\"../node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.js\",\"../node_modules/.pnpm/fast-deep-equal@3.1.3/node_modules/fast-deep-equal/index.js\",\"../node_modules/.pnpm/fast-json-stable-stringify@2.1.0/node_modules/fast-json-stable-stringify/index.js\",\"../node_modules/.pnpm/he@1.2.0/node_modules/he/he.js\",\"../node_modules/.pnpm/json-logic-js@2.0.5/node_modules/json-logic-js/logic.js\",\"../node_modules/.pnpm/path-to-regexp@8.3.0/node_modules/path-to-regexp/src/index.ts\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/constants.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/debug.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/re.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/parse-options.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/identifiers.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/classes/semver.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/parse.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/valid.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/clean.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/inc.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/diff.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/major.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/minor.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/patch.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/prerelease.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/compare.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/rcompare.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/compare-loose.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/compare-build.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/sort.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/rsort.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/gt.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/lt.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/eq.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/neq.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/gte.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/lte.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/cmp.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/coerce.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/lrucache.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/classes/range.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/classes/comparator.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/satisfies.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/to-comparators.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/max-satisfying.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/min-satisfying.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/min-version.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/valid.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/outside.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/gtr.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/ltr.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/intersects.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/simplify.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/subset.js\",\"../node_modules/.pnpm/semver@7.7.3/node_modules/semver/index.js\",\"../node_modules/.pnpm/crc-32@1.2.2/node_modules/crc-32/crc32.js\",\"../apps/ecosystem-certifier/fixtures/flagship/knowledge-pack-entry.ts\",\"../node_modules/.pnpm/fflate@0.8.2/node_modules/fflate/esm/browser.js\",\"../node_modules/.pnpm/uc.micro@2.1.0/node_modules/uc.micro/index.mjs\",\"../node_modules/.pnpm/uc.micro@2.1.0/node_modules/uc.micro/properties/Any/regex.mjs\",\"../node_modules/.pnpm/uc.micro@2.1.0/node_modules/uc.micro/categories/Cc/regex.mjs\",\"../node_modules/.pnpm/uc.micro@2.1.0/node_modules/uc.micro/categories/Cf/regex.mjs\",\"../node_modules/.pnpm/uc.micro@2.1.0/node_modules/uc.micro/categories/P/regex.mjs\",\"../node_modules/.pnpm/uc.micro@2.1.0/node_modules/uc.micro/categories/S/regex.mjs\",\"../node_modules/.pnpm/uc.micro@2.1.0/node_modules/uc.micro/categories/Z/regex.mjs\",\"../node_modules/.pnpm/linkify-it@5.0.0/node_modules/linkify-it/lib/re.mjs\",\"../node_modules/.pnpm/linkify-it@5.0.0/node_modules/linkify-it/index.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/common/utils.mjs\",\"../node_modules/.pnpm/mdurl@2.0.0/node_modules/mdurl/index.mjs\",\"../node_modules/.pnpm/mdurl@2.0.0/node_modules/mdurl/lib/decode.mjs\",\"../node_modules/.pnpm/mdurl@2.0.0/node_modules/mdurl/lib/encode.mjs\",\"../node_modules/.pnpm/mdurl@2.0.0/node_modules/mdurl/lib/format.mjs\",\"../node_modules/.pnpm/mdurl@2.0.0/node_modules/mdurl/lib/parse.mjs\",\"https://raw.githubusercontent.com/fb55/entities/61afd4701eaa736978b13c7351cd3de9a96b04bc/src/generated/decode-data-html.ts\",\"https://raw.githubusercontent.com/fb55/entities/61afd4701eaa736978b13c7351cd3de9a96b04bc/src/generated/decode-data-xml.ts\",\"https://raw.githubusercontent.com/fb55/entities/61afd4701eaa736978b13c7351cd3de9a96b04bc/src/decode_codepoint.ts\",\"https://raw.githubusercontent.com/fb55/entities/61afd4701eaa736978b13c7351cd3de9a96b04bc/src/decode.ts\",\"https://raw.githubusercontent.com/fb55/entities/61afd4701eaa736978b13c7351cd3de9a96b04bc/src/generated/encode-html.ts\",\"https://raw.githubusercontent.com/fb55/entities/61afd4701eaa736978b13c7351cd3de9a96b04bc/src/escape.ts\",\"https://raw.githubusercontent.com/fb55/entities/61afd4701eaa736978b13c7351cd3de9a96b04bc/src/index.ts\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/helpers/index.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/helpers/parse_link_label.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/helpers/parse_link_destination.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/helpers/parse_link_title.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/renderer.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/ruler.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/token.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_core/state_core.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_core/normalize.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_core/block.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_core/inline.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_core/linkify.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_core/replacements.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_core/smartquotes.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_core/text_join.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/parser_core.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/state_block.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/table.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/code.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/fence.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/blockquote.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/hr.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/list.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/reference.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/common/html_blocks.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/common/html_re.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/html_block.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/heading.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/lheading.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_block/paragraph.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/parser_block.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/state_inline.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/text.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/linkify.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/newline.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/escape.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/backticks.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/strikethrough.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/emphasis.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/link.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/image.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/autolink.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/html_inline.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/entity.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/balance_pairs.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/rules_inline/fragments_join.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/parser_inline.mjs\",\"../node_modules/.pnpm/punycode.js@2.3.1/node_modules/punycode.js/punycode.es6.js\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/presets/default.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/presets/zero.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/presets/commonmark.mjs\",\"../node_modules/.pnpm/markdown-it@14.1.1/node_modules/markdown-it/lib/index.mjs\",\"../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/src/utils.ts\",\"../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/src/_md.ts\",\"../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/src/sha2.ts\",\"../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/src/sha256.ts\",\"../node_modules/.pnpm/tinyqueue@3.0.0/node_modules/tinyqueue/index.js\"],\"sourcesContent\":[\"'use strict'\\n\\nexports.byteLength = byteLength\\nexports.toByteArray = toByteArray\\nexports.fromByteArray = fromByteArray\\n\\nvar lookup = []\\nvar revLookup = []\\nvar Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array\\n\\nvar code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'\\nfor (var i = 0, len = code.length; i < len; ++i) {\\n lookup[i] = code[i]\\n revLookup[code.charCodeAt(i)] = i\\n}\\n\\n// Support decoding URL-safe base64 strings, as Node.js does.\\n// See: https://en.wikipedia.org/wiki/Base64#URL_applications\\nrevLookup['-'.charCodeAt(0)] = 62\\nrevLookup['_'.charCodeAt(0)] = 63\\n\\nfunction getLens (b64) {\\n var len = b64.length\\n\\n if (len % 4 > 0) {\\n throw new Error('Invalid string. Length must be a multiple of 4')\\n }\\n\\n // Trim off extra bytes after placeholder bytes are found\\n // See: https://github.com/beatgammit/base64-js/issues/42\\n var validLen = b64.indexOf('=')\\n if (validLen === -1) validLen = len\\n\\n var placeHoldersLen = validLen === len\\n ? 0\\n : 4 - (validLen % 4)\\n\\n return [validLen, placeHoldersLen]\\n}\\n\\n// base64 is 4/3 + up to two characters of the original data\\nfunction byteLength (b64) {\\n var lens = getLens(b64)\\n var validLen = lens[0]\\n var placeHoldersLen = lens[1]\\n return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen\\n}\\n\\nfunction _byteLength (b64, validLen, placeHoldersLen) {\\n return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen\\n}\\n\\nfunction toByteArray (b64) {\\n var tmp\\n var lens = getLens(b64)\\n var validLen = lens[0]\\n var placeHoldersLen = lens[1]\\n\\n var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen))\\n\\n var curByte = 0\\n\\n // if there are placeholders, only get up to the last complete 4 chars\\n var len = placeHoldersLen > 0\\n ? validLen - 4\\n : validLen\\n\\n var i\\n for (i = 0; i < len; i += 4) {\\n tmp =\\n (revLookup[b64.charCodeAt(i)] << 18) |\\n (revLookup[b64.charCodeAt(i + 1)] << 12) |\\n (revLookup[b64.charCodeAt(i + 2)] << 6) |\\n revLookup[b64.charCodeAt(i + 3)]\\n arr[curByte++] = (tmp >> 16) & 0xFF\\n arr[curByte++] = (tmp >> 8) & 0xFF\\n arr[curByte++] = tmp & 0xFF\\n }\\n\\n if (placeHoldersLen === 2) {\\n tmp =\\n (revLookup[b64.charCodeAt(i)] << 2) |\\n (revLookup[b64.charCodeAt(i + 1)] >> 4)\\n arr[curByte++] = tmp & 0xFF\\n }\\n\\n if (placeHoldersLen === 1) {\\n tmp =\\n (revLookup[b64.charCodeAt(i)] << 10) |\\n (revLookup[b64.charCodeAt(i + 1)] << 4) |\\n (revLookup[b64.charCodeAt(i + 2)] >> 2)\\n arr[curByte++] = (tmp >> 8) & 0xFF\\n arr[curByte++] = tmp & 0xFF\\n }\\n\\n return arr\\n}\\n\\nfunction tripletToBase64 (num) {\\n return lookup[num >> 18 & 0x3F] +\\n lookup[num >> 12 & 0x3F] +\\n lookup[num >> 6 & 0x3F] +\\n lookup[num & 0x3F]\\n}\\n\\nfunction encodeChunk (uint8, start, end) {\\n var tmp\\n var output = []\\n for (var i = start; i < end; i += 3) {\\n tmp =\\n ((uint8[i] << 16) & 0xFF0000) +\\n ((uint8[i + 1] << 8) & 0xFF00) +\\n (uint8[i + 2] & 0xFF)\\n output.push(tripletToBase64(tmp))\\n }\\n return output.join('')\\n}\\n\\nfunction fromByteArray (uint8) {\\n var tmp\\n var len = uint8.length\\n var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes\\n var parts = []\\n var maxChunkLength = 16383 // must be multiple of 3\\n\\n // go through the array every three bytes, we'll deal with trailing stuff later\\n for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {\\n parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)))\\n }\\n\\n // pad the end with zeros, but make sure to not forget the extra bytes\\n if (extraBytes === 1) {\\n tmp = uint8[len - 1]\\n parts.push(\\n lookup[tmp >> 2] +\\n lookup[(tmp << 4) & 0x3F] +\\n '=='\\n )\\n } else if (extraBytes === 2) {\\n tmp = (uint8[len - 2] << 8) + uint8[len - 1]\\n parts.push(\\n lookup[tmp >> 10] +\\n lookup[(tmp >> 4) & 0x3F] +\\n lookup[(tmp << 2) & 0x3F] +\\n '='\\n )\\n }\\n\\n return parts.join('')\\n}\\n\",\"'use strict';\\n\\n// do not edit .js files directly - edit src/index.jst\\n\\n\\n\\nmodule.exports = function equal(a, b) {\\n if (a === b) return true;\\n\\n if (a && b && typeof a == 'object' && typeof b == 'object') {\\n if (a.constructor !== b.constructor) return false;\\n\\n var length, i, keys;\\n if (Array.isArray(a)) {\\n length = a.length;\\n if (length != b.length) return false;\\n for (i = length; i-- !== 0;)\\n if (!equal(a[i], b[i])) return false;\\n return true;\\n }\\n\\n\\n\\n if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;\\n if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();\\n if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();\\n\\n keys = Object.keys(a);\\n length = keys.length;\\n if (length !== Object.keys(b).length) return false;\\n\\n for (i = length; i-- !== 0;)\\n if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;\\n\\n for (i = length; i-- !== 0;) {\\n var key = keys[i];\\n\\n if (!equal(a[key], b[key])) return false;\\n }\\n\\n return true;\\n }\\n\\n // true if both NaN, false otherwise\\n return a!==a && b!==b;\\n};\\n\",\"'use strict';\\n\\nmodule.exports = function (data, opts) {\\n if (!opts) opts = {};\\n if (typeof opts === 'function') opts = { cmp: opts };\\n var cycles = (typeof opts.cycles === 'boolean') ? opts.cycles : false;\\n\\n var cmp = opts.cmp && (function (f) {\\n return function (node) {\\n return function (a, b) {\\n var aobj = { key: a, value: node[a] };\\n var bobj = { key: b, value: node[b] };\\n return f(aobj, bobj);\\n };\\n };\\n })(opts.cmp);\\n\\n var seen = [];\\n return (function stringify (node) {\\n if (node && node.toJSON && typeof node.toJSON === 'function') {\\n node = node.toJSON();\\n }\\n\\n if (node === undefined) return;\\n if (typeof node == 'number') return isFinite(node) ? '' + node : 'null';\\n if (typeof node !== 'object') return JSON.stringify(node);\\n\\n var i, out;\\n if (Array.isArray(node)) {\\n out = '[';\\n for (i = 0; i < node.length; i++) {\\n if (i) out += ',';\\n out += stringify(node[i]) || 'null';\\n }\\n return out + ']';\\n }\\n\\n if (node === null) return 'null';\\n\\n if (seen.indexOf(node) !== -1) {\\n if (cycles) return JSON.stringify('__cycle__');\\n throw new TypeError('Converting circular structure to JSON');\\n }\\n\\n var seenIndex = seen.push(node) - 1;\\n var keys = Object.keys(node).sort(cmp && cmp(node));\\n out = '';\\n for (i = 0; i < keys.length; i++) {\\n var key = keys[i];\\n var value = stringify(node[key]);\\n\\n if (!value) continue;\\n if (out) out += ',';\\n out += JSON.stringify(key) + ':' + value;\\n }\\n seen.splice(seenIndex, 1);\\n return '{' + out + '}';\\n })(data);\\n};\\n\",\"/*! https://mths.be/he v1.2.0 by @mathias | MIT license */\\n;(function(root) {\\n\\n\\t// Detect free variables `exports`.\\n\\tvar freeExports = typeof exports == 'object' && exports;\\n\\n\\t// Detect free variable `module`.\\n\\tvar freeModule = typeof module == 'object' && module &&\\n\\t\\tmodule.exports == freeExports && module;\\n\\n\\t// Detect free variable `global`, from Node.js or Browserified code,\\n\\t// and use it as `root`.\\n\\tvar freeGlobal = typeof global == 'object' && global;\\n\\tif (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {\\n\\t\\troot = freeGlobal;\\n\\t}\\n\\n\\t/*--------------------------------------------------------------------------*/\\n\\n\\t// All astral symbols.\\n\\tvar regexAstralSymbols = /[\\\\uD800-\\\\uDBFF][\\\\uDC00-\\\\uDFFF]/g;\\n\\t// All ASCII symbols (not just printable ASCII) except those listed in the\\n\\t// first column of the overrides table.\\n\\t// https://html.spec.whatwg.org/multipage/syntax.html#table-charref-overrides\\n\\tvar regexAsciiWhitelist = /[\\\\x01-\\\\x7F]/g;\\n\\t// All BMP symbols that are not ASCII newlines, printable ASCII symbols, or\\n\\t// code points listed in the first column of the overrides table on\\n\\t// https://html.spec.whatwg.org/multipage/syntax.html#table-charref-overrides.\\n\\tvar regexBmpWhitelist = /[\\\\x01-\\\\t\\\\x0B\\\\f\\\\x0E-\\\\x1F\\\\x7F\\\\x81\\\\x8D\\\\x8F\\\\x90\\\\x9D\\\\xA0-\\\\uFFFF]/g;\\n\\n\\tvar regexEncodeNonAscii = /<\\\\u20D2|=\\\\u20E5|>\\\\u20D2|\\\\u205F\\\\u200A|\\\\u219D\\\\u0338|\\\\u2202\\\\u0338|\\\\u2220\\\\u20D2|\\\\u2229\\\\uFE00|\\\\u222A\\\\uFE00|\\\\u223C\\\\u20D2|\\\\u223D\\\\u0331|\\\\u223E\\\\u0333|\\\\u2242\\\\u0338|\\\\u224B\\\\u0338|\\\\u224D\\\\u20D2|\\\\u224E\\\\u0338|\\\\u224F\\\\u0338|\\\\u2250\\\\u0338|\\\\u2261\\\\u20E5|\\\\u2264\\\\u20D2|\\\\u2265\\\\u20D2|\\\\u2266\\\\u0338|\\\\u2267\\\\u0338|\\\\u2268\\\\uFE00|\\\\u2269\\\\uFE00|\\\\u226A\\\\u0338|\\\\u226A\\\\u20D2|\\\\u226B\\\\u0338|\\\\u226B\\\\u20D2|\\\\u227F\\\\u0338|\\\\u2282\\\\u20D2|\\\\u2283\\\\u20D2|\\\\u228A\\\\uFE00|\\\\u228B\\\\uFE00|\\\\u228F\\\\u0338|\\\\u2290\\\\u0338|\\\\u2293\\\\uFE00|\\\\u2294\\\\uFE00|\\\\u22B4\\\\u20D2|\\\\u22B5\\\\u20D2|\\\\u22D8\\\\u0338|\\\\u22D9\\\\u0338|\\\\u22DA\\\\uFE00|\\\\u22DB\\\\uFE00|\\\\u22F5\\\\u0338|\\\\u22F9\\\\u0338|\\\\u2933\\\\u0338|\\\\u29CF\\\\u0338|\\\\u29D0\\\\u0338|\\\\u2A6D\\\\u0338|\\\\u2A70\\\\u0338|\\\\u2A7D\\\\u0338|\\\\u2A7E\\\\u0338|\\\\u2AA1\\\\u0338|\\\\u2AA2\\\\u0338|\\\\u2AAC\\\\uFE00|\\\\u2AAD\\\\uFE00|\\\\u2AAF\\\\u0338|\\\\u2AB0\\\\u0338|\\\\u2AC5\\\\u0338|\\\\u2AC6\\\\u0338|\\\\u2ACB\\\\uFE00|\\\\u2ACC\\\\uFE00|\\\\u2AFD\\\\u20E5|[\\\\xA0-\\\\u0113\\\\u0116-\\\\u0122\\\\u0124-\\\\u012B\\\\u012E-\\\\u014D\\\\u0150-\\\\u017E\\\\u0192\\\\u01B5\\\\u01F5\\\\u0237\\\\u02C6\\\\u02C7\\\\u02D8-\\\\u02DD\\\\u0311\\\\u0391-\\\\u03A1\\\\u03A3-\\\\u03A9\\\\u03B1-\\\\u03C9\\\\u03D1\\\\u03D2\\\\u03D5\\\\u03D6\\\\u03DC\\\\u03DD\\\\u03F0\\\\u03F1\\\\u03F5\\\\u03F6\\\\u0401-\\\\u040C\\\\u040E-\\\\u044F\\\\u0451-\\\\u045C\\\\u045E\\\\u045F\\\\u2002-\\\\u2005\\\\u2007-\\\\u2010\\\\u2013-\\\\u2016\\\\u2018-\\\\u201A\\\\u201C-\\\\u201E\\\\u2020-\\\\u2022\\\\u2025\\\\u2026\\\\u2030-\\\\u2035\\\\u2039\\\\u203A\\\\u203E\\\\u2041\\\\u2043\\\\u2044\\\\u204F\\\\u2057\\\\u205F-\\\\u2063\\\\u20AC\\\\u20DB\\\\u20DC\\\\u2102\\\\u2105\\\\u210A-\\\\u2113\\\\u2115-\\\\u211E\\\\u2122\\\\u2124\\\\u2127-\\\\u2129\\\\u212C\\\\u212D\\\\u212F-\\\\u2131\\\\u2133-\\\\u2138\\\\u2145-\\\\u2148\\\\u2153-\\\\u215E\\\\u2190-\\\\u219B\\\\u219D-\\\\u21A7\\\\u21A9-\\\\u21AE\\\\u21B0-\\\\u21B3\\\\u21B5-\\\\u21B7\\\\u21BA-\\\\u21DB\\\\u21DD\\\\u21E4\\\\u21E5\\\\u21F5\\\\u21FD-\\\\u2205\\\\u2207-\\\\u2209\\\\u220B\\\\u220C\\\\u220F-\\\\u2214\\\\u2216-\\\\u2218\\\\u221A\\\\u221D-\\\\u2238\\\\u223A-\\\\u2257\\\\u2259\\\\u225A\\\\u225C\\\\u225F-\\\\u2262\\\\u2264-\\\\u228B\\\\u228D-\\\\u229B\\\\u229D-\\\\u22A5\\\\u22A7-\\\\u22B0\\\\u22B2-\\\\u22BB\\\\u22BD-\\\\u22DB\\\\u22DE-\\\\u22E3\\\\u22E6-\\\\u22F7\\\\u22F9-\\\\u22FE\\\\u2305\\\\u2306\\\\u2308-\\\\u2310\\\\u2312\\\\u2313\\\\u2315\\\\u2316\\\\u231C-\\\\u231F\\\\u2322\\\\u2323\\\\u232D\\\\u232E\\\\u2336\\\\u233D\\\\u233F\\\\u237C\\\\u23B0\\\\u23B1\\\\u23B4-\\\\u23B6\\\\u23DC-\\\\u23DF\\\\u23E2\\\\u23E7\\\\u2423\\\\u24C8\\\\u2500\\\\u2502\\\\u250C\\\\u2510\\\\u2514\\\\u2518\\\\u251C\\\\u2524\\\\u252C\\\\u2534\\\\u253C\\\\u2550-\\\\u256C\\\\u2580\\\\u2584\\\\u2588\\\\u2591-\\\\u2593\\\\u25A1\\\\u25AA\\\\u25AB\\\\u25AD\\\\u25AE\\\\u25B1\\\\u25B3-\\\\u25B5\\\\u25B8\\\\u25B9\\\\u25BD-\\\\u25BF\\\\u25C2\\\\u25C3\\\\u25CA\\\\u25CB\\\\u25EC\\\\u25EF\\\\u25F8-\\\\u25FC\\\\u2605\\\\u2606\\\\u260E\\\\u2640\\\\u2642\\\\u2660\\\\u2663\\\\u2665\\\\u2666\\\\u266A\\\\u266D-\\\\u266F\\\\u2713\\\\u2717\\\\u2720\\\\u2736\\\\u2758\\\\u2772\\\\u2773\\\\u27C8\\\\u27C9\\\\u27E6-\\\\u27ED\\\\u27F5-\\\\u27FA\\\\u27FC\\\\u27FF\\\\u2902-\\\\u2905\\\\u290C-\\\\u2913\\\\u2916\\\\u2919-\\\\u2920\\\\u2923-\\\\u292A\\\\u2933\\\\u2935-\\\\u2939\\\\u293C\\\\u293D\\\\u2945\\\\u2948-\\\\u294B\\\\u294E-\\\\u2976\\\\u2978\\\\u2979\\\\u297B-\\\\u297F\\\\u2985\\\\u2986\\\\u298B-\\\\u2996\\\\u299A\\\\u299C\\\\u299D\\\\u29A4-\\\\u29B7\\\\u29B9\\\\u29BB\\\\u29BC\\\\u29BE-\\\\u29C5\\\\u29C9\\\\u29CD-\\\\u29D0\\\\u29DC-\\\\u29DE\\\\u29E3-\\\\u29E5\\\\u29EB\\\\u29F4\\\\u29F6\\\\u2A00-\\\\u2A02\\\\u2A04\\\\u2A06\\\\u2A0C\\\\u2A0D\\\\u2A10-\\\\u2A17\\\\u2A22-\\\\u2A27\\\\u2A29\\\\u2A2A\\\\u2A2D-\\\\u2A31\\\\u2A33-\\\\u2A3C\\\\u2A3F\\\\u2A40\\\\u2A42-\\\\u2A4D\\\\u2A50\\\\u2A53-\\\\u2A58\\\\u2A5A-\\\\u2A5D\\\\u2A5F\\\\u2A66\\\\u2A6A\\\\u2A6D-\\\\u2A75\\\\u2A77-\\\\u2A9A\\\\u2A9D-\\\\u2AA2\\\\u2AA4-\\\\u2AB0\\\\u2AB3-\\\\u2AC8\\\\u2ACB\\\\u2ACC\\\\u2ACF-\\\\u2ADB\\\\u2AE4\\\\u2AE6-\\\\u2AE9\\\\u2AEB-\\\\u2AF3\\\\u2AFD\\\\uFB00-\\\\uFB04]|\\\\uD835[\\\\uDC9C\\\\uDC9E\\\\uDC9F\\\\uDCA2\\\\uDCA5\\\\uDCA6\\\\uDCA9-\\\\uDCAC\\\\uDCAE-\\\\uDCB9\\\\uDCBB\\\\uDCBD-\\\\uDCC3\\\\uDCC5-\\\\uDCCF\\\\uDD04\\\\uDD05\\\\uDD07-\\\\uDD0A\\\\uDD0D-\\\\uDD14\\\\uDD16-\\\\uDD1C\\\\uDD1E-\\\\uDD39\\\\uDD3B-\\\\uDD3E\\\\uDD40-\\\\uDD44\\\\uDD46\\\\uDD4A-\\\\uDD50\\\\uDD52-\\\\uDD6B]/g;\\n\\tvar encodeMap = {'\\\\xAD':'shy','\\\\u200C':'zwnj','\\\\u200D':'zwj','\\\\u200E':'lrm','\\\\u2063':'ic','\\\\u2062':'it','\\\\u2061':'af','\\\\u200F':'rlm','\\\\u200B':'ZeroWidthSpace','\\\\u2060':'NoBreak','\\\\u0311':'DownBreve','\\\\u20DB':'tdot','\\\\u20DC':'DotDot','\\\\t':'Tab','\\\\n':'NewLine','\\\\u2008':'puncsp','\\\\u205F':'MediumSpace','\\\\u2009':'thinsp','\\\\u200A':'hairsp','\\\\u2004':'emsp13','\\\\u2002':'ensp','\\\\u2005':'emsp14','\\\\u2003':'emsp','\\\\u2007':'numsp','\\\\xA0':'nbsp','\\\\u205F\\\\u200A':'ThickSpace','\\\\u203E':'oline','_':'lowbar','\\\\u2010':'dash','\\\\u2013':'ndash','\\\\u2014':'mdash','\\\\u2015':'horbar',',':'comma',';':'semi','\\\\u204F':'bsemi',':':'colon','\\\\u2A74':'Colone','!':'excl','\\\\xA1':'iexcl','?':'quest','\\\\xBF':'iquest','.':'period','\\\\u2025':'nldr','\\\\u2026':'mldr','\\\\xB7':'middot','\\\\'':'apos','\\\\u2018':'lsquo','\\\\u2019':'rsquo','\\\\u201A':'sbquo','\\\\u2039':'lsaquo','\\\\u203A':'rsaquo','\\\"':'quot','\\\\u201C':'ldquo','\\\\u201D':'rdquo','\\\\u201E':'bdquo','\\\\xAB':'laquo','\\\\xBB':'raquo','(':'lpar',')':'rpar','[':'lsqb',']':'rsqb','{':'lcub','}':'rcub','\\\\u2308':'lceil','\\\\u2309':'rceil','\\\\u230A':'lfloor','\\\\u230B':'rfloor','\\\\u2985':'lopar','\\\\u2986':'ropar','\\\\u298B':'lbrke','\\\\u298C':'rbrke','\\\\u298D':'lbrkslu','\\\\u298E':'rbrksld','\\\\u298F':'lbrksld','\\\\u2990':'rbrkslu','\\\\u2991':'langd','\\\\u2992':'rangd','\\\\u2993':'lparlt','\\\\u2994':'rpargt','\\\\u2995':'gtlPar','\\\\u2996':'ltrPar','\\\\u27E6':'lobrk','\\\\u27E7':'robrk','\\\\u27E8':'lang','\\\\u27E9':'rang','\\\\u27EA':'Lang','\\\\u27EB':'Rang','\\\\u27EC':'loang','\\\\u27ED':'roang','\\\\u2772':'lbbrk','\\\\u2773':'rbbrk','\\\\u2016':'Vert','\\\\xA7':'sect','\\\\xB6':'para','@':'commat','*':'ast','/':'sol','undefined':null,'&':'amp','#':'num','%':'percnt','\\\\u2030':'permil','\\\\u2031':'pertenk','\\\\u2020':'dagger','\\\\u2021':'Dagger','\\\\u2022':'bull','\\\\u2043':'hybull','\\\\u2032':'prime','\\\\u2033':'Prime','\\\\u2034':'tprime','\\\\u2057':'qprime','\\\\u2035':'bprime','\\\\u2041':'caret','`':'grave','\\\\xB4':'acute','\\\\u02DC':'tilde','^':'Hat','\\\\xAF':'macr','\\\\u02D8':'breve','\\\\u02D9':'dot','\\\\xA8':'die','\\\\u02DA':'ring','\\\\u02DD':'dblac','\\\\xB8':'cedil','\\\\u02DB':'ogon','\\\\u02C6':'circ','\\\\u02C7':'caron','\\\\xB0':'deg','\\\\xA9':'copy','\\\\xAE':'reg','\\\\u2117':'copysr','\\\\u2118':'wp','\\\\u211E':'rx','\\\\u2127':'mho','\\\\u2129':'iiota','\\\\u2190':'larr','\\\\u219A':'nlarr','\\\\u2192':'rarr','\\\\u219B':'nrarr','\\\\u2191':'uarr','\\\\u2193':'darr','\\\\u2194':'harr','\\\\u21AE':'nharr','\\\\u2195':'varr','\\\\u2196':'nwarr','\\\\u2197':'nearr','\\\\u2198':'searr','\\\\u2199':'swarr','\\\\u219D':'rarrw','\\\\u219D\\\\u0338':'nrarrw','\\\\u219E':'Larr','\\\\u219F':'Uarr','\\\\u21A0':'Rarr','\\\\u21A1':'Darr','\\\\u21A2':'larrtl','\\\\u21A3':'rarrtl','\\\\u21A4':'mapstoleft','\\\\u21A5':'mapstoup','\\\\u21A6':'map','\\\\u21A7':'mapstodown','\\\\u21A9':'larrhk','\\\\u21AA':'rarrhk','\\\\u21AB':'larrlp','\\\\u21AC':'rarrlp','\\\\u21AD':'harrw','\\\\u21B0':'lsh','\\\\u21B1':'rsh','\\\\u21B2':'ldsh','\\\\u21B3':'rdsh','\\\\u21B5':'crarr','\\\\u21B6':'cularr','\\\\u21B7':'curarr','\\\\u21BA':'olarr','\\\\u21BB':'orarr','\\\\u21BC':'lharu','\\\\u21BD':'lhard','\\\\u21BE':'uharr','\\\\u21BF':'uharl','\\\\u21C0':'rharu','\\\\u21C1':'rhard','\\\\u21C2':'dharr','\\\\u21C3':'dharl','\\\\u21C4':'rlarr','\\\\u21C5':'udarr','\\\\u21C6':'lrarr','\\\\u21C7':'llarr','\\\\u21C8':'uuarr','\\\\u21C9':'rrarr','\\\\u21CA':'ddarr','\\\\u21CB':'lrhar','\\\\u21CC':'rlhar','\\\\u21D0':'lArr','\\\\u21CD':'nlArr','\\\\u21D1':'uArr','\\\\u21D2':'rArr','\\\\u21CF':'nrArr','\\\\u21D3':'dArr','\\\\u21D4':'iff','\\\\u21CE':'nhArr','\\\\u21D5':'vArr','\\\\u21D6':'nwArr','\\\\u21D7':'neArr','\\\\u21D8':'seArr','\\\\u21D9':'swArr','\\\\u21DA':'lAarr','\\\\u21DB':'rAarr','\\\\u21DD':'zigrarr','\\\\u21E4':'larrb','\\\\u21E5':'rarrb','\\\\u21F5':'duarr','\\\\u21FD':'loarr','\\\\u21FE':'roarr','\\\\u21FF':'hoarr','\\\\u2200':'forall','\\\\u2201':'comp','\\\\u2202':'part','\\\\u2202\\\\u0338':'npart','\\\\u2203':'exist','\\\\u2204':'nexist','\\\\u2205':'empty','\\\\u2207':'Del','\\\\u2208':'in','\\\\u2209':'notin','\\\\u220B':'ni','\\\\u220C':'notni','\\\\u03F6':'bepsi','\\\\u220F':'prod','\\\\u2210':'coprod','\\\\u2211':'sum','+':'plus','\\\\xB1':'pm','\\\\xF7':'div','\\\\xD7':'times','<':'lt','\\\\u226E':'nlt','<\\\\u20D2':'nvlt','=':'equals','\\\\u2260':'ne','=\\\\u20E5':'bne','\\\\u2A75':'Equal','>':'gt','\\\\u226F':'ngt','>\\\\u20D2':'nvgt','\\\\xAC':'not','|':'vert','\\\\xA6':'brvbar','\\\\u2212':'minus','\\\\u2213':'mp','\\\\u2214':'plusdo','\\\\u2044':'frasl','\\\\u2216':'setmn','\\\\u2217':'lowast','\\\\u2218':'compfn','\\\\u221A':'Sqrt','\\\\u221D':'prop','\\\\u221E':'infin','\\\\u221F':'angrt','\\\\u2220':'ang','\\\\u2220\\\\u20D2':'nang','\\\\u2221':'angmsd','\\\\u2222':'angsph','\\\\u2223':'mid','\\\\u2224':'nmid','\\\\u2225':'par','\\\\u2226':'npar','\\\\u2227':'and','\\\\u2228':'or','\\\\u2229':'cap','\\\\u2229\\\\uFE00':'caps','\\\\u222A':'cup','\\\\u222A\\\\uFE00':'cups','\\\\u222B':'int','\\\\u222C':'Int','\\\\u222D':'tint','\\\\u2A0C':'qint','\\\\u222E':'oint','\\\\u222F':'Conint','\\\\u2230':'Cconint','\\\\u2231':'cwint','\\\\u2232':'cwconint','\\\\u2233':'awconint','\\\\u2234':'there4','\\\\u2235':'becaus','\\\\u2236':'ratio','\\\\u2237':'Colon','\\\\u2238':'minusd','\\\\u223A':'mDDot','\\\\u223B':'homtht','\\\\u223C':'sim','\\\\u2241':'nsim','\\\\u223C\\\\u20D2':'nvsim','\\\\u223D':'bsim','\\\\u223D\\\\u0331':'race','\\\\u223E':'ac','\\\\u223E\\\\u0333':'acE','\\\\u223F':'acd','\\\\u2240':'wr','\\\\u2242':'esim','\\\\u2242\\\\u0338':'nesim','\\\\u2243':'sime','\\\\u2244':'nsime','\\\\u2245':'cong','\\\\u2247':'ncong','\\\\u2246':'simne','\\\\u2248':'ap','\\\\u2249':'nap','\\\\u224A':'ape','\\\\u224B':'apid','\\\\u224B\\\\u0338':'napid','\\\\u224C':'bcong','\\\\u224D':'CupCap','\\\\u226D':'NotCupCap','\\\\u224D\\\\u20D2':'nvap','\\\\u224E':'bump','\\\\u224E\\\\u0338':'nbump','\\\\u224F':'bumpe','\\\\u224F\\\\u0338':'nbumpe','\\\\u2250':'doteq','\\\\u2250\\\\u0338':'nedot','\\\\u2251':'eDot','\\\\u2252':'efDot','\\\\u2253':'erDot','\\\\u2254':'colone','\\\\u2255':'ecolon','\\\\u2256':'ecir','\\\\u2257':'cire','\\\\u2259':'wedgeq','\\\\u225A':'veeeq','\\\\u225C':'trie','\\\\u225F':'equest','\\\\u2261':'equiv','\\\\u2262':'nequiv','\\\\u2261\\\\u20E5':'bnequiv','\\\\u2264':'le','\\\\u2270':'nle','\\\\u2264\\\\u20D2':'nvle','\\\\u2265':'ge','\\\\u2271':'nge','\\\\u2265\\\\u20D2':'nvge','\\\\u2266':'lE','\\\\u2266\\\\u0338':'nlE','\\\\u2267':'gE','\\\\u2267\\\\u0338':'ngE','\\\\u2268\\\\uFE00':'lvnE','\\\\u2268':'lnE','\\\\u2269':'gnE','\\\\u2269\\\\uFE00':'gvnE','\\\\u226A':'ll','\\\\u226A\\\\u0338':'nLtv','\\\\u226A\\\\u20D2':'nLt','\\\\u226B':'gg','\\\\u226B\\\\u0338':'nGtv','\\\\u226B\\\\u20D2':'nGt','\\\\u226C':'twixt','\\\\u2272':'lsim','\\\\u2274':'nlsim','\\\\u2273':'gsim','\\\\u2275':'ngsim','\\\\u2276':'lg','\\\\u2278':'ntlg','\\\\u2277':'gl','\\\\u2279':'ntgl','\\\\u227A':'pr','\\\\u2280':'npr','\\\\u227B':'sc','\\\\u2281':'nsc','\\\\u227C':'prcue','\\\\u22E0':'nprcue','\\\\u227D':'sccue','\\\\u22E1':'nsccue','\\\\u227E':'prsim','\\\\u227F':'scsim','\\\\u227F\\\\u0338':'NotSucceedsTilde','\\\\u2282':'sub','\\\\u2284':'nsub','\\\\u2282\\\\u20D2':'vnsub','\\\\u2283':'sup','\\\\u2285':'nsup','\\\\u2283\\\\u20D2':'vnsup','\\\\u2286':'sube','\\\\u2288':'nsube','\\\\u2287':'supe','\\\\u2289':'nsupe','\\\\u228A\\\\uFE00':'vsubne','\\\\u228A':'subne','\\\\u228B\\\\uFE00':'vsupne','\\\\u228B':'supne','\\\\u228D':'cupdot','\\\\u228E':'uplus','\\\\u228F':'sqsub','\\\\u228F\\\\u0338':'NotSquareSubset','\\\\u2290':'sqsup','\\\\u2290\\\\u0338':'NotSquareSuperset','\\\\u2291':'sqsube','\\\\u22E2':'nsqsube','\\\\u2292':'sqsupe','\\\\u22E3':'nsqsupe','\\\\u2293':'sqcap','\\\\u2293\\\\uFE00':'sqcaps','\\\\u2294':'sqcup','\\\\u2294\\\\uFE00':'sqcups','\\\\u2295':'oplus','\\\\u2296':'ominus','\\\\u2297':'otimes','\\\\u2298':'osol','\\\\u2299':'odot','\\\\u229A':'ocir','\\\\u229B':'oast','\\\\u229D':'odash','\\\\u229E':'plusb','\\\\u229F':'minusb','\\\\u22A0':'timesb','\\\\u22A1':'sdotb','\\\\u22A2':'vdash','\\\\u22AC':'nvdash','\\\\u22A3':'dashv','\\\\u22A4':'top','\\\\u22A5':'bot','\\\\u22A7':'models','\\\\u22A8':'vDash','\\\\u22AD':'nvDash','\\\\u22A9':'Vdash','\\\\u22AE':'nVdash','\\\\u22AA':'Vvdash','\\\\u22AB':'VDash','\\\\u22AF':'nVDash','\\\\u22B0':'prurel','\\\\u22B2':'vltri','\\\\u22EA':'nltri','\\\\u22B3':'vrtri','\\\\u22EB':'nrtri','\\\\u22B4':'ltrie','\\\\u22EC':'nltrie','\\\\u22B4\\\\u20D2':'nvltrie','\\\\u22B5':'rtrie','\\\\u22ED':'nrtrie','\\\\u22B5\\\\u20D2':'nvrtrie','\\\\u22B6':'origof','\\\\u22B7':'imof','\\\\u22B8':'mumap','\\\\u22B9':'hercon','\\\\u22BA':'intcal','\\\\u22BB':'veebar','\\\\u22BD':'barvee','\\\\u22BE':'angrtvb','\\\\u22BF':'lrtri','\\\\u22C0':'Wedge','\\\\u22C1':'Vee','\\\\u22C2':'xcap','\\\\u22C3':'xcup','\\\\u22C4':'diam','\\\\u22C5':'sdot','\\\\u22C6':'Star','\\\\u22C7':'divonx','\\\\u22C8':'bowtie','\\\\u22C9':'ltimes','\\\\u22CA':'rtimes','\\\\u22CB':'lthree','\\\\u22CC':'rthree','\\\\u22CD':'bsime','\\\\u22CE':'cuvee','\\\\u22CF':'cuwed','\\\\u22D0':'Sub','\\\\u22D1':'Sup','\\\\u22D2':'Cap','\\\\u22D3':'Cup','\\\\u22D4':'fork','\\\\u22D5':'epar','\\\\u22D6':'ltdot','\\\\u22D7':'gtdot','\\\\u22D8':'Ll','\\\\u22D8\\\\u0338':'nLl','\\\\u22D9':'Gg','\\\\u22D9\\\\u0338':'nGg','\\\\u22DA\\\\uFE00':'lesg','\\\\u22DA':'leg','\\\\u22DB':'gel','\\\\u22DB\\\\uFE00':'gesl','\\\\u22DE':'cuepr','\\\\u22DF':'cuesc','\\\\u22E6':'lnsim','\\\\u22E7':'gnsim','\\\\u22E8':'prnsim','\\\\u22E9':'scnsim','\\\\u22EE':'vellip','\\\\u22EF':'ctdot','\\\\u22F0':'utdot','\\\\u22F1':'dtdot','\\\\u22F2':'disin','\\\\u22F3':'isinsv','\\\\u22F4':'isins','\\\\u22F5':'isindot','\\\\u22F5\\\\u0338':'notindot','\\\\u22F6':'notinvc','\\\\u22F7':'notinvb','\\\\u22F9':'isinE','\\\\u22F9\\\\u0338':'notinE','\\\\u22FA':'nisd','\\\\u22FB':'xnis','\\\\u22FC':'nis','\\\\u22FD':'notnivc','\\\\u22FE':'notnivb','\\\\u2305':'barwed','\\\\u2306':'Barwed','\\\\u230C':'drcrop','\\\\u230D':'dlcrop','\\\\u230E':'urcrop','\\\\u230F':'ulcrop','\\\\u2310':'bnot','\\\\u2312':'profline','\\\\u2313':'profsurf','\\\\u2315':'telrec','\\\\u2316':'target','\\\\u231C':'ulcorn','\\\\u231D':'urcorn','\\\\u231E':'dlcorn','\\\\u231F':'drcorn','\\\\u2322':'frown','\\\\u2323':'smile','\\\\u232D':'cylcty','\\\\u232E':'profalar','\\\\u2336':'topbot','\\\\u233D':'ovbar','\\\\u233F':'solbar','\\\\u237C':'angzarr','\\\\u23B0':'lmoust','\\\\u23B1':'rmoust','\\\\u23B4':'tbrk','\\\\u23B5':'bbrk','\\\\u23B6':'bbrktbrk','\\\\u23DC':'OverParenthesis','\\\\u23DD':'UnderParenthesis','\\\\u23DE':'OverBrace','\\\\u23DF':'UnderBrace','\\\\u23E2':'trpezium','\\\\u23E7':'elinters','\\\\u2423':'blank','\\\\u2500':'boxh','\\\\u2502':'boxv','\\\\u250C':'boxdr','\\\\u2510':'boxdl','\\\\u2514':'boxur','\\\\u2518':'boxul','\\\\u251C':'boxvr','\\\\u2524':'boxvl','\\\\u252C':'boxhd','\\\\u2534':'boxhu','\\\\u253C':'boxvh','\\\\u2550':'boxH','\\\\u2551':'boxV','\\\\u2552':'boxdR','\\\\u2553':'boxDr','\\\\u2554':'boxDR','\\\\u2555':'boxdL','\\\\u2556':'boxDl','\\\\u2557':'boxDL','\\\\u2558':'boxuR','\\\\u2559':'boxUr','\\\\u255A':'boxUR','\\\\u255B':'boxuL','\\\\u255C':'boxUl','\\\\u255D':'boxUL','\\\\u255E':'boxvR','\\\\u255F':'boxVr','\\\\u2560':'boxVR','\\\\u2561':'boxvL','\\\\u2562':'boxVl','\\\\u2563':'boxVL','\\\\u2564':'boxHd','\\\\u2565':'boxhD','\\\\u2566':'boxHD','\\\\u2567':'boxHu','\\\\u2568':'boxhU','\\\\u2569':'boxHU','\\\\u256A':'boxvH','\\\\u256B':'boxVh','\\\\u256C':'boxVH','\\\\u2580':'uhblk','\\\\u2584':'lhblk','\\\\u2588':'block','\\\\u2591':'blk14','\\\\u2592':'blk12','\\\\u2593':'blk34','\\\\u25A1':'squ','\\\\u25AA':'squf','\\\\u25AB':'EmptyVerySmallSquare','\\\\u25AD':'rect','\\\\u25AE':'marker','\\\\u25B1':'fltns','\\\\u25B3':'xutri','\\\\u25B4':'utrif','\\\\u25B5':'utri','\\\\u25B8':'rtrif','\\\\u25B9':'rtri','\\\\u25BD':'xdtri','\\\\u25BE':'dtrif','\\\\u25BF':'dtri','\\\\u25C2':'ltrif','\\\\u25C3':'ltri','\\\\u25CA':'loz','\\\\u25CB':'cir','\\\\u25EC':'tridot','\\\\u25EF':'xcirc','\\\\u25F8':'ultri','\\\\u25F9':'urtri','\\\\u25FA':'lltri','\\\\u25FB':'EmptySmallSquare','\\\\u25FC':'FilledSmallSquare','\\\\u2605':'starf','\\\\u2606':'star','\\\\u260E':'phone','\\\\u2640':'female','\\\\u2642':'male','\\\\u2660':'spades','\\\\u2663':'clubs','\\\\u2665':'hearts','\\\\u2666':'diams','\\\\u266A':'sung','\\\\u2713':'check','\\\\u2717':'cross','\\\\u2720':'malt','\\\\u2736':'sext','\\\\u2758':'VerticalSeparator','\\\\u27C8':'bsolhsub','\\\\u27C9':'suphsol','\\\\u27F5':'xlarr','\\\\u27F6':'xrarr','\\\\u27F7':'xharr','\\\\u27F8':'xlArr','\\\\u27F9':'xrArr','\\\\u27FA':'xhArr','\\\\u27FC':'xmap','\\\\u27FF':'dzigrarr','\\\\u2902':'nvlArr','\\\\u2903':'nvrArr','\\\\u2904':'nvHarr','\\\\u2905':'Map','\\\\u290C':'lbarr','\\\\u290D':'rbarr','\\\\u290E':'lBarr','\\\\u290F':'rBarr','\\\\u2910':'RBarr','\\\\u2911':'DDotrahd','\\\\u2912':'UpArrowBar','\\\\u2913':'DownArrowBar','\\\\u2916':'Rarrtl','\\\\u2919':'latail','\\\\u291A':'ratail','\\\\u291B':'lAtail','\\\\u291C':'rAtail','\\\\u291D':'larrfs','\\\\u291E':'rarrfs','\\\\u291F':'larrbfs','\\\\u2920':'rarrbfs','\\\\u2923':'nwarhk','\\\\u2924':'nearhk','\\\\u2925':'searhk','\\\\u2926':'swarhk','\\\\u2927':'nwnear','\\\\u2928':'toea','\\\\u2929':'tosa','\\\\u292A':'swnwar','\\\\u2933':'rarrc','\\\\u2933\\\\u0338':'nrarrc','\\\\u2935':'cudarrr','\\\\u2936':'ldca','\\\\u2937':'rdca','\\\\u2938':'cudarrl','\\\\u2939':'larrpl','\\\\u293C':'curarrm','\\\\u293D':'cularrp','\\\\u2945':'rarrpl','\\\\u2948':'harrcir','\\\\u2949':'Uarrocir','\\\\u294A':'lurdshar','\\\\u294B':'ldrushar','\\\\u294E':'LeftRightVector','\\\\u294F':'RightUpDownVector','\\\\u2950':'DownLeftRightVector','\\\\u2951':'LeftUpDownVector','\\\\u2952':'LeftVectorBar','\\\\u2953':'RightVectorBar','\\\\u2954':'RightUpVectorBar','\\\\u2955':'RightDownVectorBar','\\\\u2956':'DownLeftVectorBar','\\\\u2957':'DownRightVectorBar','\\\\u2958':'LeftUpVectorBar','\\\\u2959':'LeftDownVectorBar','\\\\u295A':'LeftTeeVector','\\\\u295B':'RightTeeVector','\\\\u295C':'RightUpTeeVector','\\\\u295D':'RightDownTeeVector','\\\\u295E':'DownLeftTeeVector','\\\\u295F':'DownRightTeeVector','\\\\u2960':'LeftUpTeeVector','\\\\u2961':'LeftDownTeeVector','\\\\u2962':'lHar','\\\\u2963':'uHar','\\\\u2964':'rHar','\\\\u2965':'dHar','\\\\u2966':'luruhar','\\\\u2967':'ldrdhar','\\\\u2968':'ruluhar','\\\\u2969':'rdldhar','\\\\u296A':'lharul','\\\\u296B':'llhard','\\\\u296C':'rharul','\\\\u296D':'lrhard','\\\\u296E':'udhar','\\\\u296F':'duhar','\\\\u2970':'RoundImplies','\\\\u2971':'erarr','\\\\u2972':'simrarr','\\\\u2973':'larrsim','\\\\u2974':'rarrsim','\\\\u2975':'rarrap','\\\\u2976':'ltlarr','\\\\u2978':'gtrarr','\\\\u2979':'subrarr','\\\\u297B':'suplarr','\\\\u297C':'lfisht','\\\\u297D':'rfisht','\\\\u297E':'ufisht','\\\\u297F':'dfisht','\\\\u299A':'vzigzag','\\\\u299C':'vangrt','\\\\u299D':'angrtvbd','\\\\u29A4':'ange','\\\\u29A5':'range','\\\\u29A6':'dwangle','\\\\u29A7':'uwangle','\\\\u29A8':'angmsdaa','\\\\u29A9':'angmsdab','\\\\u29AA':'angmsdac','\\\\u29AB':'angmsdad','\\\\u29AC':'angmsdae','\\\\u29AD':'angmsdaf','\\\\u29AE':'angmsdag','\\\\u29AF':'angmsdah','\\\\u29B0':'bemptyv','\\\\u29B1':'demptyv','\\\\u29B2':'cemptyv','\\\\u29B3':'raemptyv','\\\\u29B4':'laemptyv','\\\\u29B5':'ohbar','\\\\u29B6':'omid','\\\\u29B7':'opar','\\\\u29B9':'operp','\\\\u29BB':'olcross','\\\\u29BC':'odsold','\\\\u29BE':'olcir','\\\\u29BF':'ofcir','\\\\u29C0':'olt','\\\\u29C1':'ogt','\\\\u29C2':'cirscir','\\\\u29C3':'cirE','\\\\u29C4':'solb','\\\\u29C5':'bsolb','\\\\u29C9':'boxbox','\\\\u29CD':'trisb','\\\\u29CE':'rtriltri','\\\\u29CF':'LeftTriangleBar','\\\\u29CF\\\\u0338':'NotLeftTriangleBar','\\\\u29D0':'RightTriangleBar','\\\\u29D0\\\\u0338':'NotRightTriangleBar','\\\\u29DC':'iinfin','\\\\u29DD':'infintie','\\\\u29DE':'nvinfin','\\\\u29E3':'eparsl','\\\\u29E4':'smeparsl','\\\\u29E5':'eqvparsl','\\\\u29EB':'lozf','\\\\u29F4':'RuleDelayed','\\\\u29F6':'dsol','\\\\u2A00':'xodot','\\\\u2A01':'xoplus','\\\\u2A02':'xotime','\\\\u2A04':'xuplus','\\\\u2A06':'xsqcup','\\\\u2A0D':'fpartint','\\\\u2A10':'cirfnint','\\\\u2A11':'awint','\\\\u2A12':'rppolint','\\\\u2A13':'scpolint','\\\\u2A14':'npolint','\\\\u2A15':'pointint','\\\\u2A16':'quatint','\\\\u2A17':'intlarhk','\\\\u2A22':'pluscir','\\\\u2A23':'plusacir','\\\\u2A24':'simplus','\\\\u2A25':'plusdu','\\\\u2A26':'plussim','\\\\u2A27':'plustwo','\\\\u2A29':'mcomma','\\\\u2A2A':'minusdu','\\\\u2A2D':'loplus','\\\\u2A2E':'roplus','\\\\u2A2F':'Cross','\\\\u2A30':'timesd','\\\\u2A31':'timesbar','\\\\u2A33':'smashp','\\\\u2A34':'lotimes','\\\\u2A35':'rotimes','\\\\u2A36':'otimesas','\\\\u2A37':'Otimes','\\\\u2A38':'odiv','\\\\u2A39':'triplus','\\\\u2A3A':'triminus','\\\\u2A3B':'tritime','\\\\u2A3C':'iprod','\\\\u2A3F':'amalg','\\\\u2A40':'capdot','\\\\u2A42':'ncup','\\\\u2A43':'ncap','\\\\u2A44':'capand','\\\\u2A45':'cupor','\\\\u2A46':'cupcap','\\\\u2A47':'capcup','\\\\u2A48':'cupbrcap','\\\\u2A49':'capbrcup','\\\\u2A4A':'cupcup','\\\\u2A4B':'capcap','\\\\u2A4C':'ccups','\\\\u2A4D':'ccaps','\\\\u2A50':'ccupssm','\\\\u2A53':'And','\\\\u2A54':'Or','\\\\u2A55':'andand','\\\\u2A56':'oror','\\\\u2A57':'orslope','\\\\u2A58':'andslope','\\\\u2A5A':'andv','\\\\u2A5B':'orv','\\\\u2A5C':'andd','\\\\u2A5D':'ord','\\\\u2A5F':'wedbar','\\\\u2A66':'sdote','\\\\u2A6A':'simdot','\\\\u2A6D':'congdot','\\\\u2A6D\\\\u0338':'ncongdot','\\\\u2A6E':'easter','\\\\u2A6F':'apacir','\\\\u2A70':'apE','\\\\u2A70\\\\u0338':'napE','\\\\u2A71':'eplus','\\\\u2A72':'pluse','\\\\u2A73':'Esim','\\\\u2A77':'eDDot','\\\\u2A78':'equivDD','\\\\u2A79':'ltcir','\\\\u2A7A':'gtcir','\\\\u2A7B':'ltquest','\\\\u2A7C':'gtquest','\\\\u2A7D':'les','\\\\u2A7D\\\\u0338':'nles','\\\\u2A7E':'ges','\\\\u2A7E\\\\u0338':'nges','\\\\u2A7F':'lesdot','\\\\u2A80':'gesdot','\\\\u2A81':'lesdoto','\\\\u2A82':'gesdoto','\\\\u2A83':'lesdotor','\\\\u2A84':'gesdotol','\\\\u2A85':'lap','\\\\u2A86':'gap','\\\\u2A87':'lne','\\\\u2A88':'gne','\\\\u2A89':'lnap','\\\\u2A8A':'gnap','\\\\u2A8B':'lEg','\\\\u2A8C':'gEl','\\\\u2A8D':'lsime','\\\\u2A8E':'gsime','\\\\u2A8F':'lsimg','\\\\u2A90':'gsiml','\\\\u2A91':'lgE','\\\\u2A92':'glE','\\\\u2A93':'lesges','\\\\u2A94':'gesles','\\\\u2A95':'els','\\\\u2A96':'egs','\\\\u2A97':'elsdot','\\\\u2A98':'egsdot','\\\\u2A99':'el','\\\\u2A9A':'eg','\\\\u2A9D':'siml','\\\\u2A9E':'simg','\\\\u2A9F':'simlE','\\\\u2AA0':'simgE','\\\\u2AA1':'LessLess','\\\\u2AA1\\\\u0338':'NotNestedLessLess','\\\\u2AA2':'GreaterGreater','\\\\u2AA2\\\\u0338':'NotNestedGreaterGreater','\\\\u2AA4':'glj','\\\\u2AA5':'gla','\\\\u2AA6':'ltcc','\\\\u2AA7':'gtcc','\\\\u2AA8':'lescc','\\\\u2AA9':'gescc','\\\\u2AAA':'smt','\\\\u2AAB':'lat','\\\\u2AAC':'smte','\\\\u2AAC\\\\uFE00':'smtes','\\\\u2AAD':'late','\\\\u2AAD\\\\uFE00':'lates','\\\\u2AAE':'bumpE','\\\\u2AAF':'pre','\\\\u2AAF\\\\u0338':'npre','\\\\u2AB0':'sce','\\\\u2AB0\\\\u0338':'nsce','\\\\u2AB3':'prE','\\\\u2AB4':'scE','\\\\u2AB5':'prnE','\\\\u2AB6':'scnE','\\\\u2AB7':'prap','\\\\u2AB8':'scap','\\\\u2AB9':'prnap','\\\\u2ABA':'scnap','\\\\u2ABB':'Pr','\\\\u2ABC':'Sc','\\\\u2ABD':'subdot','\\\\u2ABE':'supdot','\\\\u2ABF':'subplus','\\\\u2AC0':'supplus','\\\\u2AC1':'submult','\\\\u2AC2':'supmult','\\\\u2AC3':'subedot','\\\\u2AC4':'supedot','\\\\u2AC5':'subE','\\\\u2AC5\\\\u0338':'nsubE','\\\\u2AC6':'supE','\\\\u2AC6\\\\u0338':'nsupE','\\\\u2AC7':'subsim','\\\\u2AC8':'supsim','\\\\u2ACB\\\\uFE00':'vsubnE','\\\\u2ACB':'subnE','\\\\u2ACC\\\\uFE00':'vsupnE','\\\\u2ACC':'supnE','\\\\u2ACF':'csub','\\\\u2AD0':'csup','\\\\u2AD1':'csube','\\\\u2AD2':'csupe','\\\\u2AD3':'subsup','\\\\u2AD4':'supsub','\\\\u2AD5':'subsub','\\\\u2AD6':'supsup','\\\\u2AD7':'suphsub','\\\\u2AD8':'supdsub','\\\\u2AD9':'forkv','\\\\u2ADA':'topfork','\\\\u2ADB':'mlcp','\\\\u2AE4':'Dashv','\\\\u2AE6':'Vdashl','\\\\u2AE7':'Barv','\\\\u2AE8':'vBar','\\\\u2AE9':'vBarv','\\\\u2AEB':'Vbar','\\\\u2AEC':'Not','\\\\u2AED':'bNot','\\\\u2AEE':'rnmid','\\\\u2AEF':'cirmid','\\\\u2AF0':'midcir','\\\\u2AF1':'topcir','\\\\u2AF2':'nhpar','\\\\u2AF3':'parsim','\\\\u2AFD':'parsl','\\\\u2AFD\\\\u20E5':'nparsl','\\\\u266D':'flat','\\\\u266E':'natur','\\\\u266F':'sharp','\\\\xA4':'curren','\\\\xA2':'cent','$':'dollar','\\\\xA3':'pound','\\\\xA5':'yen','\\\\u20AC':'euro','\\\\xB9':'sup1','\\\\xBD':'half','\\\\u2153':'frac13','\\\\xBC':'frac14','\\\\u2155':'frac15','\\\\u2159':'frac16','\\\\u215B':'frac18','\\\\xB2':'sup2','\\\\u2154':'frac23','\\\\u2156':'frac25','\\\\xB3':'sup3','\\\\xBE':'frac34','\\\\u2157':'frac35','\\\\u215C':'frac38','\\\\u2158':'frac45','\\\\u215A':'frac56','\\\\u215D':'frac58','\\\\u215E':'frac78','\\\\uD835\\\\uDCB6':'ascr','\\\\uD835\\\\uDD52':'aopf','\\\\uD835\\\\uDD1E':'afr','\\\\uD835\\\\uDD38':'Aopf','\\\\uD835\\\\uDD04':'Afr','\\\\uD835\\\\uDC9C':'Ascr','\\\\xAA':'ordf','\\\\xE1':'aacute','\\\\xC1':'Aacute','\\\\xE0':'agrave','\\\\xC0':'Agrave','\\\\u0103':'abreve','\\\\u0102':'Abreve','\\\\xE2':'acirc','\\\\xC2':'Acirc','\\\\xE5':'aring','\\\\xC5':'angst','\\\\xE4':'auml','\\\\xC4':'Auml','\\\\xE3':'atilde','\\\\xC3':'Atilde','\\\\u0105':'aogon','\\\\u0104':'Aogon','\\\\u0101':'amacr','\\\\u0100':'Amacr','\\\\xE6':'aelig','\\\\xC6':'AElig','\\\\uD835\\\\uDCB7':'bscr','\\\\uD835\\\\uDD53':'bopf','\\\\uD835\\\\uDD1F':'bfr','\\\\uD835\\\\uDD39':'Bopf','\\\\u212C':'Bscr','\\\\uD835\\\\uDD05':'Bfr','\\\\uD835\\\\uDD20':'cfr','\\\\uD835\\\\uDCB8':'cscr','\\\\uD835\\\\uDD54':'copf','\\\\u212D':'Cfr','\\\\uD835\\\\uDC9E':'Cscr','\\\\u2102':'Copf','\\\\u0107':'cacute','\\\\u0106':'Cacute','\\\\u0109':'ccirc','\\\\u0108':'Ccirc','\\\\u010D':'ccaron','\\\\u010C':'Ccaron','\\\\u010B':'cdot','\\\\u010A':'Cdot','\\\\xE7':'ccedil','\\\\xC7':'Ccedil','\\\\u2105':'incare','\\\\uD835\\\\uDD21':'dfr','\\\\u2146':'dd','\\\\uD835\\\\uDD55':'dopf','\\\\uD835\\\\uDCB9':'dscr','\\\\uD835\\\\uDC9F':'Dscr','\\\\uD835\\\\uDD07':'Dfr','\\\\u2145':'DD','\\\\uD835\\\\uDD3B':'Dopf','\\\\u010F':'dcaron','\\\\u010E':'Dcaron','\\\\u0111':'dstrok','\\\\u0110':'Dstrok','\\\\xF0':'eth','\\\\xD0':'ETH','\\\\u2147':'ee','\\\\u212F':'escr','\\\\uD835\\\\uDD22':'efr','\\\\uD835\\\\uDD56':'eopf','\\\\u2130':'Escr','\\\\uD835\\\\uDD08':'Efr','\\\\uD835\\\\uDD3C':'Eopf','\\\\xE9':'eacute','\\\\xC9':'Eacute','\\\\xE8':'egrave','\\\\xC8':'Egrave','\\\\xEA':'ecirc','\\\\xCA':'Ecirc','\\\\u011B':'ecaron','\\\\u011A':'Ecaron','\\\\xEB':'euml','\\\\xCB':'Euml','\\\\u0117':'edot','\\\\u0116':'Edot','\\\\u0119':'eogon','\\\\u0118':'Eogon','\\\\u0113':'emacr','\\\\u0112':'Emacr','\\\\uD835\\\\uDD23':'ffr','\\\\uD835\\\\uDD57':'fopf','\\\\uD835\\\\uDCBB':'fscr','\\\\uD835\\\\uDD09':'Ffr','\\\\uD835\\\\uDD3D':'Fopf','\\\\u2131':'Fscr','\\\\uFB00':'fflig','\\\\uFB03':'ffilig','\\\\uFB04':'ffllig','\\\\uFB01':'filig','fj':'fjlig','\\\\uFB02':'fllig','\\\\u0192':'fnof','\\\\u210A':'gscr','\\\\uD835\\\\uDD58':'gopf','\\\\uD835\\\\uDD24':'gfr','\\\\uD835\\\\uDCA2':'Gscr','\\\\uD835\\\\uDD3E':'Gopf','\\\\uD835\\\\uDD0A':'Gfr','\\\\u01F5':'gacute','\\\\u011F':'gbreve','\\\\u011E':'Gbreve','\\\\u011D':'gcirc','\\\\u011C':'Gcirc','\\\\u0121':'gdot','\\\\u0120':'Gdot','\\\\u0122':'Gcedil','\\\\uD835\\\\uDD25':'hfr','\\\\u210E':'planckh','\\\\uD835\\\\uDCBD':'hscr','\\\\uD835\\\\uDD59':'hopf','\\\\u210B':'Hscr','\\\\u210C':'Hfr','\\\\u210D':'Hopf','\\\\u0125':'hcirc','\\\\u0124':'Hcirc','\\\\u210F':'hbar','\\\\u0127':'hstrok','\\\\u0126':'Hstrok','\\\\uD835\\\\uDD5A':'iopf','\\\\uD835\\\\uDD26':'ifr','\\\\uD835\\\\uDCBE':'iscr','\\\\u2148':'ii','\\\\uD835\\\\uDD40':'Iopf','\\\\u2110':'Iscr','\\\\u2111':'Im','\\\\xED':'iacute','\\\\xCD':'Iacute','\\\\xEC':'igrave','\\\\xCC':'Igrave','\\\\xEE':'icirc','\\\\xCE':'Icirc','\\\\xEF':'iuml','\\\\xCF':'Iuml','\\\\u0129':'itilde','\\\\u0128':'Itilde','\\\\u0130':'Idot','\\\\u012F':'iogon','\\\\u012E':'Iogon','\\\\u012B':'imacr','\\\\u012A':'Imacr','\\\\u0133':'ijlig','\\\\u0132':'IJlig','\\\\u0131':'imath','\\\\uD835\\\\uDCBF':'jscr','\\\\uD835\\\\uDD5B':'jopf','\\\\uD835\\\\uDD27':'jfr','\\\\uD835\\\\uDCA5':'Jscr','\\\\uD835\\\\uDD0D':'Jfr','\\\\uD835\\\\uDD41':'Jopf','\\\\u0135':'jcirc','\\\\u0134':'Jcirc','\\\\u0237':'jmath','\\\\uD835\\\\uDD5C':'kopf','\\\\uD835\\\\uDCC0':'kscr','\\\\uD835\\\\uDD28':'kfr','\\\\uD835\\\\uDCA6':'Kscr','\\\\uD835\\\\uDD42':'Kopf','\\\\uD835\\\\uDD0E':'Kfr','\\\\u0137':'kcedil','\\\\u0136':'Kcedil','\\\\uD835\\\\uDD29':'lfr','\\\\uD835\\\\uDCC1':'lscr','\\\\u2113':'ell','\\\\uD835\\\\uDD5D':'lopf','\\\\u2112':'Lscr','\\\\uD835\\\\uDD0F':'Lfr','\\\\uD835\\\\uDD43':'Lopf','\\\\u013A':'lacute','\\\\u0139':'Lacute','\\\\u013E':'lcaron','\\\\u013D':'Lcaron','\\\\u013C':'lcedil','\\\\u013B':'Lcedil','\\\\u0142':'lstrok','\\\\u0141':'Lstrok','\\\\u0140':'lmidot','\\\\u013F':'Lmidot','\\\\uD835\\\\uDD2A':'mfr','\\\\uD835\\\\uDD5E':'mopf','\\\\uD835\\\\uDCC2':'mscr','\\\\uD835\\\\uDD10':'Mfr','\\\\uD835\\\\uDD44':'Mopf','\\\\u2133':'Mscr','\\\\uD835\\\\uDD2B':'nfr','\\\\uD835\\\\uDD5F':'nopf','\\\\uD835\\\\uDCC3':'nscr','\\\\u2115':'Nopf','\\\\uD835\\\\uDCA9':'Nscr','\\\\uD835\\\\uDD11':'Nfr','\\\\u0144':'nacute','\\\\u0143':'Nacute','\\\\u0148':'ncaron','\\\\u0147':'Ncaron','\\\\xF1':'ntilde','\\\\xD1':'Ntilde','\\\\u0146':'ncedil','\\\\u0145':'Ncedil','\\\\u2116':'numero','\\\\u014B':'eng','\\\\u014A':'ENG','\\\\uD835\\\\uDD60':'oopf','\\\\uD835\\\\uDD2C':'ofr','\\\\u2134':'oscr','\\\\uD835\\\\uDCAA':'Oscr','\\\\uD835\\\\uDD12':'Ofr','\\\\uD835\\\\uDD46':'Oopf','\\\\xBA':'ordm','\\\\xF3':'oacute','\\\\xD3':'Oacute','\\\\xF2':'ograve','\\\\xD2':'Ograve','\\\\xF4':'ocirc','\\\\xD4':'Ocirc','\\\\xF6':'ouml','\\\\xD6':'Ouml','\\\\u0151':'odblac','\\\\u0150':'Odblac','\\\\xF5':'otilde','\\\\xD5':'Otilde','\\\\xF8':'oslash','\\\\xD8':'Oslash','\\\\u014D':'omacr','\\\\u014C':'Omacr','\\\\u0153':'oelig','\\\\u0152':'OElig','\\\\uD835\\\\uDD2D':'pfr','\\\\uD835\\\\uDCC5':'pscr','\\\\uD835\\\\uDD61':'popf','\\\\u2119':'Popf','\\\\uD835\\\\uDD13':'Pfr','\\\\uD835\\\\uDCAB':'Pscr','\\\\uD835\\\\uDD62':'qopf','\\\\uD835\\\\uDD2E':'qfr','\\\\uD835\\\\uDCC6':'qscr','\\\\uD835\\\\uDCAC':'Qscr','\\\\uD835\\\\uDD14':'Qfr','\\\\u211A':'Qopf','\\\\u0138':'kgreen','\\\\uD835\\\\uDD2F':'rfr','\\\\uD835\\\\uDD63':'ropf','\\\\uD835\\\\uDCC7':'rscr','\\\\u211B':'Rscr','\\\\u211C':'Re','\\\\u211D':'Ropf','\\\\u0155':'racute','\\\\u0154':'Racute','\\\\u0159':'rcaron','\\\\u0158':'Rcaron','\\\\u0157':'rcedil','\\\\u0156':'Rcedil','\\\\uD835\\\\uDD64':'sopf','\\\\uD835\\\\uDCC8':'sscr','\\\\uD835\\\\uDD30':'sfr','\\\\uD835\\\\uDD4A':'Sopf','\\\\uD835\\\\uDD16':'Sfr','\\\\uD835\\\\uDCAE':'Sscr','\\\\u24C8':'oS','\\\\u015B':'sacute','\\\\u015A':'Sacute','\\\\u015D':'scirc','\\\\u015C':'Scirc','\\\\u0161':'scaron','\\\\u0160':'Scaron','\\\\u015F':'scedil','\\\\u015E':'Scedil','\\\\xDF':'szlig','\\\\uD835\\\\uDD31':'tfr','\\\\uD835\\\\uDCC9':'tscr','\\\\uD835\\\\uDD65':'topf','\\\\uD835\\\\uDCAF':'Tscr','\\\\uD835\\\\uDD17':'Tfr','\\\\uD835\\\\uDD4B':'Topf','\\\\u0165':'tcaron','\\\\u0164':'Tcaron','\\\\u0163':'tcedil','\\\\u0162':'Tcedil','\\\\u2122':'trade','\\\\u0167':'tstrok','\\\\u0166':'Tstrok','\\\\uD835\\\\uDCCA':'uscr','\\\\uD835\\\\uDD66':'uopf','\\\\uD835\\\\uDD32':'ufr','\\\\uD835\\\\uDD4C':'Uopf','\\\\uD835\\\\uDD18':'Ufr','\\\\uD835\\\\uDCB0':'Uscr','\\\\xFA':'uacute','\\\\xDA':'Uacute','\\\\xF9':'ugrave','\\\\xD9':'Ugrave','\\\\u016D':'ubreve','\\\\u016C':'Ubreve','\\\\xFB':'ucirc','\\\\xDB':'Ucirc','\\\\u016F':'uring','\\\\u016E':'Uring','\\\\xFC':'uuml','\\\\xDC':'Uuml','\\\\u0171':'udblac','\\\\u0170':'Udblac','\\\\u0169':'utilde','\\\\u0168':'Utilde','\\\\u0173':'uogon','\\\\u0172':'Uogon','\\\\u016B':'umacr','\\\\u016A':'Umacr','\\\\uD835\\\\uDD33':'vfr','\\\\uD835\\\\uDD67':'vopf','\\\\uD835\\\\uDCCB':'vscr','\\\\uD835\\\\uDD19':'Vfr','\\\\uD835\\\\uDD4D':'Vopf','\\\\uD835\\\\uDCB1':'Vscr','\\\\uD835\\\\uDD68':'wopf','\\\\uD835\\\\uDCCC':'wscr','\\\\uD835\\\\uDD34':'wfr','\\\\uD835\\\\uDCB2':'Wscr','\\\\uD835\\\\uDD4E':'Wopf','\\\\uD835\\\\uDD1A':'Wfr','\\\\u0175':'wcirc','\\\\u0174':'Wcirc','\\\\uD835\\\\uDD35':'xfr','\\\\uD835\\\\uDCCD':'xscr','\\\\uD835\\\\uDD69':'xopf','\\\\uD835\\\\uDD4F':'Xopf','\\\\uD835\\\\uDD1B':'Xfr','\\\\uD835\\\\uDCB3':'Xscr','\\\\uD835\\\\uDD36':'yfr','\\\\uD835\\\\uDCCE':'yscr','\\\\uD835\\\\uDD6A':'yopf','\\\\uD835\\\\uDCB4':'Yscr','\\\\uD835\\\\uDD1C':'Yfr','\\\\uD835\\\\uDD50':'Yopf','\\\\xFD':'yacute','\\\\xDD':'Yacute','\\\\u0177':'ycirc','\\\\u0176':'Ycirc','\\\\xFF':'yuml','\\\\u0178':'Yuml','\\\\uD835\\\\uDCCF':'zscr','\\\\uD835\\\\uDD37':'zfr','\\\\uD835\\\\uDD6B':'zopf','\\\\u2128':'Zfr','\\\\u2124':'Zopf','\\\\uD835\\\\uDCB5':'Zscr','\\\\u017A':'zacute','\\\\u0179':'Zacute','\\\\u017E':'zcaron','\\\\u017D':'Zcaron','\\\\u017C':'zdot','\\\\u017B':'Zdot','\\\\u01B5':'imped','\\\\xFE':'thorn','\\\\xDE':'THORN','\\\\u0149':'napos','\\\\u03B1':'alpha','\\\\u0391':'Alpha','\\\\u03B2':'beta','\\\\u0392':'Beta','\\\\u03B3':'gamma','\\\\u0393':'Gamma','\\\\u03B4':'delta','\\\\u0394':'Delta','\\\\u03B5':'epsi','\\\\u03F5':'epsiv','\\\\u0395':'Epsilon','\\\\u03DD':'gammad','\\\\u03DC':'Gammad','\\\\u03B6':'zeta','\\\\u0396':'Zeta','\\\\u03B7':'eta','\\\\u0397':'Eta','\\\\u03B8':'theta','\\\\u03D1':'thetav','\\\\u0398':'Theta','\\\\u03B9':'iota','\\\\u0399':'Iota','\\\\u03BA':'kappa','\\\\u03F0':'kappav','\\\\u039A':'Kappa','\\\\u03BB':'lambda','\\\\u039B':'Lambda','\\\\u03BC':'mu','\\\\xB5':'micro','\\\\u039C':'Mu','\\\\u03BD':'nu','\\\\u039D':'Nu','\\\\u03BE':'xi','\\\\u039E':'Xi','\\\\u03BF':'omicron','\\\\u039F':'Omicron','\\\\u03C0':'pi','\\\\u03D6':'piv','\\\\u03A0':'Pi','\\\\u03C1':'rho','\\\\u03F1':'rhov','\\\\u03A1':'Rho','\\\\u03C3':'sigma','\\\\u03A3':'Sigma','\\\\u03C2':'sigmaf','\\\\u03C4':'tau','\\\\u03A4':'Tau','\\\\u03C5':'upsi','\\\\u03A5':'Upsilon','\\\\u03D2':'Upsi','\\\\u03C6':'phi','\\\\u03D5':'phiv','\\\\u03A6':'Phi','\\\\u03C7':'chi','\\\\u03A7':'Chi','\\\\u03C8':'psi','\\\\u03A8':'Psi','\\\\u03C9':'omega','\\\\u03A9':'ohm','\\\\u0430':'acy','\\\\u0410':'Acy','\\\\u0431':'bcy','\\\\u0411':'Bcy','\\\\u0432':'vcy','\\\\u0412':'Vcy','\\\\u0433':'gcy','\\\\u0413':'Gcy','\\\\u0453':'gjcy','\\\\u0403':'GJcy','\\\\u0434':'dcy','\\\\u0414':'Dcy','\\\\u0452':'djcy','\\\\u0402':'DJcy','\\\\u0435':'iecy','\\\\u0415':'IEcy','\\\\u0451':'iocy','\\\\u0401':'IOcy','\\\\u0454':'jukcy','\\\\u0404':'Jukcy','\\\\u0436':'zhcy','\\\\u0416':'ZHcy','\\\\u0437':'zcy','\\\\u0417':'Zcy','\\\\u0455':'dscy','\\\\u0405':'DScy','\\\\u0438':'icy','\\\\u0418':'Icy','\\\\u0456':'iukcy','\\\\u0406':'Iukcy','\\\\u0457':'yicy','\\\\u0407':'YIcy','\\\\u0439':'jcy','\\\\u0419':'Jcy','\\\\u0458':'jsercy','\\\\u0408':'Jsercy','\\\\u043A':'kcy','\\\\u041A':'Kcy','\\\\u045C':'kjcy','\\\\u040C':'KJcy','\\\\u043B':'lcy','\\\\u041B':'Lcy','\\\\u0459':'ljcy','\\\\u0409':'LJcy','\\\\u043C':'mcy','\\\\u041C':'Mcy','\\\\u043D':'ncy','\\\\u041D':'Ncy','\\\\u045A':'njcy','\\\\u040A':'NJcy','\\\\u043E':'ocy','\\\\u041E':'Ocy','\\\\u043F':'pcy','\\\\u041F':'Pcy','\\\\u0440':'rcy','\\\\u0420':'Rcy','\\\\u0441':'scy','\\\\u0421':'Scy','\\\\u0442':'tcy','\\\\u0422':'Tcy','\\\\u045B':'tshcy','\\\\u040B':'TSHcy','\\\\u0443':'ucy','\\\\u0423':'Ucy','\\\\u045E':'ubrcy','\\\\u040E':'Ubrcy','\\\\u0444':'fcy','\\\\u0424':'Fcy','\\\\u0445':'khcy','\\\\u0425':'KHcy','\\\\u0446':'tscy','\\\\u0426':'TScy','\\\\u0447':'chcy','\\\\u0427':'CHcy','\\\\u045F':'dzcy','\\\\u040F':'DZcy','\\\\u0448':'shcy','\\\\u0428':'SHcy','\\\\u0449':'shchcy','\\\\u0429':'SHCHcy','\\\\u044A':'hardcy','\\\\u042A':'HARDcy','\\\\u044B':'ycy','\\\\u042B':'Ycy','\\\\u044C':'softcy','\\\\u042C':'SOFTcy','\\\\u044D':'ecy','\\\\u042D':'Ecy','\\\\u044E':'yucy','\\\\u042E':'YUcy','\\\\u044F':'yacy','\\\\u042F':'YAcy','\\\\u2135':'aleph','\\\\u2136':'beth','\\\\u2137':'gimel','\\\\u2138':'daleth'};\\n\\n\\tvar regexEscape = /[\\\"&'<>`]/g;\\n\\tvar escapeMap = {\\n\\t\\t'\\\"': '"',\\n\\t\\t'&': '&',\\n\\t\\t'\\\\'': ''',\\n\\t\\t'<': '<',\\n\\t\\t// See https://mathiasbynens.be/notes/ambiguous-ampersands: in HTML, the\\n\\t\\t// following is not strictly necessary unless it’s part of a tag or an\\n\\t\\t// unquoted attribute value. We’re only escaping it to support those\\n\\t\\t// situations, and for XML support.\\n\\t\\t'>': '>',\\n\\t\\t// In Internet Explorer ≤ 8, the backtick character can be used\\n\\t\\t// to break out of (un)quoted attribute values or HTML comments.\\n\\t\\t// See http://html5sec.org/#102, http://html5sec.org/#108, and\\n\\t\\t// http://html5sec.org/#133.\\n\\t\\t'`': '`'\\n\\t};\\n\\n\\tvar regexInvalidEntity = /&#(?:[xX][^a-fA-F0-9]|[^0-9xX])/;\\n\\tvar regexInvalidRawCodePoint = /[\\\\0-\\\\x08\\\\x0B\\\\x0E-\\\\x1F\\\\x7F-\\\\x9F\\\\uFDD0-\\\\uFDEF\\\\uFFFE\\\\uFFFF]|[\\\\uD83F\\\\uD87F\\\\uD8BF\\\\uD8FF\\\\uD93F\\\\uD97F\\\\uD9BF\\\\uD9FF\\\\uDA3F\\\\uDA7F\\\\uDABF\\\\uDAFF\\\\uDB3F\\\\uDB7F\\\\uDBBF\\\\uDBFF][\\\\uDFFE\\\\uDFFF]|[\\\\uD800-\\\\uDBFF](?![\\\\uDC00-\\\\uDFFF])|(?:[^\\\\uD800-\\\\uDBFF]|^)[\\\\uDC00-\\\\uDFFF]/;\\n\\tvar regexDecode = /&(CounterClockwiseContourIntegral|DoubleLongLeftRightArrow|ClockwiseContourIntegral|NotNestedGreaterGreater|NotSquareSupersetEqual|DiacriticalDoubleAcute|NotRightTriangleEqual|NotSucceedsSlantEqual|NotPrecedesSlantEqual|CloseCurlyDoubleQuote|NegativeVeryThinSpace|DoubleContourIntegral|FilledVerySmallSquare|CapitalDifferentialD|OpenCurlyDoubleQuote|EmptyVerySmallSquare|NestedGreaterGreater|DoubleLongRightArrow|NotLeftTriangleEqual|NotGreaterSlantEqual|ReverseUpEquilibrium|DoubleLeftRightArrow|NotSquareSubsetEqual|NotDoubleVerticalBar|RightArrowLeftArrow|NotGreaterFullEqual|NotRightTriangleBar|SquareSupersetEqual|DownLeftRightVector|DoubleLongLeftArrow|leftrightsquigarrow|LeftArrowRightArrow|NegativeMediumSpace|blacktriangleright|RightDownVectorBar|PrecedesSlantEqual|RightDoubleBracket|SucceedsSlantEqual|NotLeftTriangleBar|RightTriangleEqual|SquareIntersection|RightDownTeeVector|ReverseEquilibrium|NegativeThickSpace|longleftrightarrow|Longleftrightarrow|LongLeftRightArrow|DownRightTeeVector|DownRightVectorBar|GreaterSlantEqual|SquareSubsetEqual|LeftDownVectorBar|LeftDoubleBracket|VerticalSeparator|rightleftharpoons|NotGreaterGreater|NotSquareSuperset|blacktriangleleft|blacktriangledown|NegativeThinSpace|LeftDownTeeVector|NotLessSlantEqual|leftrightharpoons|DoubleUpDownArrow|DoubleVerticalBar|LeftTriangleEqual|FilledSmallSquare|twoheadrightarrow|NotNestedLessLess|DownLeftTeeVector|DownLeftVectorBar|RightAngleBracket|NotTildeFullEqual|NotReverseElement|RightUpDownVector|DiacriticalTilde|NotSucceedsTilde|circlearrowright|NotPrecedesEqual|rightharpoondown|DoubleRightArrow|NotSucceedsEqual|NonBreakingSpace|NotRightTriangle|LessEqualGreater|RightUpTeeVector|LeftAngleBracket|GreaterFullEqual|DownArrowUpArrow|RightUpVectorBar|twoheadleftarrow|GreaterEqualLess|downharpoonright|RightTriangleBar|ntrianglerighteq|NotSupersetEqual|LeftUpDownVector|DiacriticalAcute|rightrightarrows|vartriangleright|UpArrowDownArrow|DiacriticalGrave|UnderParenthesis|EmptySmallSquare|LeftUpVectorBar|leftrightarrows|DownRightVector|downharpoonleft|trianglerighteq|ShortRightArrow|OverParenthesis|DoubleLeftArrow|DoubleDownArrow|NotSquareSubset|bigtriangledown|ntrianglelefteq|UpperRightArrow|curvearrowright|vartriangleleft|NotLeftTriangle|nleftrightarrow|LowerRightArrow|NotHumpDownHump|NotGreaterTilde|rightthreetimes|LeftUpTeeVector|NotGreaterEqual|straightepsilon|LeftTriangleBar|rightsquigarrow|ContourIntegral|rightleftarrows|CloseCurlyQuote|RightDownVector|LeftRightVector|nLeftrightarrow|leftharpoondown|circlearrowleft|SquareSuperset|OpenCurlyQuote|hookrightarrow|HorizontalLine|DiacriticalDot|NotLessGreater|ntriangleright|DoubleRightTee|InvisibleComma|InvisibleTimes|LowerLeftArrow|DownLeftVector|NotSubsetEqual|curvearrowleft|trianglelefteq|NotVerticalBar|TildeFullEqual|downdownarrows|NotGreaterLess|RightTeeVector|ZeroWidthSpace|looparrowright|LongRightArrow|doublebarwedge|ShortLeftArrow|ShortDownArrow|RightVectorBar|GreaterGreater|ReverseElement|rightharpoonup|LessSlantEqual|leftthreetimes|upharpoonright|rightarrowtail|LeftDownVector|Longrightarrow|NestedLessLess|UpperLeftArrow|nshortparallel|leftleftarrows|leftrightarrow|Leftrightarrow|LeftRightArrow|longrightarrow|upharpoonleft|RightArrowBar|ApplyFunction|LeftTeeVector|leftarrowtail|NotEqualTilde|varsubsetneqq|varsupsetneqq|RightTeeArrow|SucceedsEqual|SucceedsTilde|LeftVectorBar|SupersetEqual|hookleftarrow|DifferentialD|VerticalTilde|VeryThinSpace|blacktriangle|bigtriangleup|LessFullEqual|divideontimes|leftharpoonup|UpEquilibrium|ntriangleleft|RightTriangle|measuredangle|shortparallel|longleftarrow|Longleftarrow|LongLeftArrow|DoubleLeftTee|Poincareplane|PrecedesEqual|triangleright|DoubleUpArrow|RightUpVector|fallingdotseq|looparrowleft|PrecedesTilde|NotTildeEqual|NotTildeTilde|smallsetminus|Proportional|triangleleft|triangledown|UnderBracket|NotHumpEqual|exponentiale|ExponentialE|NotLessTilde|HilbertSpace|RightCeiling|blacklozenge|varsupsetneq|HumpDownHump|GreaterEqual|VerticalLine|LeftTeeArrow|NotLessEqual|DownTeeArrow|LeftTriangle|varsubsetneq|Intersection|NotCongruent|DownArrowBar|LeftUpVector|LeftArrowBar|risingdotseq|GreaterTilde|RoundImplies|SquareSubset|ShortUpArrow|NotSuperset|quaternions|precnapprox|backepsilon|preccurlyeq|OverBracket|blacksquare|MediumSpace|VerticalBar|circledcirc|circleddash|CircleMinus|CircleTimes|LessGreater|curlyeqprec|curlyeqsucc|diamondsuit|UpDownArrow|Updownarrow|RuleDelayed|Rrightarrow|updownarrow|RightVector|nRightarrow|nrightarrow|eqslantless|LeftCeiling|Equilibrium|SmallCircle|expectation|NotSucceeds|thickapprox|GreaterLess|SquareUnion|NotPrecedes|NotLessLess|straightphi|succnapprox|succcurlyeq|SubsetEqual|sqsupseteq|Proportion|Laplacetrf|ImaginaryI|supsetneqq|NotGreater|gtreqqless|NotElement|ThickSpace|TildeEqual|TildeTilde|Fouriertrf|rmoustache|EqualTilde|eqslantgtr|UnderBrace|LeftVector|UpArrowBar|nLeftarrow|nsubseteqq|subsetneqq|nsupseteqq|nleftarrow|succapprox|lessapprox|UpTeeArrow|upuparrows|curlywedge|lesseqqgtr|varepsilon|varnothing|RightFloor|complement|CirclePlus|sqsubseteq|Lleftarrow|circledast|RightArrow|Rightarrow|rightarrow|lmoustache|Bernoullis|precapprox|mapstoleft|mapstodown|longmapsto|dotsquare|downarrow|DoubleDot|nsubseteq|supsetneq|leftarrow|nsupseteq|subsetneq|ThinSpace|ngeqslant|subseteqq|HumpEqual|NotSubset|triangleq|NotCupCap|lesseqgtr|heartsuit|TripleDot|Leftarrow|Coproduct|Congruent|varpropto|complexes|gvertneqq|LeftArrow|LessTilde|supseteqq|MinusPlus|CircleDot|nleqslant|NotExists|gtreqless|nparallel|UnionPlus|LeftFloor|checkmark|CenterDot|centerdot|Mellintrf|gtrapprox|bigotimes|OverBrace|spadesuit|therefore|pitchfork|rationals|PlusMinus|Backslash|Therefore|DownBreve|backsimeq|backprime|DownArrow|nshortmid|Downarrow|lvertneqq|eqvparsl|imagline|imagpart|infintie|integers|Integral|intercal|LessLess|Uarrocir|intlarhk|sqsupset|angmsdaf|sqsubset|llcorner|vartheta|cupbrcap|lnapprox|Superset|SuchThat|succnsim|succneqq|angmsdag|biguplus|curlyvee|trpezium|Succeeds|NotTilde|bigwedge|angmsdah|angrtvbd|triminus|cwconint|fpartint|lrcorner|smeparsl|subseteq|urcorner|lurdshar|laemptyv|DDotrahd|approxeq|ldrushar|awconint|mapstoup|backcong|shortmid|triangle|geqslant|gesdotol|timesbar|circledR|circledS|setminus|multimap|naturals|scpolint|ncongdot|RightTee|boxminus|gnapprox|boxtimes|andslope|thicksim|angmsdaa|varsigma|cirfnint|rtriltri|angmsdab|rppolint|angmsdac|barwedge|drbkarow|clubsuit|thetasym|bsolhsub|capbrcup|dzigrarr|doteqdot|DotEqual|dotminus|UnderBar|NotEqual|realpart|otimesas|ulcorner|hksearow|hkswarow|parallel|PartialD|elinters|emptyset|plusacir|bbrktbrk|angmsdad|pointint|bigoplus|angmsdae|Precedes|bigsqcup|varkappa|notindot|supseteq|precneqq|precnsim|profalar|profline|profsurf|leqslant|lesdotor|raemptyv|subplus|notnivb|notnivc|subrarr|zigrarr|vzigzag|submult|subedot|Element|between|cirscir|larrbfs|larrsim|lotimes|lbrksld|lbrkslu|lozenge|ldrdhar|dbkarow|bigcirc|epsilon|simrarr|simplus|ltquest|Epsilon|luruhar|gtquest|maltese|npolint|eqcolon|npreceq|bigodot|ddagger|gtrless|bnequiv|harrcir|ddotseq|equivDD|backsim|demptyv|nsqsube|nsqsupe|Upsilon|nsubset|upsilon|minusdu|nsucceq|swarrow|nsupset|coloneq|searrow|boxplus|napprox|natural|asympeq|alefsym|congdot|nearrow|bigstar|diamond|supplus|tritime|LeftTee|nvinfin|triplus|NewLine|nvltrie|nvrtrie|nwarrow|nexists|Diamond|ruluhar|Implies|supmult|angzarr|suplarr|suphsub|questeq|because|digamma|Because|olcross|bemptyv|omicron|Omicron|rotimes|NoBreak|intprod|angrtvb|orderof|uwangle|suphsol|lesdoto|orslope|DownTee|realine|cudarrl|rdldhar|OverBar|supedot|lessdot|supdsub|topfork|succsim|rbrkslu|rbrksld|pertenk|cudarrr|isindot|planckh|lessgtr|pluscir|gesdoto|plussim|plustwo|lesssim|cularrp|rarrsim|Cayleys|notinva|notinvb|notinvc|UpArrow|Uparrow|uparrow|NotLess|dwangle|precsim|Product|curarrm|Cconint|dotplus|rarrbfs|ccupssm|Cedilla|cemptyv|notniva|quatint|frac35|frac38|frac45|frac56|frac58|frac78|tridot|xoplus|gacute|gammad|Gammad|lfisht|lfloor|bigcup|sqsupe|gbreve|Gbreve|lharul|sqsube|sqcups|Gcedil|apacir|llhard|lmidot|Lmidot|lmoust|andand|sqcaps|approx|Abreve|spades|circeq|tprime|divide|topcir|Assign|topbot|gesdot|divonx|xuplus|timesd|gesles|atilde|solbar|SOFTcy|loplus|timesb|lowast|lowbar|dlcorn|dlcrop|softcy|dollar|lparlt|thksim|lrhard|Atilde|lsaquo|smashp|bigvee|thinsp|wreath|bkarow|lsquor|lstrok|Lstrok|lthree|ltimes|ltlarr|DotDot|simdot|ltrPar|weierp|xsqcup|angmsd|sigmav|sigmaf|zeetrf|Zcaron|zcaron|mapsto|vsupne|thetav|cirmid|marker|mcomma|Zacute|vsubnE|there4|gtlPar|vsubne|bottom|gtrarr|SHCHcy|shchcy|midast|midcir|middot|minusb|minusd|gtrdot|bowtie|sfrown|mnplus|models|colone|seswar|Colone|mstpos|searhk|gtrsim|nacute|Nacute|boxbox|telrec|hairsp|Tcedil|nbumpe|scnsim|ncaron|Ncaron|ncedil|Ncedil|hamilt|Scedil|nearhk|hardcy|HARDcy|tcedil|Tcaron|commat|nequiv|nesear|tcaron|target|hearts|nexist|varrho|scedil|Scaron|scaron|hellip|Sacute|sacute|hercon|swnwar|compfn|rtimes|rthree|rsquor|rsaquo|zacute|wedgeq|homtht|barvee|barwed|Barwed|rpargt|horbar|conint|swarhk|roplus|nltrie|hslash|hstrok|Hstrok|rmoust|Conint|bprime|hybull|hyphen|iacute|Iacute|supsup|supsub|supsim|varphi|coprod|brvbar|agrave|Supset|supset|igrave|Igrave|notinE|Agrave|iiiint|iinfin|copysr|wedbar|Verbar|vangrt|becaus|incare|verbar|inodot|bullet|drcorn|intcal|drcrop|cularr|vellip|Utilde|bumpeq|cupcap|dstrok|Dstrok|CupCap|cupcup|cupdot|eacute|Eacute|supdot|iquest|easter|ecaron|Ecaron|ecolon|isinsv|utilde|itilde|Itilde|curarr|succeq|Bumpeq|cacute|ulcrop|nparsl|Cacute|nprcue|egrave|Egrave|nrarrc|nrarrw|subsup|subsub|nrtrie|jsercy|nsccue|Jsercy|kappav|kcedil|Kcedil|subsim|ulcorn|nsimeq|egsdot|veebar|kgreen|capand|elsdot|Subset|subset|curren|aacute|lacute|Lacute|emptyv|ntilde|Ntilde|lagran|lambda|Lambda|capcap|Ugrave|langle|subdot|emsp13|numero|emsp14|nvdash|nvDash|nVdash|nVDash|ugrave|ufisht|nvHarr|larrfs|nvlArr|larrhk|larrlp|larrpl|nvrArr|Udblac|nwarhk|larrtl|nwnear|oacute|Oacute|latail|lAtail|sstarf|lbrace|odblac|Odblac|lbrack|udblac|odsold|eparsl|lcaron|Lcaron|ograve|Ograve|lcedil|Lcedil|Aacute|ssmile|ssetmn|squarf|ldquor|capcup|ominus|cylcty|rharul|eqcirc|dagger|rfloor|rfisht|Dagger|daleth|equals|origof|capdot|equest|dcaron|Dcaron|rdquor|oslash|Oslash|otilde|Otilde|otimes|Otimes|urcrop|Ubreve|ubreve|Yacute|Uacute|uacute|Rcedil|rcedil|urcorn|parsim|Rcaron|Vdashl|rcaron|Tstrok|percnt|period|permil|Exists|yacute|rbrack|rbrace|phmmat|ccaron|Ccaron|planck|ccedil|plankv|tstrok|female|plusdo|plusdu|ffilig|plusmn|ffllig|Ccedil|rAtail|dfisht|bernou|ratail|Rarrtl|rarrtl|angsph|rarrpl|rarrlp|rarrhk|xwedge|xotime|forall|ForAll|Vvdash|vsupnE|preceq|bigcap|frac12|frac13|frac14|primes|rarrfs|prnsim|frac15|Square|frac16|square|lesdot|frac18|frac23|propto|prurel|rarrap|rangle|puncsp|frac25|Racute|qprime|racute|lesges|frac34|abreve|AElig|eqsim|utdot|setmn|urtri|Equal|Uring|seArr|uring|searr|dashv|Dashv|mumap|nabla|iogon|Iogon|sdote|sdotb|scsim|napid|napos|equiv|natur|Acirc|dblac|erarr|nbump|iprod|erDot|ucirc|awint|esdot|angrt|ncong|isinE|scnap|Scirc|scirc|ndash|isins|Ubrcy|nearr|neArr|isinv|nedot|ubrcy|acute|Ycirc|iukcy|Iukcy|xutri|nesim|caret|jcirc|Jcirc|caron|twixt|ddarr|sccue|exist|jmath|sbquo|ngeqq|angst|ccaps|lceil|ngsim|UpTee|delta|Delta|rtrif|nharr|nhArr|nhpar|rtrie|jukcy|Jukcy|kappa|rsquo|Kappa|nlarr|nlArr|TSHcy|rrarr|aogon|Aogon|fflig|xrarr|tshcy|ccirc|nleqq|filig|upsih|nless|dharl|nlsim|fjlig|ropar|nltri|dharr|robrk|roarr|fllig|fltns|roang|rnmid|subnE|subne|lAarr|trisb|Ccirc|acirc|ccups|blank|VDash|forkv|Vdash|langd|cedil|blk12|blk14|laquo|strns|diams|notin|vDash|larrb|blk34|block|disin|uplus|vdash|vBarv|aelig|starf|Wedge|check|xrArr|lates|lbarr|lBarr|notni|lbbrk|bcong|frasl|lbrke|frown|vrtri|vprop|vnsup|gamma|Gamma|wedge|xodot|bdquo|srarr|doteq|ldquo|boxdl|boxdL|gcirc|Gcirc|boxDl|boxDL|boxdr|boxdR|boxDr|TRADE|trade|rlhar|boxDR|vnsub|npart|vltri|rlarr|boxhd|boxhD|nprec|gescc|nrarr|nrArr|boxHd|boxHD|boxhu|boxhU|nrtri|boxHu|clubs|boxHU|times|colon|Colon|gimel|xlArr|Tilde|nsime|tilde|nsmid|nspar|THORN|thorn|xlarr|nsube|nsubE|thkap|xhArr|comma|nsucc|boxul|boxuL|nsupe|nsupE|gneqq|gnsim|boxUl|boxUL|grave|boxur|boxuR|boxUr|boxUR|lescc|angle|bepsi|boxvh|varpi|boxvH|numsp|Theta|gsime|gsiml|theta|boxVh|boxVH|boxvl|gtcir|gtdot|boxvL|boxVl|boxVL|crarr|cross|Cross|nvsim|boxvr|nwarr|nwArr|sqsup|dtdot|Uogon|lhard|lharu|dtrif|ocirc|Ocirc|lhblk|duarr|odash|sqsub|Hacek|sqcup|llarr|duhar|oelig|OElig|ofcir|boxvR|uogon|lltri|boxVr|csube|uuarr|ohbar|csupe|ctdot|olarr|olcir|harrw|oline|sqcap|omacr|Omacr|omega|Omega|boxVR|aleph|lneqq|lnsim|loang|loarr|rharu|lobrk|hcirc|operp|oplus|rhard|Hcirc|orarr|Union|order|ecirc|Ecirc|cuepr|szlig|cuesc|breve|reals|eDDot|Breve|hoarr|lopar|utrif|rdquo|Umacr|umacr|efDot|swArr|ultri|alpha|rceil|ovbar|swarr|Wcirc|wcirc|smtes|smile|bsemi|lrarr|aring|parsl|lrhar|bsime|uhblk|lrtri|cupor|Aring|uharr|uharl|slarr|rbrke|bsolb|lsime|rbbrk|RBarr|lsimg|phone|rBarr|rbarr|icirc|lsquo|Icirc|emacr|Emacr|ratio|simne|plusb|simlE|simgE|simeq|pluse|ltcir|ltdot|empty|xharr|xdtri|iexcl|Alpha|ltrie|rarrw|pound|ltrif|xcirc|bumpe|prcue|bumpE|asymp|amacr|cuvee|Sigma|sigma|iiint|udhar|iiota|ijlig|IJlig|supnE|imacr|Imacr|prime|Prime|image|prnap|eogon|Eogon|rarrc|mdash|mDDot|cuwed|imath|supne|imped|Amacr|udarr|prsim|micro|rarrb|cwint|raquo|infin|eplus|range|rangd|Ucirc|radic|minus|amalg|veeeq|rAarr|epsiv|ycirc|quest|sharp|quot|zwnj|Qscr|race|qscr|Qopf|qopf|qint|rang|Rang|Zscr|zscr|Zopf|zopf|rarr|rArr|Rarr|Pscr|pscr|prop|prod|prnE|prec|ZHcy|zhcy|prap|Zeta|zeta|Popf|popf|Zdot|plus|zdot|Yuml|yuml|phiv|YUcy|yucy|Yscr|yscr|perp|Yopf|yopf|part|para|YIcy|Ouml|rcub|yicy|YAcy|rdca|ouml|osol|Oscr|rdsh|yacy|real|oscr|xvee|andd|rect|andv|Xscr|oror|ordm|ordf|xscr|ange|aopf|Aopf|rHar|Xopf|opar|Oopf|xopf|xnis|rhov|oopf|omid|xmap|oint|apid|apos|ogon|ascr|Ascr|odot|odiv|xcup|xcap|ocir|oast|nvlt|nvle|nvgt|nvge|nvap|Wscr|wscr|auml|ntlg|ntgl|nsup|nsub|nsim|Nscr|nscr|nsce|Wopf|ring|npre|wopf|npar|Auml|Barv|bbrk|Nopf|nopf|nmid|nLtv|beta|ropf|Ropf|Beta|beth|nles|rpar|nleq|bnot|bNot|nldr|NJcy|rscr|Rscr|Vscr|vscr|rsqb|njcy|bopf|nisd|Bopf|rtri|Vopf|nGtv|ngtr|vopf|boxh|boxH|boxv|nges|ngeq|boxV|bscr|scap|Bscr|bsim|Vert|vert|bsol|bull|bump|caps|cdot|ncup|scnE|ncap|nbsp|napE|Cdot|cent|sdot|Vbar|nang|vBar|chcy|Mscr|mscr|sect|semi|CHcy|Mopf|mopf|sext|circ|cire|mldr|mlcp|cirE|comp|shcy|SHcy|vArr|varr|cong|copf|Copf|copy|COPY|malt|male|macr|lvnE|cscr|ltri|sime|ltcc|simg|Cscr|siml|csub|Uuml|lsqb|lsim|uuml|csup|Lscr|lscr|utri|smid|lpar|cups|smte|lozf|darr|Lopf|Uscr|solb|lopf|sopf|Sopf|lneq|uscr|spar|dArr|lnap|Darr|dash|Sqrt|LJcy|ljcy|lHar|dHar|Upsi|upsi|diam|lesg|djcy|DJcy|leqq|dopf|Dopf|dscr|Dscr|dscy|ldsh|ldca|squf|DScy|sscr|Sscr|dsol|lcub|late|star|Star|Uopf|Larr|lArr|larr|uopf|dtri|dzcy|sube|subE|Lang|lang|Kscr|kscr|Kopf|kopf|KJcy|kjcy|KHcy|khcy|DZcy|ecir|edot|eDot|Jscr|jscr|succ|Jopf|jopf|Edot|uHar|emsp|ensp|Iuml|iuml|eopf|isin|Iscr|iscr|Eopf|epar|sung|epsi|escr|sup1|sup2|sup3|Iota|iota|supe|supE|Iopf|iopf|IOcy|iocy|Escr|esim|Esim|imof|Uarr|QUOT|uArr|uarr|euml|IEcy|iecy|Idot|Euml|euro|excl|Hscr|hscr|Hopf|hopf|TScy|tscy|Tscr|hbar|tscr|flat|tbrk|fnof|hArr|harr|half|fopf|Fopf|tdot|gvnE|fork|trie|gtcc|fscr|Fscr|gdot|gsim|Gscr|gscr|Gopf|gopf|gneq|Gdot|tosa|gnap|Topf|topf|geqq|toea|GJcy|gjcy|tint|gesl|mid|Sfr|ggg|top|ges|gla|glE|glj|geq|gne|gEl|gel|gnE|Gcy|gcy|gap|Tfr|tfr|Tcy|tcy|Hat|Tau|Ffr|tau|Tab|hfr|Hfr|ffr|Fcy|fcy|icy|Icy|iff|ETH|eth|ifr|Ifr|Eta|eta|int|Int|Sup|sup|ucy|Ucy|Sum|sum|jcy|ENG|ufr|Ufr|eng|Jcy|jfr|els|ell|egs|Efr|efr|Jfr|uml|kcy|Kcy|Ecy|ecy|kfr|Kfr|lap|Sub|sub|lat|lcy|Lcy|leg|Dot|dot|lEg|leq|les|squ|div|die|lfr|Lfr|lgE|Dfr|dfr|Del|deg|Dcy|dcy|lne|lnE|sol|loz|smt|Cup|lrm|cup|lsh|Lsh|sim|shy|map|Map|mcy|Mcy|mfr|Mfr|mho|gfr|Gfr|sfr|cir|Chi|chi|nap|Cfr|vcy|Vcy|cfr|Scy|scy|ncy|Ncy|vee|Vee|Cap|cap|nfr|scE|sce|Nfr|nge|ngE|nGg|vfr|Vfr|ngt|bot|nGt|nis|niv|Rsh|rsh|nle|nlE|bne|Bfr|bfr|nLl|nlt|nLt|Bcy|bcy|not|Not|rlm|wfr|Wfr|npr|nsc|num|ocy|ast|Ocy|ofr|xfr|Xfr|Ofr|ogt|ohm|apE|olt|Rho|ape|rho|Rfr|rfr|ord|REG|ang|reg|orv|And|and|AMP|Rcy|amp|Afr|ycy|Ycy|yen|yfr|Yfr|rcy|par|pcy|Pcy|pfr|Pfr|phi|Phi|afr|Acy|acy|zcy|Zcy|piv|acE|acd|zfr|Zfr|pre|prE|psi|Psi|qfr|Qfr|zwj|Or|ge|Gg|gt|gg|el|oS|lt|Lt|LT|Re|lg|gl|eg|ne|Im|it|le|DD|wp|wr|nu|Nu|dd|lE|Sc|sc|pi|Pi|ee|af|ll|Ll|rx|gE|xi|pm|Xi|ic|pr|Pr|in|ni|mp|mu|ac|Mu|or|ap|Gt|GT|ii);|&(Aacute|Agrave|Atilde|Ccedil|Eacute|Egrave|Iacute|Igrave|Ntilde|Oacute|Ograve|Oslash|Otilde|Uacute|Ugrave|Yacute|aacute|agrave|atilde|brvbar|ccedil|curren|divide|eacute|egrave|frac12|frac14|frac34|iacute|igrave|iquest|middot|ntilde|oacute|ograve|oslash|otilde|plusmn|uacute|ugrave|yacute|AElig|Acirc|Aring|Ecirc|Icirc|Ocirc|THORN|Ucirc|acirc|acute|aelig|aring|cedil|ecirc|icirc|iexcl|laquo|micro|ocirc|pound|raquo|szlig|thorn|times|ucirc|Auml|COPY|Euml|Iuml|Ouml|QUOT|Uuml|auml|cent|copy|euml|iuml|macr|nbsp|ordf|ordm|ouml|para|quot|sect|sup1|sup2|sup3|uuml|yuml|AMP|ETH|REG|amp|deg|eth|not|reg|shy|uml|yen|GT|LT|gt|lt)(?!;)([=a-zA-Z0-9]?)|&#([0-9]+)(;?)|&#[xX]([a-fA-F0-9]+)(;?)|&([0-9a-zA-Z]+)/g;\\n\\tvar decodeMap = {'aacute':'\\\\xE1','Aacute':'\\\\xC1','abreve':'\\\\u0103','Abreve':'\\\\u0102','ac':'\\\\u223E','acd':'\\\\u223F','acE':'\\\\u223E\\\\u0333','acirc':'\\\\xE2','Acirc':'\\\\xC2','acute':'\\\\xB4','acy':'\\\\u0430','Acy':'\\\\u0410','aelig':'\\\\xE6','AElig':'\\\\xC6','af':'\\\\u2061','afr':'\\\\uD835\\\\uDD1E','Afr':'\\\\uD835\\\\uDD04','agrave':'\\\\xE0','Agrave':'\\\\xC0','alefsym':'\\\\u2135','aleph':'\\\\u2135','alpha':'\\\\u03B1','Alpha':'\\\\u0391','amacr':'\\\\u0101','Amacr':'\\\\u0100','amalg':'\\\\u2A3F','amp':'&','AMP':'&','and':'\\\\u2227','And':'\\\\u2A53','andand':'\\\\u2A55','andd':'\\\\u2A5C','andslope':'\\\\u2A58','andv':'\\\\u2A5A','ang':'\\\\u2220','ange':'\\\\u29A4','angle':'\\\\u2220','angmsd':'\\\\u2221','angmsdaa':'\\\\u29A8','angmsdab':'\\\\u29A9','angmsdac':'\\\\u29AA','angmsdad':'\\\\u29AB','angmsdae':'\\\\u29AC','angmsdaf':'\\\\u29AD','angmsdag':'\\\\u29AE','angmsdah':'\\\\u29AF','angrt':'\\\\u221F','angrtvb':'\\\\u22BE','angrtvbd':'\\\\u299D','angsph':'\\\\u2222','angst':'\\\\xC5','angzarr':'\\\\u237C','aogon':'\\\\u0105','Aogon':'\\\\u0104','aopf':'\\\\uD835\\\\uDD52','Aopf':'\\\\uD835\\\\uDD38','ap':'\\\\u2248','apacir':'\\\\u2A6F','ape':'\\\\u224A','apE':'\\\\u2A70','apid':'\\\\u224B','apos':'\\\\'','ApplyFunction':'\\\\u2061','approx':'\\\\u2248','approxeq':'\\\\u224A','aring':'\\\\xE5','Aring':'\\\\xC5','ascr':'\\\\uD835\\\\uDCB6','Ascr':'\\\\uD835\\\\uDC9C','Assign':'\\\\u2254','ast':'*','asymp':'\\\\u2248','asympeq':'\\\\u224D','atilde':'\\\\xE3','Atilde':'\\\\xC3','auml':'\\\\xE4','Auml':'\\\\xC4','awconint':'\\\\u2233','awint':'\\\\u2A11','backcong':'\\\\u224C','backepsilon':'\\\\u03F6','backprime':'\\\\u2035','backsim':'\\\\u223D','backsimeq':'\\\\u22CD','Backslash':'\\\\u2216','Barv':'\\\\u2AE7','barvee':'\\\\u22BD','barwed':'\\\\u2305','Barwed':'\\\\u2306','barwedge':'\\\\u2305','bbrk':'\\\\u23B5','bbrktbrk':'\\\\u23B6','bcong':'\\\\u224C','bcy':'\\\\u0431','Bcy':'\\\\u0411','bdquo':'\\\\u201E','becaus':'\\\\u2235','because':'\\\\u2235','Because':'\\\\u2235','bemptyv':'\\\\u29B0','bepsi':'\\\\u03F6','bernou':'\\\\u212C','Bernoullis':'\\\\u212C','beta':'\\\\u03B2','Beta':'\\\\u0392','beth':'\\\\u2136','between':'\\\\u226C','bfr':'\\\\uD835\\\\uDD1F','Bfr':'\\\\uD835\\\\uDD05','bigcap':'\\\\u22C2','bigcirc':'\\\\u25EF','bigcup':'\\\\u22C3','bigodot':'\\\\u2A00','bigoplus':'\\\\u2A01','bigotimes':'\\\\u2A02','bigsqcup':'\\\\u2A06','bigstar':'\\\\u2605','bigtriangledown':'\\\\u25BD','bigtriangleup':'\\\\u25B3','biguplus':'\\\\u2A04','bigvee':'\\\\u22C1','bigwedge':'\\\\u22C0','bkarow':'\\\\u290D','blacklozenge':'\\\\u29EB','blacksquare':'\\\\u25AA','blacktriangle':'\\\\u25B4','blacktriangledown':'\\\\u25BE','blacktriangleleft':'\\\\u25C2','blacktriangleright':'\\\\u25B8','blank':'\\\\u2423','blk12':'\\\\u2592','blk14':'\\\\u2591','blk34':'\\\\u2593','block':'\\\\u2588','bne':'=\\\\u20E5','bnequiv':'\\\\u2261\\\\u20E5','bnot':'\\\\u2310','bNot':'\\\\u2AED','bopf':'\\\\uD835\\\\uDD53','Bopf':'\\\\uD835\\\\uDD39','bot':'\\\\u22A5','bottom':'\\\\u22A5','bowtie':'\\\\u22C8','boxbox':'\\\\u29C9','boxdl':'\\\\u2510','boxdL':'\\\\u2555','boxDl':'\\\\u2556','boxDL':'\\\\u2557','boxdr':'\\\\u250C','boxdR':'\\\\u2552','boxDr':'\\\\u2553','boxDR':'\\\\u2554','boxh':'\\\\u2500','boxH':'\\\\u2550','boxhd':'\\\\u252C','boxhD':'\\\\u2565','boxHd':'\\\\u2564','boxHD':'\\\\u2566','boxhu':'\\\\u2534','boxhU':'\\\\u2568','boxHu':'\\\\u2567','boxHU':'\\\\u2569','boxminus':'\\\\u229F','boxplus':'\\\\u229E','boxtimes':'\\\\u22A0','boxul':'\\\\u2518','boxuL':'\\\\u255B','boxUl':'\\\\u255C','boxUL':'\\\\u255D','boxur':'\\\\u2514','boxuR':'\\\\u2558','boxUr':'\\\\u2559','boxUR':'\\\\u255A','boxv':'\\\\u2502','boxV':'\\\\u2551','boxvh':'\\\\u253C','boxvH':'\\\\u256A','boxVh':'\\\\u256B','boxVH':'\\\\u256C','boxvl':'\\\\u2524','boxvL':'\\\\u2561','boxVl':'\\\\u2562','boxVL':'\\\\u2563','boxvr':'\\\\u251C','boxvR':'\\\\u255E','boxVr':'\\\\u255F','boxVR':'\\\\u2560','bprime':'\\\\u2035','breve':'\\\\u02D8','Breve':'\\\\u02D8','brvbar':'\\\\xA6','bscr':'\\\\uD835\\\\uDCB7','Bscr':'\\\\u212C','bsemi':'\\\\u204F','bsim':'\\\\u223D','bsime':'\\\\u22CD','bsol':'\\\\\\\\','bsolb':'\\\\u29C5','bsolhsub':'\\\\u27C8','bull':'\\\\u2022','bullet':'\\\\u2022','bump':'\\\\u224E','bumpe':'\\\\u224F','bumpE':'\\\\u2AAE','bumpeq':'\\\\u224F','Bumpeq':'\\\\u224E','cacute':'\\\\u0107','Cacute':'\\\\u0106','cap':'\\\\u2229','Cap':'\\\\u22D2','capand':'\\\\u2A44','capbrcup':'\\\\u2A49','capcap':'\\\\u2A4B','capcup':'\\\\u2A47','capdot':'\\\\u2A40','CapitalDifferentialD':'\\\\u2145','caps':'\\\\u2229\\\\uFE00','caret':'\\\\u2041','caron':'\\\\u02C7','Cayleys':'\\\\u212D','ccaps':'\\\\u2A4D','ccaron':'\\\\u010D','Ccaron':'\\\\u010C','ccedil':'\\\\xE7','Ccedil':'\\\\xC7','ccirc':'\\\\u0109','Ccirc':'\\\\u0108','Cconint':'\\\\u2230','ccups':'\\\\u2A4C','ccupssm':'\\\\u2A50','cdot':'\\\\u010B','Cdot':'\\\\u010A','cedil':'\\\\xB8','Cedilla':'\\\\xB8','cemptyv':'\\\\u29B2','cent':'\\\\xA2','centerdot':'\\\\xB7','CenterDot':'\\\\xB7','cfr':'\\\\uD835\\\\uDD20','Cfr':'\\\\u212D','chcy':'\\\\u0447','CHcy':'\\\\u0427','check':'\\\\u2713','checkmark':'\\\\u2713','chi':'\\\\u03C7','Chi':'\\\\u03A7','cir':'\\\\u25CB','circ':'\\\\u02C6','circeq':'\\\\u2257','circlearrowleft':'\\\\u21BA','circlearrowright':'\\\\u21BB','circledast':'\\\\u229B','circledcirc':'\\\\u229A','circleddash':'\\\\u229D','CircleDot':'\\\\u2299','circledR':'\\\\xAE','circledS':'\\\\u24C8','CircleMinus':'\\\\u2296','CirclePlus':'\\\\u2295','CircleTimes':'\\\\u2297','cire':'\\\\u2257','cirE':'\\\\u29C3','cirfnint':'\\\\u2A10','cirmid':'\\\\u2AEF','cirscir':'\\\\u29C2','ClockwiseContourIntegral':'\\\\u2232','CloseCurlyDoubleQuote':'\\\\u201D','CloseCurlyQuote':'\\\\u2019','clubs':'\\\\u2663','clubsuit':'\\\\u2663','colon':':','Colon':'\\\\u2237','colone':'\\\\u2254','Colone':'\\\\u2A74','coloneq':'\\\\u2254','comma':',','commat':'@','comp':'\\\\u2201','compfn':'\\\\u2218','complement':'\\\\u2201','complexes':'\\\\u2102','cong':'\\\\u2245','congdot':'\\\\u2A6D','Congruent':'\\\\u2261','conint':'\\\\u222E','Conint':'\\\\u222F','ContourIntegral':'\\\\u222E','copf':'\\\\uD835\\\\uDD54','Copf':'\\\\u2102','coprod':'\\\\u2210','Coproduct':'\\\\u2210','copy':'\\\\xA9','COPY':'\\\\xA9','copysr':'\\\\u2117','CounterClockwiseContourIntegral':'\\\\u2233','crarr':'\\\\u21B5','cross':'\\\\u2717','Cross':'\\\\u2A2F','cscr':'\\\\uD835\\\\uDCB8','Cscr':'\\\\uD835\\\\uDC9E','csub':'\\\\u2ACF','csube':'\\\\u2AD1','csup':'\\\\u2AD0','csupe':'\\\\u2AD2','ctdot':'\\\\u22EF','cudarrl':'\\\\u2938','cudarrr':'\\\\u2935','cuepr':'\\\\u22DE','cuesc':'\\\\u22DF','cularr':'\\\\u21B6','cularrp':'\\\\u293D','cup':'\\\\u222A','Cup':'\\\\u22D3','cupbrcap':'\\\\u2A48','cupcap':'\\\\u2A46','CupCap':'\\\\u224D','cupcup':'\\\\u2A4A','cupdot':'\\\\u228D','cupor':'\\\\u2A45','cups':'\\\\u222A\\\\uFE00','curarr':'\\\\u21B7','curarrm':'\\\\u293C','curlyeqprec':'\\\\u22DE','curlyeqsucc':'\\\\u22DF','curlyvee':'\\\\u22CE','curlywedge':'\\\\u22CF','curren':'\\\\xA4','curvearrowleft':'\\\\u21B6','curvearrowright':'\\\\u21B7','cuvee':'\\\\u22CE','cuwed':'\\\\u22CF','cwconint':'\\\\u2232','cwint':'\\\\u2231','cylcty':'\\\\u232D','dagger':'\\\\u2020','Dagger':'\\\\u2021','daleth':'\\\\u2138','darr':'\\\\u2193','dArr':'\\\\u21D3','Darr':'\\\\u21A1','dash':'\\\\u2010','dashv':'\\\\u22A3','Dashv':'\\\\u2AE4','dbkarow':'\\\\u290F','dblac':'\\\\u02DD','dcaron':'\\\\u010F','Dcaron':'\\\\u010E','dcy':'\\\\u0434','Dcy':'\\\\u0414','dd':'\\\\u2146','DD':'\\\\u2145','ddagger':'\\\\u2021','ddarr':'\\\\u21CA','DDotrahd':'\\\\u2911','ddotseq':'\\\\u2A77','deg':'\\\\xB0','Del':'\\\\u2207','delta':'\\\\u03B4','Delta':'\\\\u0394','demptyv':'\\\\u29B1','dfisht':'\\\\u297F','dfr':'\\\\uD835\\\\uDD21','Dfr':'\\\\uD835\\\\uDD07','dHar':'\\\\u2965','dharl':'\\\\u21C3','dharr':'\\\\u21C2','DiacriticalAcute':'\\\\xB4','DiacriticalDot':'\\\\u02D9','DiacriticalDoubleAcute':'\\\\u02DD','DiacriticalGrave':'`','DiacriticalTilde':'\\\\u02DC','diam':'\\\\u22C4','diamond':'\\\\u22C4','Diamond':'\\\\u22C4','diamondsuit':'\\\\u2666','diams':'\\\\u2666','die':'\\\\xA8','DifferentialD':'\\\\u2146','digamma':'\\\\u03DD','disin':'\\\\u22F2','div':'\\\\xF7','divide':'\\\\xF7','divideontimes':'\\\\u22C7','divonx':'\\\\u22C7','djcy':'\\\\u0452','DJcy':'\\\\u0402','dlcorn':'\\\\u231E','dlcrop':'\\\\u230D','dollar':'$','dopf':'\\\\uD835\\\\uDD55','Dopf':'\\\\uD835\\\\uDD3B','dot':'\\\\u02D9','Dot':'\\\\xA8','DotDot':'\\\\u20DC','doteq':'\\\\u2250','doteqdot':'\\\\u2251','DotEqual':'\\\\u2250','dotminus':'\\\\u2238','dotplus':'\\\\u2214','dotsquare':'\\\\u22A1','doublebarwedge':'\\\\u2306','DoubleContourIntegral':'\\\\u222F','DoubleDot':'\\\\xA8','DoubleDownArrow':'\\\\u21D3','DoubleLeftArrow':'\\\\u21D0','DoubleLeftRightArrow':'\\\\u21D4','DoubleLeftTee':'\\\\u2AE4','DoubleLongLeftArrow':'\\\\u27F8','DoubleLongLeftRightArrow':'\\\\u27FA','DoubleLongRightArrow':'\\\\u27F9','DoubleRightArrow':'\\\\u21D2','DoubleRightTee':'\\\\u22A8','DoubleUpArrow':'\\\\u21D1','DoubleUpDownArrow':'\\\\u21D5','DoubleVerticalBar':'\\\\u2225','downarrow':'\\\\u2193','Downarrow':'\\\\u21D3','DownArrow':'\\\\u2193','DownArrowBar':'\\\\u2913','DownArrowUpArrow':'\\\\u21F5','DownBreve':'\\\\u0311','downdownarrows':'\\\\u21CA','downharpoonleft':'\\\\u21C3','downharpoonright':'\\\\u21C2','DownLeftRightVector':'\\\\u2950','DownLeftTeeVector':'\\\\u295E','DownLeftVector':'\\\\u21BD','DownLeftVectorBar':'\\\\u2956','DownRightTeeVector':'\\\\u295F','DownRightVector':'\\\\u21C1','DownRightVectorBar':'\\\\u2957','DownTee':'\\\\u22A4','DownTeeArrow':'\\\\u21A7','drbkarow':'\\\\u2910','drcorn':'\\\\u231F','drcrop':'\\\\u230C','dscr':'\\\\uD835\\\\uDCB9','Dscr':'\\\\uD835\\\\uDC9F','dscy':'\\\\u0455','DScy':'\\\\u0405','dsol':'\\\\u29F6','dstrok':'\\\\u0111','Dstrok':'\\\\u0110','dtdot':'\\\\u22F1','dtri':'\\\\u25BF','dtrif':'\\\\u25BE','duarr':'\\\\u21F5','duhar':'\\\\u296F','dwangle':'\\\\u29A6','dzcy':'\\\\u045F','DZcy':'\\\\u040F','dzigrarr':'\\\\u27FF','eacute':'\\\\xE9','Eacute':'\\\\xC9','easter':'\\\\u2A6E','ecaron':'\\\\u011B','Ecaron':'\\\\u011A','ecir':'\\\\u2256','ecirc':'\\\\xEA','Ecirc':'\\\\xCA','ecolon':'\\\\u2255','ecy':'\\\\u044D','Ecy':'\\\\u042D','eDDot':'\\\\u2A77','edot':'\\\\u0117','eDot':'\\\\u2251','Edot':'\\\\u0116','ee':'\\\\u2147','efDot':'\\\\u2252','efr':'\\\\uD835\\\\uDD22','Efr':'\\\\uD835\\\\uDD08','eg':'\\\\u2A9A','egrave':'\\\\xE8','Egrave':'\\\\xC8','egs':'\\\\u2A96','egsdot':'\\\\u2A98','el':'\\\\u2A99','Element':'\\\\u2208','elinters':'\\\\u23E7','ell':'\\\\u2113','els':'\\\\u2A95','elsdot':'\\\\u2A97','emacr':'\\\\u0113','Emacr':'\\\\u0112','empty':'\\\\u2205','emptyset':'\\\\u2205','EmptySmallSquare':'\\\\u25FB','emptyv':'\\\\u2205','EmptyVerySmallSquare':'\\\\u25AB','emsp':'\\\\u2003','emsp13':'\\\\u2004','emsp14':'\\\\u2005','eng':'\\\\u014B','ENG':'\\\\u014A','ensp':'\\\\u2002','eogon':'\\\\u0119','Eogon':'\\\\u0118','eopf':'\\\\uD835\\\\uDD56','Eopf':'\\\\uD835\\\\uDD3C','epar':'\\\\u22D5','eparsl':'\\\\u29E3','eplus':'\\\\u2A71','epsi':'\\\\u03B5','epsilon':'\\\\u03B5','Epsilon':'\\\\u0395','epsiv':'\\\\u03F5','eqcirc':'\\\\u2256','eqcolon':'\\\\u2255','eqsim':'\\\\u2242','eqslantgtr':'\\\\u2A96','eqslantless':'\\\\u2A95','Equal':'\\\\u2A75','equals':'=','EqualTilde':'\\\\u2242','equest':'\\\\u225F','Equilibrium':'\\\\u21CC','equiv':'\\\\u2261','equivDD':'\\\\u2A78','eqvparsl':'\\\\u29E5','erarr':'\\\\u2971','erDot':'\\\\u2253','escr':'\\\\u212F','Escr':'\\\\u2130','esdot':'\\\\u2250','esim':'\\\\u2242','Esim':'\\\\u2A73','eta':'\\\\u03B7','Eta':'\\\\u0397','eth':'\\\\xF0','ETH':'\\\\xD0','euml':'\\\\xEB','Euml':'\\\\xCB','euro':'\\\\u20AC','excl':'!','exist':'\\\\u2203','Exists':'\\\\u2203','expectation':'\\\\u2130','exponentiale':'\\\\u2147','ExponentialE':'\\\\u2147','fallingdotseq':'\\\\u2252','fcy':'\\\\u0444','Fcy':'\\\\u0424','female':'\\\\u2640','ffilig':'\\\\uFB03','fflig':'\\\\uFB00','ffllig':'\\\\uFB04','ffr':'\\\\uD835\\\\uDD23','Ffr':'\\\\uD835\\\\uDD09','filig':'\\\\uFB01','FilledSmallSquare':'\\\\u25FC','FilledVerySmallSquare':'\\\\u25AA','fjlig':'fj','flat':'\\\\u266D','fllig':'\\\\uFB02','fltns':'\\\\u25B1','fnof':'\\\\u0192','fopf':'\\\\uD835\\\\uDD57','Fopf':'\\\\uD835\\\\uDD3D','forall':'\\\\u2200','ForAll':'\\\\u2200','fork':'\\\\u22D4','forkv':'\\\\u2AD9','Fouriertrf':'\\\\u2131','fpartint':'\\\\u2A0D','frac12':'\\\\xBD','frac13':'\\\\u2153','frac14':'\\\\xBC','frac15':'\\\\u2155','frac16':'\\\\u2159','frac18':'\\\\u215B','frac23':'\\\\u2154','frac25':'\\\\u2156','frac34':'\\\\xBE','frac35':'\\\\u2157','frac38':'\\\\u215C','frac45':'\\\\u2158','frac56':'\\\\u215A','frac58':'\\\\u215D','frac78':'\\\\u215E','frasl':'\\\\u2044','frown':'\\\\u2322','fscr':'\\\\uD835\\\\uDCBB','Fscr':'\\\\u2131','gacute':'\\\\u01F5','gamma':'\\\\u03B3','Gamma':'\\\\u0393','gammad':'\\\\u03DD','Gammad':'\\\\u03DC','gap':'\\\\u2A86','gbreve':'\\\\u011F','Gbreve':'\\\\u011E','Gcedil':'\\\\u0122','gcirc':'\\\\u011D','Gcirc':'\\\\u011C','gcy':'\\\\u0433','Gcy':'\\\\u0413','gdot':'\\\\u0121','Gdot':'\\\\u0120','ge':'\\\\u2265','gE':'\\\\u2267','gel':'\\\\u22DB','gEl':'\\\\u2A8C','geq':'\\\\u2265','geqq':'\\\\u2267','geqslant':'\\\\u2A7E','ges':'\\\\u2A7E','gescc':'\\\\u2AA9','gesdot':'\\\\u2A80','gesdoto':'\\\\u2A82','gesdotol':'\\\\u2A84','gesl':'\\\\u22DB\\\\uFE00','gesles':'\\\\u2A94','gfr':'\\\\uD835\\\\uDD24','Gfr':'\\\\uD835\\\\uDD0A','gg':'\\\\u226B','Gg':'\\\\u22D9','ggg':'\\\\u22D9','gimel':'\\\\u2137','gjcy':'\\\\u0453','GJcy':'\\\\u0403','gl':'\\\\u2277','gla':'\\\\u2AA5','glE':'\\\\u2A92','glj':'\\\\u2AA4','gnap':'\\\\u2A8A','gnapprox':'\\\\u2A8A','gne':'\\\\u2A88','gnE':'\\\\u2269','gneq':'\\\\u2A88','gneqq':'\\\\u2269','gnsim':'\\\\u22E7','gopf':'\\\\uD835\\\\uDD58','Gopf':'\\\\uD835\\\\uDD3E','grave':'`','GreaterEqual':'\\\\u2265','GreaterEqualLess':'\\\\u22DB','GreaterFullEqual':'\\\\u2267','GreaterGreater':'\\\\u2AA2','GreaterLess':'\\\\u2277','GreaterSlantEqual':'\\\\u2A7E','GreaterTilde':'\\\\u2273','gscr':'\\\\u210A','Gscr':'\\\\uD835\\\\uDCA2','gsim':'\\\\u2273','gsime':'\\\\u2A8E','gsiml':'\\\\u2A90','gt':'>','Gt':'\\\\u226B','GT':'>','gtcc':'\\\\u2AA7','gtcir':'\\\\u2A7A','gtdot':'\\\\u22D7','gtlPar':'\\\\u2995','gtquest':'\\\\u2A7C','gtrapprox':'\\\\u2A86','gtrarr':'\\\\u2978','gtrdot':'\\\\u22D7','gtreqless':'\\\\u22DB','gtreqqless':'\\\\u2A8C','gtrless':'\\\\u2277','gtrsim':'\\\\u2273','gvertneqq':'\\\\u2269\\\\uFE00','gvnE':'\\\\u2269\\\\uFE00','Hacek':'\\\\u02C7','hairsp':'\\\\u200A','half':'\\\\xBD','hamilt':'\\\\u210B','hardcy':'\\\\u044A','HARDcy':'\\\\u042A','harr':'\\\\u2194','hArr':'\\\\u21D4','harrcir':'\\\\u2948','harrw':'\\\\u21AD','Hat':'^','hbar':'\\\\u210F','hcirc':'\\\\u0125','Hcirc':'\\\\u0124','hearts':'\\\\u2665','heartsuit':'\\\\u2665','hellip':'\\\\u2026','hercon':'\\\\u22B9','hfr':'\\\\uD835\\\\uDD25','Hfr':'\\\\u210C','HilbertSpace':'\\\\u210B','hksearow':'\\\\u2925','hkswarow':'\\\\u2926','hoarr':'\\\\u21FF','homtht':'\\\\u223B','hookleftarrow':'\\\\u21A9','hookrightarrow':'\\\\u21AA','hopf':'\\\\uD835\\\\uDD59','Hopf':'\\\\u210D','horbar':'\\\\u2015','HorizontalLine':'\\\\u2500','hscr':'\\\\uD835\\\\uDCBD','Hscr':'\\\\u210B','hslash':'\\\\u210F','hstrok':'\\\\u0127','Hstrok':'\\\\u0126','HumpDownHump':'\\\\u224E','HumpEqual':'\\\\u224F','hybull':'\\\\u2043','hyphen':'\\\\u2010','iacute':'\\\\xED','Iacute':'\\\\xCD','ic':'\\\\u2063','icirc':'\\\\xEE','Icirc':'\\\\xCE','icy':'\\\\u0438','Icy':'\\\\u0418','Idot':'\\\\u0130','iecy':'\\\\u0435','IEcy':'\\\\u0415','iexcl':'\\\\xA1','iff':'\\\\u21D4','ifr':'\\\\uD835\\\\uDD26','Ifr':'\\\\u2111','igrave':'\\\\xEC','Igrave':'\\\\xCC','ii':'\\\\u2148','iiiint':'\\\\u2A0C','iiint':'\\\\u222D','iinfin':'\\\\u29DC','iiota':'\\\\u2129','ijlig':'\\\\u0133','IJlig':'\\\\u0132','Im':'\\\\u2111','imacr':'\\\\u012B','Imacr':'\\\\u012A','image':'\\\\u2111','ImaginaryI':'\\\\u2148','imagline':'\\\\u2110','imagpart':'\\\\u2111','imath':'\\\\u0131','imof':'\\\\u22B7','imped':'\\\\u01B5','Implies':'\\\\u21D2','in':'\\\\u2208','incare':'\\\\u2105','infin':'\\\\u221E','infintie':'\\\\u29DD','inodot':'\\\\u0131','int':'\\\\u222B','Int':'\\\\u222C','intcal':'\\\\u22BA','integers':'\\\\u2124','Integral':'\\\\u222B','intercal':'\\\\u22BA','Intersection':'\\\\u22C2','intlarhk':'\\\\u2A17','intprod':'\\\\u2A3C','InvisibleComma':'\\\\u2063','InvisibleTimes':'\\\\u2062','iocy':'\\\\u0451','IOcy':'\\\\u0401','iogon':'\\\\u012F','Iogon':'\\\\u012E','iopf':'\\\\uD835\\\\uDD5A','Iopf':'\\\\uD835\\\\uDD40','iota':'\\\\u03B9','Iota':'\\\\u0399','iprod':'\\\\u2A3C','iquest':'\\\\xBF','iscr':'\\\\uD835\\\\uDCBE','Iscr':'\\\\u2110','isin':'\\\\u2208','isindot':'\\\\u22F5','isinE':'\\\\u22F9','isins':'\\\\u22F4','isinsv':'\\\\u22F3','isinv':'\\\\u2208','it':'\\\\u2062','itilde':'\\\\u0129','Itilde':'\\\\u0128','iukcy':'\\\\u0456','Iukcy':'\\\\u0406','iuml':'\\\\xEF','Iuml':'\\\\xCF','jcirc':'\\\\u0135','Jcirc':'\\\\u0134','jcy':'\\\\u0439','Jcy':'\\\\u0419','jfr':'\\\\uD835\\\\uDD27','Jfr':'\\\\uD835\\\\uDD0D','jmath':'\\\\u0237','jopf':'\\\\uD835\\\\uDD5B','Jopf':'\\\\uD835\\\\uDD41','jscr':'\\\\uD835\\\\uDCBF','Jscr':'\\\\uD835\\\\uDCA5','jsercy':'\\\\u0458','Jsercy':'\\\\u0408','jukcy':'\\\\u0454','Jukcy':'\\\\u0404','kappa':'\\\\u03BA','Kappa':'\\\\u039A','kappav':'\\\\u03F0','kcedil':'\\\\u0137','Kcedil':'\\\\u0136','kcy':'\\\\u043A','Kcy':'\\\\u041A','kfr':'\\\\uD835\\\\uDD28','Kfr':'\\\\uD835\\\\uDD0E','kgreen':'\\\\u0138','khcy':'\\\\u0445','KHcy':'\\\\u0425','kjcy':'\\\\u045C','KJcy':'\\\\u040C','kopf':'\\\\uD835\\\\uDD5C','Kopf':'\\\\uD835\\\\uDD42','kscr':'\\\\uD835\\\\uDCC0','Kscr':'\\\\uD835\\\\uDCA6','lAarr':'\\\\u21DA','lacute':'\\\\u013A','Lacute':'\\\\u0139','laemptyv':'\\\\u29B4','lagran':'\\\\u2112','lambda':'\\\\u03BB','Lambda':'\\\\u039B','lang':'\\\\u27E8','Lang':'\\\\u27EA','langd':'\\\\u2991','langle':'\\\\u27E8','lap':'\\\\u2A85','Laplacetrf':'\\\\u2112','laquo':'\\\\xAB','larr':'\\\\u2190','lArr':'\\\\u21D0','Larr':'\\\\u219E','larrb':'\\\\u21E4','larrbfs':'\\\\u291F','larrfs':'\\\\u291D','larrhk':'\\\\u21A9','larrlp':'\\\\u21AB','larrpl':'\\\\u2939','larrsim':'\\\\u2973','larrtl':'\\\\u21A2','lat':'\\\\u2AAB','latail':'\\\\u2919','lAtail':'\\\\u291B','late':'\\\\u2AAD','lates':'\\\\u2AAD\\\\uFE00','lbarr':'\\\\u290C','lBarr':'\\\\u290E','lbbrk':'\\\\u2772','lbrace':'{','lbrack':'[','lbrke':'\\\\u298B','lbrksld':'\\\\u298F','lbrkslu':'\\\\u298D','lcaron':'\\\\u013E','Lcaron':'\\\\u013D','lcedil':'\\\\u013C','Lcedil':'\\\\u013B','lceil':'\\\\u2308','lcub':'{','lcy':'\\\\u043B','Lcy':'\\\\u041B','ldca':'\\\\u2936','ldquo':'\\\\u201C','ldquor':'\\\\u201E','ldrdhar':'\\\\u2967','ldrushar':'\\\\u294B','ldsh':'\\\\u21B2','le':'\\\\u2264','lE':'\\\\u2266','LeftAngleBracket':'\\\\u27E8','leftarrow':'\\\\u2190','Leftarrow':'\\\\u21D0','LeftArrow':'\\\\u2190','LeftArrowBar':'\\\\u21E4','LeftArrowRightArrow':'\\\\u21C6','leftarrowtail':'\\\\u21A2','LeftCeiling':'\\\\u2308','LeftDoubleBracket':'\\\\u27E6','LeftDownTeeVector':'\\\\u2961','LeftDownVector':'\\\\u21C3','LeftDownVectorBar':'\\\\u2959','LeftFloor':'\\\\u230A','leftharpoondown':'\\\\u21BD','leftharpoonup':'\\\\u21BC','leftleftarrows':'\\\\u21C7','leftrightarrow':'\\\\u2194','Leftrightarrow':'\\\\u21D4','LeftRightArrow':'\\\\u2194','leftrightarrows':'\\\\u21C6','leftrightharpoons':'\\\\u21CB','leftrightsquigarrow':'\\\\u21AD','LeftRightVector':'\\\\u294E','LeftTee':'\\\\u22A3','LeftTeeArrow':'\\\\u21A4','LeftTeeVector':'\\\\u295A','leftthreetimes':'\\\\u22CB','LeftTriangle':'\\\\u22B2','LeftTriangleBar':'\\\\u29CF','LeftTriangleEqual':'\\\\u22B4','LeftUpDownVector':'\\\\u2951','LeftUpTeeVector':'\\\\u2960','LeftUpVector':'\\\\u21BF','LeftUpVectorBar':'\\\\u2958','LeftVector':'\\\\u21BC','LeftVectorBar':'\\\\u2952','leg':'\\\\u22DA','lEg':'\\\\u2A8B','leq':'\\\\u2264','leqq':'\\\\u2266','leqslant':'\\\\u2A7D','les':'\\\\u2A7D','lescc':'\\\\u2AA8','lesdot':'\\\\u2A7F','lesdoto':'\\\\u2A81','lesdotor':'\\\\u2A83','lesg':'\\\\u22DA\\\\uFE00','lesges':'\\\\u2A93','lessapprox':'\\\\u2A85','lessdot':'\\\\u22D6','lesseqgtr':'\\\\u22DA','lesseqqgtr':'\\\\u2A8B','LessEqualGreater':'\\\\u22DA','LessFullEqual':'\\\\u2266','LessGreater':'\\\\u2276','lessgtr':'\\\\u2276','LessLess':'\\\\u2AA1','lesssim':'\\\\u2272','LessSlantEqual':'\\\\u2A7D','LessTilde':'\\\\u2272','lfisht':'\\\\u297C','lfloor':'\\\\u230A','lfr':'\\\\uD835\\\\uDD29','Lfr':'\\\\uD835\\\\uDD0F','lg':'\\\\u2276','lgE':'\\\\u2A91','lHar':'\\\\u2962','lhard':'\\\\u21BD','lharu':'\\\\u21BC','lharul':'\\\\u296A','lhblk':'\\\\u2584','ljcy':'\\\\u0459','LJcy':'\\\\u0409','ll':'\\\\u226A','Ll':'\\\\u22D8','llarr':'\\\\u21C7','llcorner':'\\\\u231E','Lleftarrow':'\\\\u21DA','llhard':'\\\\u296B','lltri':'\\\\u25FA','lmidot':'\\\\u0140','Lmidot':'\\\\u013F','lmoust':'\\\\u23B0','lmoustache':'\\\\u23B0','lnap':'\\\\u2A89','lnapprox':'\\\\u2A89','lne':'\\\\u2A87','lnE':'\\\\u2268','lneq':'\\\\u2A87','lneqq':'\\\\u2268','lnsim':'\\\\u22E6','loang':'\\\\u27EC','loarr':'\\\\u21FD','lobrk':'\\\\u27E6','longleftarrow':'\\\\u27F5','Longleftarrow':'\\\\u27F8','LongLeftArrow':'\\\\u27F5','longleftrightarrow':'\\\\u27F7','Longleftrightarrow':'\\\\u27FA','LongLeftRightArrow':'\\\\u27F7','longmapsto':'\\\\u27FC','longrightarrow':'\\\\u27F6','Longrightarrow':'\\\\u27F9','LongRightArrow':'\\\\u27F6','looparrowleft':'\\\\u21AB','looparrowright':'\\\\u21AC','lopar':'\\\\u2985','lopf':'\\\\uD835\\\\uDD5D','Lopf':'\\\\uD835\\\\uDD43','loplus':'\\\\u2A2D','lotimes':'\\\\u2A34','lowast':'\\\\u2217','lowbar':'_','LowerLeftArrow':'\\\\u2199','LowerRightArrow':'\\\\u2198','loz':'\\\\u25CA','lozenge':'\\\\u25CA','lozf':'\\\\u29EB','lpar':'(','lparlt':'\\\\u2993','lrarr':'\\\\u21C6','lrcorner':'\\\\u231F','lrhar':'\\\\u21CB','lrhard':'\\\\u296D','lrm':'\\\\u200E','lrtri':'\\\\u22BF','lsaquo':'\\\\u2039','lscr':'\\\\uD835\\\\uDCC1','Lscr':'\\\\u2112','lsh':'\\\\u21B0','Lsh':'\\\\u21B0','lsim':'\\\\u2272','lsime':'\\\\u2A8D','lsimg':'\\\\u2A8F','lsqb':'[','lsquo':'\\\\u2018','lsquor':'\\\\u201A','lstrok':'\\\\u0142','Lstrok':'\\\\u0141','lt':'<','Lt':'\\\\u226A','LT':'<','ltcc':'\\\\u2AA6','ltcir':'\\\\u2A79','ltdot':'\\\\u22D6','lthree':'\\\\u22CB','ltimes':'\\\\u22C9','ltlarr':'\\\\u2976','ltquest':'\\\\u2A7B','ltri':'\\\\u25C3','ltrie':'\\\\u22B4','ltrif':'\\\\u25C2','ltrPar':'\\\\u2996','lurdshar':'\\\\u294A','luruhar':'\\\\u2966','lvertneqq':'\\\\u2268\\\\uFE00','lvnE':'\\\\u2268\\\\uFE00','macr':'\\\\xAF','male':'\\\\u2642','malt':'\\\\u2720','maltese':'\\\\u2720','map':'\\\\u21A6','Map':'\\\\u2905','mapsto':'\\\\u21A6','mapstodown':'\\\\u21A7','mapstoleft':'\\\\u21A4','mapstoup':'\\\\u21A5','marker':'\\\\u25AE','mcomma':'\\\\u2A29','mcy':'\\\\u043C','Mcy':'\\\\u041C','mdash':'\\\\u2014','mDDot':'\\\\u223A','measuredangle':'\\\\u2221','MediumSpace':'\\\\u205F','Mellintrf':'\\\\u2133','mfr':'\\\\uD835\\\\uDD2A','Mfr':'\\\\uD835\\\\uDD10','mho':'\\\\u2127','micro':'\\\\xB5','mid':'\\\\u2223','midast':'*','midcir':'\\\\u2AF0','middot':'\\\\xB7','minus':'\\\\u2212','minusb':'\\\\u229F','minusd':'\\\\u2238','minusdu':'\\\\u2A2A','MinusPlus':'\\\\u2213','mlcp':'\\\\u2ADB','mldr':'\\\\u2026','mnplus':'\\\\u2213','models':'\\\\u22A7','mopf':'\\\\uD835\\\\uDD5E','Mopf':'\\\\uD835\\\\uDD44','mp':'\\\\u2213','mscr':'\\\\uD835\\\\uDCC2','Mscr':'\\\\u2133','mstpos':'\\\\u223E','mu':'\\\\u03BC','Mu':'\\\\u039C','multimap':'\\\\u22B8','mumap':'\\\\u22B8','nabla':'\\\\u2207','nacute':'\\\\u0144','Nacute':'\\\\u0143','nang':'\\\\u2220\\\\u20D2','nap':'\\\\u2249','napE':'\\\\u2A70\\\\u0338','napid':'\\\\u224B\\\\u0338','napos':'\\\\u0149','napprox':'\\\\u2249','natur':'\\\\u266E','natural':'\\\\u266E','naturals':'\\\\u2115','nbsp':'\\\\xA0','nbump':'\\\\u224E\\\\u0338','nbumpe':'\\\\u224F\\\\u0338','ncap':'\\\\u2A43','ncaron':'\\\\u0148','Ncaron':'\\\\u0147','ncedil':'\\\\u0146','Ncedil':'\\\\u0145','ncong':'\\\\u2247','ncongdot':'\\\\u2A6D\\\\u0338','ncup':'\\\\u2A42','ncy':'\\\\u043D','Ncy':'\\\\u041D','ndash':'\\\\u2013','ne':'\\\\u2260','nearhk':'\\\\u2924','nearr':'\\\\u2197','neArr':'\\\\u21D7','nearrow':'\\\\u2197','nedot':'\\\\u2250\\\\u0338','NegativeMediumSpace':'\\\\u200B','NegativeThickSpace':'\\\\u200B','NegativeThinSpace':'\\\\u200B','NegativeVeryThinSpace':'\\\\u200B','nequiv':'\\\\u2262','nesear':'\\\\u2928','nesim':'\\\\u2242\\\\u0338','NestedGreaterGreater':'\\\\u226B','NestedLessLess':'\\\\u226A','NewLine':'\\\\n','nexist':'\\\\u2204','nexists':'\\\\u2204','nfr':'\\\\uD835\\\\uDD2B','Nfr':'\\\\uD835\\\\uDD11','nge':'\\\\u2271','ngE':'\\\\u2267\\\\u0338','ngeq':'\\\\u2271','ngeqq':'\\\\u2267\\\\u0338','ngeqslant':'\\\\u2A7E\\\\u0338','nges':'\\\\u2A7E\\\\u0338','nGg':'\\\\u22D9\\\\u0338','ngsim':'\\\\u2275','ngt':'\\\\u226F','nGt':'\\\\u226B\\\\u20D2','ngtr':'\\\\u226F','nGtv':'\\\\u226B\\\\u0338','nharr':'\\\\u21AE','nhArr':'\\\\u21CE','nhpar':'\\\\u2AF2','ni':'\\\\u220B','nis':'\\\\u22FC','nisd':'\\\\u22FA','niv':'\\\\u220B','njcy':'\\\\u045A','NJcy':'\\\\u040A','nlarr':'\\\\u219A','nlArr':'\\\\u21CD','nldr':'\\\\u2025','nle':'\\\\u2270','nlE':'\\\\u2266\\\\u0338','nleftarrow':'\\\\u219A','nLeftarrow':'\\\\u21CD','nleftrightarrow':'\\\\u21AE','nLeftrightarrow':'\\\\u21CE','nleq':'\\\\u2270','nleqq':'\\\\u2266\\\\u0338','nleqslant':'\\\\u2A7D\\\\u0338','nles':'\\\\u2A7D\\\\u0338','nless':'\\\\u226E','nLl':'\\\\u22D8\\\\u0338','nlsim':'\\\\u2274','nlt':'\\\\u226E','nLt':'\\\\u226A\\\\u20D2','nltri':'\\\\u22EA','nltrie':'\\\\u22EC','nLtv':'\\\\u226A\\\\u0338','nmid':'\\\\u2224','NoBreak':'\\\\u2060','NonBreakingSpace':'\\\\xA0','nopf':'\\\\uD835\\\\uDD5F','Nopf':'\\\\u2115','not':'\\\\xAC','Not':'\\\\u2AEC','NotCongruent':'\\\\u2262','NotCupCap':'\\\\u226D','NotDoubleVerticalBar':'\\\\u2226','NotElement':'\\\\u2209','NotEqual':'\\\\u2260','NotEqualTilde':'\\\\u2242\\\\u0338','NotExists':'\\\\u2204','NotGreater':'\\\\u226F','NotGreaterEqual':'\\\\u2271','NotGreaterFullEqual':'\\\\u2267\\\\u0338','NotGreaterGreater':'\\\\u226B\\\\u0338','NotGreaterLess':'\\\\u2279','NotGreaterSlantEqual':'\\\\u2A7E\\\\u0338','NotGreaterTilde':'\\\\u2275','NotHumpDownHump':'\\\\u224E\\\\u0338','NotHumpEqual':'\\\\u224F\\\\u0338','notin':'\\\\u2209','notindot':'\\\\u22F5\\\\u0338','notinE':'\\\\u22F9\\\\u0338','notinva':'\\\\u2209','notinvb':'\\\\u22F7','notinvc':'\\\\u22F6','NotLeftTriangle':'\\\\u22EA','NotLeftTriangleBar':'\\\\u29CF\\\\u0338','NotLeftTriangleEqual':'\\\\u22EC','NotLess':'\\\\u226E','NotLessEqual':'\\\\u2270','NotLessGreater':'\\\\u2278','NotLessLess':'\\\\u226A\\\\u0338','NotLessSlantEqual':'\\\\u2A7D\\\\u0338','NotLessTilde':'\\\\u2274','NotNestedGreaterGreater':'\\\\u2AA2\\\\u0338','NotNestedLessLess':'\\\\u2AA1\\\\u0338','notni':'\\\\u220C','notniva':'\\\\u220C','notnivb':'\\\\u22FE','notnivc':'\\\\u22FD','NotPrecedes':'\\\\u2280','NotPrecedesEqual':'\\\\u2AAF\\\\u0338','NotPrecedesSlantEqual':'\\\\u22E0','NotReverseElement':'\\\\u220C','NotRightTriangle':'\\\\u22EB','NotRightTriangleBar':'\\\\u29D0\\\\u0338','NotRightTriangleEqual':'\\\\u22ED','NotSquareSubset':'\\\\u228F\\\\u0338','NotSquareSubsetEqual':'\\\\u22E2','NotSquareSuperset':'\\\\u2290\\\\u0338','NotSquareSupersetEqual':'\\\\u22E3','NotSubset':'\\\\u2282\\\\u20D2','NotSubsetEqual':'\\\\u2288','NotSucceeds':'\\\\u2281','NotSucceedsEqual':'\\\\u2AB0\\\\u0338','NotSucceedsSlantEqual':'\\\\u22E1','NotSucceedsTilde':'\\\\u227F\\\\u0338','NotSuperset':'\\\\u2283\\\\u20D2','NotSupersetEqual':'\\\\u2289','NotTilde':'\\\\u2241','NotTildeEqual':'\\\\u2244','NotTildeFullEqual':'\\\\u2247','NotTildeTilde':'\\\\u2249','NotVerticalBar':'\\\\u2224','npar':'\\\\u2226','nparallel':'\\\\u2226','nparsl':'\\\\u2AFD\\\\u20E5','npart':'\\\\u2202\\\\u0338','npolint':'\\\\u2A14','npr':'\\\\u2280','nprcue':'\\\\u22E0','npre':'\\\\u2AAF\\\\u0338','nprec':'\\\\u2280','npreceq':'\\\\u2AAF\\\\u0338','nrarr':'\\\\u219B','nrArr':'\\\\u21CF','nrarrc':'\\\\u2933\\\\u0338','nrarrw':'\\\\u219D\\\\u0338','nrightarrow':'\\\\u219B','nRightarrow':'\\\\u21CF','nrtri':'\\\\u22EB','nrtrie':'\\\\u22ED','nsc':'\\\\u2281','nsccue':'\\\\u22E1','nsce':'\\\\u2AB0\\\\u0338','nscr':'\\\\uD835\\\\uDCC3','Nscr':'\\\\uD835\\\\uDCA9','nshortmid':'\\\\u2224','nshortparallel':'\\\\u2226','nsim':'\\\\u2241','nsime':'\\\\u2244','nsimeq':'\\\\u2244','nsmid':'\\\\u2224','nspar':'\\\\u2226','nsqsube':'\\\\u22E2','nsqsupe':'\\\\u22E3','nsub':'\\\\u2284','nsube':'\\\\u2288','nsubE':'\\\\u2AC5\\\\u0338','nsubset':'\\\\u2282\\\\u20D2','nsubseteq':'\\\\u2288','nsubseteqq':'\\\\u2AC5\\\\u0338','nsucc':'\\\\u2281','nsucceq':'\\\\u2AB0\\\\u0338','nsup':'\\\\u2285','nsupe':'\\\\u2289','nsupE':'\\\\u2AC6\\\\u0338','nsupset':'\\\\u2283\\\\u20D2','nsupseteq':'\\\\u2289','nsupseteqq':'\\\\u2AC6\\\\u0338','ntgl':'\\\\u2279','ntilde':'\\\\xF1','Ntilde':'\\\\xD1','ntlg':'\\\\u2278','ntriangleleft':'\\\\u22EA','ntrianglelefteq':'\\\\u22EC','ntriangleright':'\\\\u22EB','ntrianglerighteq':'\\\\u22ED','nu':'\\\\u03BD','Nu':'\\\\u039D','num':'#','numero':'\\\\u2116','numsp':'\\\\u2007','nvap':'\\\\u224D\\\\u20D2','nvdash':'\\\\u22AC','nvDash':'\\\\u22AD','nVdash':'\\\\u22AE','nVDash':'\\\\u22AF','nvge':'\\\\u2265\\\\u20D2','nvgt':'>\\\\u20D2','nvHarr':'\\\\u2904','nvinfin':'\\\\u29DE','nvlArr':'\\\\u2902','nvle':'\\\\u2264\\\\u20D2','nvlt':'<\\\\u20D2','nvltrie':'\\\\u22B4\\\\u20D2','nvrArr':'\\\\u2903','nvrtrie':'\\\\u22B5\\\\u20D2','nvsim':'\\\\u223C\\\\u20D2','nwarhk':'\\\\u2923','nwarr':'\\\\u2196','nwArr':'\\\\u21D6','nwarrow':'\\\\u2196','nwnear':'\\\\u2927','oacute':'\\\\xF3','Oacute':'\\\\xD3','oast':'\\\\u229B','ocir':'\\\\u229A','ocirc':'\\\\xF4','Ocirc':'\\\\xD4','ocy':'\\\\u043E','Ocy':'\\\\u041E','odash':'\\\\u229D','odblac':'\\\\u0151','Odblac':'\\\\u0150','odiv':'\\\\u2A38','odot':'\\\\u2299','odsold':'\\\\u29BC','oelig':'\\\\u0153','OElig':'\\\\u0152','ofcir':'\\\\u29BF','ofr':'\\\\uD835\\\\uDD2C','Ofr':'\\\\uD835\\\\uDD12','ogon':'\\\\u02DB','ograve':'\\\\xF2','Ograve':'\\\\xD2','ogt':'\\\\u29C1','ohbar':'\\\\u29B5','ohm':'\\\\u03A9','oint':'\\\\u222E','olarr':'\\\\u21BA','olcir':'\\\\u29BE','olcross':'\\\\u29BB','oline':'\\\\u203E','olt':'\\\\u29C0','omacr':'\\\\u014D','Omacr':'\\\\u014C','omega':'\\\\u03C9','Omega':'\\\\u03A9','omicron':'\\\\u03BF','Omicron':'\\\\u039F','omid':'\\\\u29B6','ominus':'\\\\u2296','oopf':'\\\\uD835\\\\uDD60','Oopf':'\\\\uD835\\\\uDD46','opar':'\\\\u29B7','OpenCurlyDoubleQuote':'\\\\u201C','OpenCurlyQuote':'\\\\u2018','operp':'\\\\u29B9','oplus':'\\\\u2295','or':'\\\\u2228','Or':'\\\\u2A54','orarr':'\\\\u21BB','ord':'\\\\u2A5D','order':'\\\\u2134','orderof':'\\\\u2134','ordf':'\\\\xAA','ordm':'\\\\xBA','origof':'\\\\u22B6','oror':'\\\\u2A56','orslope':'\\\\u2A57','orv':'\\\\u2A5B','oS':'\\\\u24C8','oscr':'\\\\u2134','Oscr':'\\\\uD835\\\\uDCAA','oslash':'\\\\xF8','Oslash':'\\\\xD8','osol':'\\\\u2298','otilde':'\\\\xF5','Otilde':'\\\\xD5','otimes':'\\\\u2297','Otimes':'\\\\u2A37','otimesas':'\\\\u2A36','ouml':'\\\\xF6','Ouml':'\\\\xD6','ovbar':'\\\\u233D','OverBar':'\\\\u203E','OverBrace':'\\\\u23DE','OverBracket':'\\\\u23B4','OverParenthesis':'\\\\u23DC','par':'\\\\u2225','para':'\\\\xB6','parallel':'\\\\u2225','parsim':'\\\\u2AF3','parsl':'\\\\u2AFD','part':'\\\\u2202','PartialD':'\\\\u2202','pcy':'\\\\u043F','Pcy':'\\\\u041F','percnt':'%','period':'.','permil':'\\\\u2030','perp':'\\\\u22A5','pertenk':'\\\\u2031','pfr':'\\\\uD835\\\\uDD2D','Pfr':'\\\\uD835\\\\uDD13','phi':'\\\\u03C6','Phi':'\\\\u03A6','phiv':'\\\\u03D5','phmmat':'\\\\u2133','phone':'\\\\u260E','pi':'\\\\u03C0','Pi':'\\\\u03A0','pitchfork':'\\\\u22D4','piv':'\\\\u03D6','planck':'\\\\u210F','planckh':'\\\\u210E','plankv':'\\\\u210F','plus':'+','plusacir':'\\\\u2A23','plusb':'\\\\u229E','pluscir':'\\\\u2A22','plusdo':'\\\\u2214','plusdu':'\\\\u2A25','pluse':'\\\\u2A72','PlusMinus':'\\\\xB1','plusmn':'\\\\xB1','plussim':'\\\\u2A26','plustwo':'\\\\u2A27','pm':'\\\\xB1','Poincareplane':'\\\\u210C','pointint':'\\\\u2A15','popf':'\\\\uD835\\\\uDD61','Popf':'\\\\u2119','pound':'\\\\xA3','pr':'\\\\u227A','Pr':'\\\\u2ABB','prap':'\\\\u2AB7','prcue':'\\\\u227C','pre':'\\\\u2AAF','prE':'\\\\u2AB3','prec':'\\\\u227A','precapprox':'\\\\u2AB7','preccurlyeq':'\\\\u227C','Precedes':'\\\\u227A','PrecedesEqual':'\\\\u2AAF','PrecedesSlantEqual':'\\\\u227C','PrecedesTilde':'\\\\u227E','preceq':'\\\\u2AAF','precnapprox':'\\\\u2AB9','precneqq':'\\\\u2AB5','precnsim':'\\\\u22E8','precsim':'\\\\u227E','prime':'\\\\u2032','Prime':'\\\\u2033','primes':'\\\\u2119','prnap':'\\\\u2AB9','prnE':'\\\\u2AB5','prnsim':'\\\\u22E8','prod':'\\\\u220F','Product':'\\\\u220F','profalar':'\\\\u232E','profline':'\\\\u2312','profsurf':'\\\\u2313','prop':'\\\\u221D','Proportion':'\\\\u2237','Proportional':'\\\\u221D','propto':'\\\\u221D','prsim':'\\\\u227E','prurel':'\\\\u22B0','pscr':'\\\\uD835\\\\uDCC5','Pscr':'\\\\uD835\\\\uDCAB','psi':'\\\\u03C8','Psi':'\\\\u03A8','puncsp':'\\\\u2008','qfr':'\\\\uD835\\\\uDD2E','Qfr':'\\\\uD835\\\\uDD14','qint':'\\\\u2A0C','qopf':'\\\\uD835\\\\uDD62','Qopf':'\\\\u211A','qprime':'\\\\u2057','qscr':'\\\\uD835\\\\uDCC6','Qscr':'\\\\uD835\\\\uDCAC','quaternions':'\\\\u210D','quatint':'\\\\u2A16','quest':'?','questeq':'\\\\u225F','quot':'\\\"','QUOT':'\\\"','rAarr':'\\\\u21DB','race':'\\\\u223D\\\\u0331','racute':'\\\\u0155','Racute':'\\\\u0154','radic':'\\\\u221A','raemptyv':'\\\\u29B3','rang':'\\\\u27E9','Rang':'\\\\u27EB','rangd':'\\\\u2992','range':'\\\\u29A5','rangle':'\\\\u27E9','raquo':'\\\\xBB','rarr':'\\\\u2192','rArr':'\\\\u21D2','Rarr':'\\\\u21A0','rarrap':'\\\\u2975','rarrb':'\\\\u21E5','rarrbfs':'\\\\u2920','rarrc':'\\\\u2933','rarrfs':'\\\\u291E','rarrhk':'\\\\u21AA','rarrlp':'\\\\u21AC','rarrpl':'\\\\u2945','rarrsim':'\\\\u2974','rarrtl':'\\\\u21A3','Rarrtl':'\\\\u2916','rarrw':'\\\\u219D','ratail':'\\\\u291A','rAtail':'\\\\u291C','ratio':'\\\\u2236','rationals':'\\\\u211A','rbarr':'\\\\u290D','rBarr':'\\\\u290F','RBarr':'\\\\u2910','rbbrk':'\\\\u2773','rbrace':'}','rbrack':']','rbrke':'\\\\u298C','rbrksld':'\\\\u298E','rbrkslu':'\\\\u2990','rcaron':'\\\\u0159','Rcaron':'\\\\u0158','rcedil':'\\\\u0157','Rcedil':'\\\\u0156','rceil':'\\\\u2309','rcub':'}','rcy':'\\\\u0440','Rcy':'\\\\u0420','rdca':'\\\\u2937','rdldhar':'\\\\u2969','rdquo':'\\\\u201D','rdquor':'\\\\u201D','rdsh':'\\\\u21B3','Re':'\\\\u211C','real':'\\\\u211C','realine':'\\\\u211B','realpart':'\\\\u211C','reals':'\\\\u211D','rect':'\\\\u25AD','reg':'\\\\xAE','REG':'\\\\xAE','ReverseElement':'\\\\u220B','ReverseEquilibrium':'\\\\u21CB','ReverseUpEquilibrium':'\\\\u296F','rfisht':'\\\\u297D','rfloor':'\\\\u230B','rfr':'\\\\uD835\\\\uDD2F','Rfr':'\\\\u211C','rHar':'\\\\u2964','rhard':'\\\\u21C1','rharu':'\\\\u21C0','rharul':'\\\\u296C','rho':'\\\\u03C1','Rho':'\\\\u03A1','rhov':'\\\\u03F1','RightAngleBracket':'\\\\u27E9','rightarrow':'\\\\u2192','Rightarrow':'\\\\u21D2','RightArrow':'\\\\u2192','RightArrowBar':'\\\\u21E5','RightArrowLeftArrow':'\\\\u21C4','rightarrowtail':'\\\\u21A3','RightCeiling':'\\\\u2309','RightDoubleBracket':'\\\\u27E7','RightDownTeeVector':'\\\\u295D','RightDownVector':'\\\\u21C2','RightDownVectorBar':'\\\\u2955','RightFloor':'\\\\u230B','rightharpoondown':'\\\\u21C1','rightharpoonup':'\\\\u21C0','rightleftarrows':'\\\\u21C4','rightleftharpoons':'\\\\u21CC','rightrightarrows':'\\\\u21C9','rightsquigarrow':'\\\\u219D','RightTee':'\\\\u22A2','RightTeeArrow':'\\\\u21A6','RightTeeVector':'\\\\u295B','rightthreetimes':'\\\\u22CC','RightTriangle':'\\\\u22B3','RightTriangleBar':'\\\\u29D0','RightTriangleEqual':'\\\\u22B5','RightUpDownVector':'\\\\u294F','RightUpTeeVector':'\\\\u295C','RightUpVector':'\\\\u21BE','RightUpVectorBar':'\\\\u2954','RightVector':'\\\\u21C0','RightVectorBar':'\\\\u2953','ring':'\\\\u02DA','risingdotseq':'\\\\u2253','rlarr':'\\\\u21C4','rlhar':'\\\\u21CC','rlm':'\\\\u200F','rmoust':'\\\\u23B1','rmoustache':'\\\\u23B1','rnmid':'\\\\u2AEE','roang':'\\\\u27ED','roarr':'\\\\u21FE','robrk':'\\\\u27E7','ropar':'\\\\u2986','ropf':'\\\\uD835\\\\uDD63','Ropf':'\\\\u211D','roplus':'\\\\u2A2E','rotimes':'\\\\u2A35','RoundImplies':'\\\\u2970','rpar':')','rpargt':'\\\\u2994','rppolint':'\\\\u2A12','rrarr':'\\\\u21C9','Rrightarrow':'\\\\u21DB','rsaquo':'\\\\u203A','rscr':'\\\\uD835\\\\uDCC7','Rscr':'\\\\u211B','rsh':'\\\\u21B1','Rsh':'\\\\u21B1','rsqb':']','rsquo':'\\\\u2019','rsquor':'\\\\u2019','rthree':'\\\\u22CC','rtimes':'\\\\u22CA','rtri':'\\\\u25B9','rtrie':'\\\\u22B5','rtrif':'\\\\u25B8','rtriltri':'\\\\u29CE','RuleDelayed':'\\\\u29F4','ruluhar':'\\\\u2968','rx':'\\\\u211E','sacute':'\\\\u015B','Sacute':'\\\\u015A','sbquo':'\\\\u201A','sc':'\\\\u227B','Sc':'\\\\u2ABC','scap':'\\\\u2AB8','scaron':'\\\\u0161','Scaron':'\\\\u0160','sccue':'\\\\u227D','sce':'\\\\u2AB0','scE':'\\\\u2AB4','scedil':'\\\\u015F','Scedil':'\\\\u015E','scirc':'\\\\u015D','Scirc':'\\\\u015C','scnap':'\\\\u2ABA','scnE':'\\\\u2AB6','scnsim':'\\\\u22E9','scpolint':'\\\\u2A13','scsim':'\\\\u227F','scy':'\\\\u0441','Scy':'\\\\u0421','sdot':'\\\\u22C5','sdotb':'\\\\u22A1','sdote':'\\\\u2A66','searhk':'\\\\u2925','searr':'\\\\u2198','seArr':'\\\\u21D8','searrow':'\\\\u2198','sect':'\\\\xA7','semi':';','seswar':'\\\\u2929','setminus':'\\\\u2216','setmn':'\\\\u2216','sext':'\\\\u2736','sfr':'\\\\uD835\\\\uDD30','Sfr':'\\\\uD835\\\\uDD16','sfrown':'\\\\u2322','sharp':'\\\\u266F','shchcy':'\\\\u0449','SHCHcy':'\\\\u0429','shcy':'\\\\u0448','SHcy':'\\\\u0428','ShortDownArrow':'\\\\u2193','ShortLeftArrow':'\\\\u2190','shortmid':'\\\\u2223','shortparallel':'\\\\u2225','ShortRightArrow':'\\\\u2192','ShortUpArrow':'\\\\u2191','shy':'\\\\xAD','sigma':'\\\\u03C3','Sigma':'\\\\u03A3','sigmaf':'\\\\u03C2','sigmav':'\\\\u03C2','sim':'\\\\u223C','simdot':'\\\\u2A6A','sime':'\\\\u2243','simeq':'\\\\u2243','simg':'\\\\u2A9E','simgE':'\\\\u2AA0','siml':'\\\\u2A9D','simlE':'\\\\u2A9F','simne':'\\\\u2246','simplus':'\\\\u2A24','simrarr':'\\\\u2972','slarr':'\\\\u2190','SmallCircle':'\\\\u2218','smallsetminus':'\\\\u2216','smashp':'\\\\u2A33','smeparsl':'\\\\u29E4','smid':'\\\\u2223','smile':'\\\\u2323','smt':'\\\\u2AAA','smte':'\\\\u2AAC','smtes':'\\\\u2AAC\\\\uFE00','softcy':'\\\\u044C','SOFTcy':'\\\\u042C','sol':'/','solb':'\\\\u29C4','solbar':'\\\\u233F','sopf':'\\\\uD835\\\\uDD64','Sopf':'\\\\uD835\\\\uDD4A','spades':'\\\\u2660','spadesuit':'\\\\u2660','spar':'\\\\u2225','sqcap':'\\\\u2293','sqcaps':'\\\\u2293\\\\uFE00','sqcup':'\\\\u2294','sqcups':'\\\\u2294\\\\uFE00','Sqrt':'\\\\u221A','sqsub':'\\\\u228F','sqsube':'\\\\u2291','sqsubset':'\\\\u228F','sqsubseteq':'\\\\u2291','sqsup':'\\\\u2290','sqsupe':'\\\\u2292','sqsupset':'\\\\u2290','sqsupseteq':'\\\\u2292','squ':'\\\\u25A1','square':'\\\\u25A1','Square':'\\\\u25A1','SquareIntersection':'\\\\u2293','SquareSubset':'\\\\u228F','SquareSubsetEqual':'\\\\u2291','SquareSuperset':'\\\\u2290','SquareSupersetEqual':'\\\\u2292','SquareUnion':'\\\\u2294','squarf':'\\\\u25AA','squf':'\\\\u25AA','srarr':'\\\\u2192','sscr':'\\\\uD835\\\\uDCC8','Sscr':'\\\\uD835\\\\uDCAE','ssetmn':'\\\\u2216','ssmile':'\\\\u2323','sstarf':'\\\\u22C6','star':'\\\\u2606','Star':'\\\\u22C6','starf':'\\\\u2605','straightepsilon':'\\\\u03F5','straightphi':'\\\\u03D5','strns':'\\\\xAF','sub':'\\\\u2282','Sub':'\\\\u22D0','subdot':'\\\\u2ABD','sube':'\\\\u2286','subE':'\\\\u2AC5','subedot':'\\\\u2AC3','submult':'\\\\u2AC1','subne':'\\\\u228A','subnE':'\\\\u2ACB','subplus':'\\\\u2ABF','subrarr':'\\\\u2979','subset':'\\\\u2282','Subset':'\\\\u22D0','subseteq':'\\\\u2286','subseteqq':'\\\\u2AC5','SubsetEqual':'\\\\u2286','subsetneq':'\\\\u228A','subsetneqq':'\\\\u2ACB','subsim':'\\\\u2AC7','subsub':'\\\\u2AD5','subsup':'\\\\u2AD3','succ':'\\\\u227B','succapprox':'\\\\u2AB8','succcurlyeq':'\\\\u227D','Succeeds':'\\\\u227B','SucceedsEqual':'\\\\u2AB0','SucceedsSlantEqual':'\\\\u227D','SucceedsTilde':'\\\\u227F','succeq':'\\\\u2AB0','succnapprox':'\\\\u2ABA','succneqq':'\\\\u2AB6','succnsim':'\\\\u22E9','succsim':'\\\\u227F','SuchThat':'\\\\u220B','sum':'\\\\u2211','Sum':'\\\\u2211','sung':'\\\\u266A','sup':'\\\\u2283','Sup':'\\\\u22D1','sup1':'\\\\xB9','sup2':'\\\\xB2','sup3':'\\\\xB3','supdot':'\\\\u2ABE','supdsub':'\\\\u2AD8','supe':'\\\\u2287','supE':'\\\\u2AC6','supedot':'\\\\u2AC4','Superset':'\\\\u2283','SupersetEqual':'\\\\u2287','suphsol':'\\\\u27C9','suphsub':'\\\\u2AD7','suplarr':'\\\\u297B','supmult':'\\\\u2AC2','supne':'\\\\u228B','supnE':'\\\\u2ACC','supplus':'\\\\u2AC0','supset':'\\\\u2283','Supset':'\\\\u22D1','supseteq':'\\\\u2287','supseteqq':'\\\\u2AC6','supsetneq':'\\\\u228B','supsetneqq':'\\\\u2ACC','supsim':'\\\\u2AC8','supsub':'\\\\u2AD4','supsup':'\\\\u2AD6','swarhk':'\\\\u2926','swarr':'\\\\u2199','swArr':'\\\\u21D9','swarrow':'\\\\u2199','swnwar':'\\\\u292A','szlig':'\\\\xDF','Tab':'\\\\t','target':'\\\\u2316','tau':'\\\\u03C4','Tau':'\\\\u03A4','tbrk':'\\\\u23B4','tcaron':'\\\\u0165','Tcaron':'\\\\u0164','tcedil':'\\\\u0163','Tcedil':'\\\\u0162','tcy':'\\\\u0442','Tcy':'\\\\u0422','tdot':'\\\\u20DB','telrec':'\\\\u2315','tfr':'\\\\uD835\\\\uDD31','Tfr':'\\\\uD835\\\\uDD17','there4':'\\\\u2234','therefore':'\\\\u2234','Therefore':'\\\\u2234','theta':'\\\\u03B8','Theta':'\\\\u0398','thetasym':'\\\\u03D1','thetav':'\\\\u03D1','thickapprox':'\\\\u2248','thicksim':'\\\\u223C','ThickSpace':'\\\\u205F\\\\u200A','thinsp':'\\\\u2009','ThinSpace':'\\\\u2009','thkap':'\\\\u2248','thksim':'\\\\u223C','thorn':'\\\\xFE','THORN':'\\\\xDE','tilde':'\\\\u02DC','Tilde':'\\\\u223C','TildeEqual':'\\\\u2243','TildeFullEqual':'\\\\u2245','TildeTilde':'\\\\u2248','times':'\\\\xD7','timesb':'\\\\u22A0','timesbar':'\\\\u2A31','timesd':'\\\\u2A30','tint':'\\\\u222D','toea':'\\\\u2928','top':'\\\\u22A4','topbot':'\\\\u2336','topcir':'\\\\u2AF1','topf':'\\\\uD835\\\\uDD65','Topf':'\\\\uD835\\\\uDD4B','topfork':'\\\\u2ADA','tosa':'\\\\u2929','tprime':'\\\\u2034','trade':'\\\\u2122','TRADE':'\\\\u2122','triangle':'\\\\u25B5','triangledown':'\\\\u25BF','triangleleft':'\\\\u25C3','trianglelefteq':'\\\\u22B4','triangleq':'\\\\u225C','triangleright':'\\\\u25B9','trianglerighteq':'\\\\u22B5','tridot':'\\\\u25EC','trie':'\\\\u225C','triminus':'\\\\u2A3A','TripleDot':'\\\\u20DB','triplus':'\\\\u2A39','trisb':'\\\\u29CD','tritime':'\\\\u2A3B','trpezium':'\\\\u23E2','tscr':'\\\\uD835\\\\uDCC9','Tscr':'\\\\uD835\\\\uDCAF','tscy':'\\\\u0446','TScy':'\\\\u0426','tshcy':'\\\\u045B','TSHcy':'\\\\u040B','tstrok':'\\\\u0167','Tstrok':'\\\\u0166','twixt':'\\\\u226C','twoheadleftarrow':'\\\\u219E','twoheadrightarrow':'\\\\u21A0','uacute':'\\\\xFA','Uacute':'\\\\xDA','uarr':'\\\\u2191','uArr':'\\\\u21D1','Uarr':'\\\\u219F','Uarrocir':'\\\\u2949','ubrcy':'\\\\u045E','Ubrcy':'\\\\u040E','ubreve':'\\\\u016D','Ubreve':'\\\\u016C','ucirc':'\\\\xFB','Ucirc':'\\\\xDB','ucy':'\\\\u0443','Ucy':'\\\\u0423','udarr':'\\\\u21C5','udblac':'\\\\u0171','Udblac':'\\\\u0170','udhar':'\\\\u296E','ufisht':'\\\\u297E','ufr':'\\\\uD835\\\\uDD32','Ufr':'\\\\uD835\\\\uDD18','ugrave':'\\\\xF9','Ugrave':'\\\\xD9','uHar':'\\\\u2963','uharl':'\\\\u21BF','uharr':'\\\\u21BE','uhblk':'\\\\u2580','ulcorn':'\\\\u231C','ulcorner':'\\\\u231C','ulcrop':'\\\\u230F','ultri':'\\\\u25F8','umacr':'\\\\u016B','Umacr':'\\\\u016A','uml':'\\\\xA8','UnderBar':'_','UnderBrace':'\\\\u23DF','UnderBracket':'\\\\u23B5','UnderParenthesis':'\\\\u23DD','Union':'\\\\u22C3','UnionPlus':'\\\\u228E','uogon':'\\\\u0173','Uogon':'\\\\u0172','uopf':'\\\\uD835\\\\uDD66','Uopf':'\\\\uD835\\\\uDD4C','uparrow':'\\\\u2191','Uparrow':'\\\\u21D1','UpArrow':'\\\\u2191','UpArrowBar':'\\\\u2912','UpArrowDownArrow':'\\\\u21C5','updownarrow':'\\\\u2195','Updownarrow':'\\\\u21D5','UpDownArrow':'\\\\u2195','UpEquilibrium':'\\\\u296E','upharpoonleft':'\\\\u21BF','upharpoonright':'\\\\u21BE','uplus':'\\\\u228E','UpperLeftArrow':'\\\\u2196','UpperRightArrow':'\\\\u2197','upsi':'\\\\u03C5','Upsi':'\\\\u03D2','upsih':'\\\\u03D2','upsilon':'\\\\u03C5','Upsilon':'\\\\u03A5','UpTee':'\\\\u22A5','UpTeeArrow':'\\\\u21A5','upuparrows':'\\\\u21C8','urcorn':'\\\\u231D','urcorner':'\\\\u231D','urcrop':'\\\\u230E','uring':'\\\\u016F','Uring':'\\\\u016E','urtri':'\\\\u25F9','uscr':'\\\\uD835\\\\uDCCA','Uscr':'\\\\uD835\\\\uDCB0','utdot':'\\\\u22F0','utilde':'\\\\u0169','Utilde':'\\\\u0168','utri':'\\\\u25B5','utrif':'\\\\u25B4','uuarr':'\\\\u21C8','uuml':'\\\\xFC','Uuml':'\\\\xDC','uwangle':'\\\\u29A7','vangrt':'\\\\u299C','varepsilon':'\\\\u03F5','varkappa':'\\\\u03F0','varnothing':'\\\\u2205','varphi':'\\\\u03D5','varpi':'\\\\u03D6','varpropto':'\\\\u221D','varr':'\\\\u2195','vArr':'\\\\u21D5','varrho':'\\\\u03F1','varsigma':'\\\\u03C2','varsubsetneq':'\\\\u228A\\\\uFE00','varsubsetneqq':'\\\\u2ACB\\\\uFE00','varsupsetneq':'\\\\u228B\\\\uFE00','varsupsetneqq':'\\\\u2ACC\\\\uFE00','vartheta':'\\\\u03D1','vartriangleleft':'\\\\u22B2','vartriangleright':'\\\\u22B3','vBar':'\\\\u2AE8','Vbar':'\\\\u2AEB','vBarv':'\\\\u2AE9','vcy':'\\\\u0432','Vcy':'\\\\u0412','vdash':'\\\\u22A2','vDash':'\\\\u22A8','Vdash':'\\\\u22A9','VDash':'\\\\u22AB','Vdashl':'\\\\u2AE6','vee':'\\\\u2228','Vee':'\\\\u22C1','veebar':'\\\\u22BB','veeeq':'\\\\u225A','vellip':'\\\\u22EE','verbar':'|','Verbar':'\\\\u2016','vert':'|','Vert':'\\\\u2016','VerticalBar':'\\\\u2223','VerticalLine':'|','VerticalSeparator':'\\\\u2758','VerticalTilde':'\\\\u2240','VeryThinSpace':'\\\\u200A','vfr':'\\\\uD835\\\\uDD33','Vfr':'\\\\uD835\\\\uDD19','vltri':'\\\\u22B2','vnsub':'\\\\u2282\\\\u20D2','vnsup':'\\\\u2283\\\\u20D2','vopf':'\\\\uD835\\\\uDD67','Vopf':'\\\\uD835\\\\uDD4D','vprop':'\\\\u221D','vrtri':'\\\\u22B3','vscr':'\\\\uD835\\\\uDCCB','Vscr':'\\\\uD835\\\\uDCB1','vsubne':'\\\\u228A\\\\uFE00','vsubnE':'\\\\u2ACB\\\\uFE00','vsupne':'\\\\u228B\\\\uFE00','vsupnE':'\\\\u2ACC\\\\uFE00','Vvdash':'\\\\u22AA','vzigzag':'\\\\u299A','wcirc':'\\\\u0175','Wcirc':'\\\\u0174','wedbar':'\\\\u2A5F','wedge':'\\\\u2227','Wedge':'\\\\u22C0','wedgeq':'\\\\u2259','weierp':'\\\\u2118','wfr':'\\\\uD835\\\\uDD34','Wfr':'\\\\uD835\\\\uDD1A','wopf':'\\\\uD835\\\\uDD68','Wopf':'\\\\uD835\\\\uDD4E','wp':'\\\\u2118','wr':'\\\\u2240','wreath':'\\\\u2240','wscr':'\\\\uD835\\\\uDCCC','Wscr':'\\\\uD835\\\\uDCB2','xcap':'\\\\u22C2','xcirc':'\\\\u25EF','xcup':'\\\\u22C3','xdtri':'\\\\u25BD','xfr':'\\\\uD835\\\\uDD35','Xfr':'\\\\uD835\\\\uDD1B','xharr':'\\\\u27F7','xhArr':'\\\\u27FA','xi':'\\\\u03BE','Xi':'\\\\u039E','xlarr':'\\\\u27F5','xlArr':'\\\\u27F8','xmap':'\\\\u27FC','xnis':'\\\\u22FB','xodot':'\\\\u2A00','xopf':'\\\\uD835\\\\uDD69','Xopf':'\\\\uD835\\\\uDD4F','xoplus':'\\\\u2A01','xotime':'\\\\u2A02','xrarr':'\\\\u27F6','xrArr':'\\\\u27F9','xscr':'\\\\uD835\\\\uDCCD','Xscr':'\\\\uD835\\\\uDCB3','xsqcup':'\\\\u2A06','xuplus':'\\\\u2A04','xutri':'\\\\u25B3','xvee':'\\\\u22C1','xwedge':'\\\\u22C0','yacute':'\\\\xFD','Yacute':'\\\\xDD','yacy':'\\\\u044F','YAcy':'\\\\u042F','ycirc':'\\\\u0177','Ycirc':'\\\\u0176','ycy':'\\\\u044B','Ycy':'\\\\u042B','yen':'\\\\xA5','yfr':'\\\\uD835\\\\uDD36','Yfr':'\\\\uD835\\\\uDD1C','yicy':'\\\\u0457','YIcy':'\\\\u0407','yopf':'\\\\uD835\\\\uDD6A','Yopf':'\\\\uD835\\\\uDD50','yscr':'\\\\uD835\\\\uDCCE','Yscr':'\\\\uD835\\\\uDCB4','yucy':'\\\\u044E','YUcy':'\\\\u042E','yuml':'\\\\xFF','Yuml':'\\\\u0178','zacute':'\\\\u017A','Zacute':'\\\\u0179','zcaron':'\\\\u017E','Zcaron':'\\\\u017D','zcy':'\\\\u0437','Zcy':'\\\\u0417','zdot':'\\\\u017C','Zdot':'\\\\u017B','zeetrf':'\\\\u2128','ZeroWidthSpace':'\\\\u200B','zeta':'\\\\u03B6','Zeta':'\\\\u0396','zfr':'\\\\uD835\\\\uDD37','Zfr':'\\\\u2128','zhcy':'\\\\u0436','ZHcy':'\\\\u0416','zigrarr':'\\\\u21DD','zopf':'\\\\uD835\\\\uDD6B','Zopf':'\\\\u2124','zscr':'\\\\uD835\\\\uDCCF','Zscr':'\\\\uD835\\\\uDCB5','zwj':'\\\\u200D','zwnj':'\\\\u200C'};\\n\\tvar decodeMapLegacy = {'aacute':'\\\\xE1','Aacute':'\\\\xC1','acirc':'\\\\xE2','Acirc':'\\\\xC2','acute':'\\\\xB4','aelig':'\\\\xE6','AElig':'\\\\xC6','agrave':'\\\\xE0','Agrave':'\\\\xC0','amp':'&','AMP':'&','aring':'\\\\xE5','Aring':'\\\\xC5','atilde':'\\\\xE3','Atilde':'\\\\xC3','auml':'\\\\xE4','Auml':'\\\\xC4','brvbar':'\\\\xA6','ccedil':'\\\\xE7','Ccedil':'\\\\xC7','cedil':'\\\\xB8','cent':'\\\\xA2','copy':'\\\\xA9','COPY':'\\\\xA9','curren':'\\\\xA4','deg':'\\\\xB0','divide':'\\\\xF7','eacute':'\\\\xE9','Eacute':'\\\\xC9','ecirc':'\\\\xEA','Ecirc':'\\\\xCA','egrave':'\\\\xE8','Egrave':'\\\\xC8','eth':'\\\\xF0','ETH':'\\\\xD0','euml':'\\\\xEB','Euml':'\\\\xCB','frac12':'\\\\xBD','frac14':'\\\\xBC','frac34':'\\\\xBE','gt':'>','GT':'>','iacute':'\\\\xED','Iacute':'\\\\xCD','icirc':'\\\\xEE','Icirc':'\\\\xCE','iexcl':'\\\\xA1','igrave':'\\\\xEC','Igrave':'\\\\xCC','iquest':'\\\\xBF','iuml':'\\\\xEF','Iuml':'\\\\xCF','laquo':'\\\\xAB','lt':'<','LT':'<','macr':'\\\\xAF','micro':'\\\\xB5','middot':'\\\\xB7','nbsp':'\\\\xA0','not':'\\\\xAC','ntilde':'\\\\xF1','Ntilde':'\\\\xD1','oacute':'\\\\xF3','Oacute':'\\\\xD3','ocirc':'\\\\xF4','Ocirc':'\\\\xD4','ograve':'\\\\xF2','Ograve':'\\\\xD2','ordf':'\\\\xAA','ordm':'\\\\xBA','oslash':'\\\\xF8','Oslash':'\\\\xD8','otilde':'\\\\xF5','Otilde':'\\\\xD5','ouml':'\\\\xF6','Ouml':'\\\\xD6','para':'\\\\xB6','plusmn':'\\\\xB1','pound':'\\\\xA3','quot':'\\\"','QUOT':'\\\"','raquo':'\\\\xBB','reg':'\\\\xAE','REG':'\\\\xAE','sect':'\\\\xA7','shy':'\\\\xAD','sup1':'\\\\xB9','sup2':'\\\\xB2','sup3':'\\\\xB3','szlig':'\\\\xDF','thorn':'\\\\xFE','THORN':'\\\\xDE','times':'\\\\xD7','uacute':'\\\\xFA','Uacute':'\\\\xDA','ucirc':'\\\\xFB','Ucirc':'\\\\xDB','ugrave':'\\\\xF9','Ugrave':'\\\\xD9','uml':'\\\\xA8','uuml':'\\\\xFC','Uuml':'\\\\xDC','yacute':'\\\\xFD','Yacute':'\\\\xDD','yen':'\\\\xA5','yuml':'\\\\xFF'};\\n\\tvar decodeMapNumeric = {'0':'\\\\uFFFD','128':'\\\\u20AC','130':'\\\\u201A','131':'\\\\u0192','132':'\\\\u201E','133':'\\\\u2026','134':'\\\\u2020','135':'\\\\u2021','136':'\\\\u02C6','137':'\\\\u2030','138':'\\\\u0160','139':'\\\\u2039','140':'\\\\u0152','142':'\\\\u017D','145':'\\\\u2018','146':'\\\\u2019','147':'\\\\u201C','148':'\\\\u201D','149':'\\\\u2022','150':'\\\\u2013','151':'\\\\u2014','152':'\\\\u02DC','153':'\\\\u2122','154':'\\\\u0161','155':'\\\\u203A','156':'\\\\u0153','158':'\\\\u017E','159':'\\\\u0178'};\\n\\tvar invalidReferenceCodePoints = [1,2,3,4,5,6,7,8,11,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,64976,64977,64978,64979,64980,64981,64982,64983,64984,64985,64986,64987,64988,64989,64990,64991,64992,64993,64994,64995,64996,64997,64998,64999,65000,65001,65002,65003,65004,65005,65006,65007,65534,65535,131070,131071,196606,196607,262142,262143,327678,327679,393214,393215,458750,458751,524286,524287,589822,589823,655358,655359,720894,720895,786430,786431,851966,851967,917502,917503,983038,983039,1048574,1048575,1114110,1114111];\\n\\n\\t/*--------------------------------------------------------------------------*/\\n\\n\\tvar stringFromCharCode = String.fromCharCode;\\n\\n\\tvar object = {};\\n\\tvar hasOwnProperty = object.hasOwnProperty;\\n\\tvar has = function(object, propertyName) {\\n\\t\\treturn hasOwnProperty.call(object, propertyName);\\n\\t};\\n\\n\\tvar contains = function(array, value) {\\n\\t\\tvar index = -1;\\n\\t\\tvar length = array.length;\\n\\t\\twhile (++index < length) {\\n\\t\\t\\tif (array[index] == value) {\\n\\t\\t\\t\\treturn true;\\n\\t\\t\\t}\\n\\t\\t}\\n\\t\\treturn false;\\n\\t};\\n\\n\\tvar merge = function(options, defaults) {\\n\\t\\tif (!options) {\\n\\t\\t\\treturn defaults;\\n\\t\\t}\\n\\t\\tvar result = {};\\n\\t\\tvar key;\\n\\t\\tfor (key in defaults) {\\n\\t\\t\\t// A `hasOwnProperty` check is not needed here, since only recognized\\n\\t\\t\\t// option names are used anyway. Any others are ignored.\\n\\t\\t\\tresult[key] = has(options, key) ? options[key] : defaults[key];\\n\\t\\t}\\n\\t\\treturn result;\\n\\t};\\n\\n\\t// Modified version of `ucs2encode`; see https://mths.be/punycode.\\n\\tvar codePointToSymbol = function(codePoint, strict) {\\n\\t\\tvar output = '';\\n\\t\\tif ((codePoint >= 0xD800 && codePoint <= 0xDFFF) || codePoint > 0x10FFFF) {\\n\\t\\t\\t// See issue #4:\\n\\t\\t\\t// “Otherwise, if the number is in the range 0xD800 to 0xDFFF or is\\n\\t\\t\\t// greater than 0x10FFFF, then this is a parse error. Return a U+FFFD\\n\\t\\t\\t// REPLACEMENT CHARACTER.”\\n\\t\\t\\tif (strict) {\\n\\t\\t\\t\\tparseError('character reference outside the permissible Unicode range');\\n\\t\\t\\t}\\n\\t\\t\\treturn '\\\\uFFFD';\\n\\t\\t}\\n\\t\\tif (has(decodeMapNumeric, codePoint)) {\\n\\t\\t\\tif (strict) {\\n\\t\\t\\t\\tparseError('disallowed character reference');\\n\\t\\t\\t}\\n\\t\\t\\treturn decodeMapNumeric[codePoint];\\n\\t\\t}\\n\\t\\tif (strict && contains(invalidReferenceCodePoints, codePoint)) {\\n\\t\\t\\tparseError('disallowed character reference');\\n\\t\\t}\\n\\t\\tif (codePoint > 0xFFFF) {\\n\\t\\t\\tcodePoint -= 0x10000;\\n\\t\\t\\toutput += stringFromCharCode(codePoint >>> 10 & 0x3FF | 0xD800);\\n\\t\\t\\tcodePoint = 0xDC00 | codePoint & 0x3FF;\\n\\t\\t}\\n\\t\\toutput += stringFromCharCode(codePoint);\\n\\t\\treturn output;\\n\\t};\\n\\n\\tvar hexEscape = function(codePoint) {\\n\\t\\treturn '&#x' + codePoint.toString(16).toUpperCase() + ';';\\n\\t};\\n\\n\\tvar decEscape = function(codePoint) {\\n\\t\\treturn '&#' + codePoint + ';';\\n\\t};\\n\\n\\tvar parseError = function(message) {\\n\\t\\tthrow Error('Parse error: ' + message);\\n\\t};\\n\\n\\t/*--------------------------------------------------------------------------*/\\n\\n\\tvar encode = function(string, options) {\\n\\t\\toptions = merge(options, encode.options);\\n\\t\\tvar strict = options.strict;\\n\\t\\tif (strict && regexInvalidRawCodePoint.test(string)) {\\n\\t\\t\\tparseError('forbidden code point');\\n\\t\\t}\\n\\t\\tvar encodeEverything = options.encodeEverything;\\n\\t\\tvar useNamedReferences = options.useNamedReferences;\\n\\t\\tvar allowUnsafeSymbols = options.allowUnsafeSymbols;\\n\\t\\tvar escapeCodePoint = options.decimal ? decEscape : hexEscape;\\n\\n\\t\\tvar escapeBmpSymbol = function(symbol) {\\n\\t\\t\\treturn escapeCodePoint(symbol.charCodeAt(0));\\n\\t\\t};\\n\\n\\t\\tif (encodeEverything) {\\n\\t\\t\\t// Encode ASCII symbols.\\n\\t\\t\\tstring = string.replace(regexAsciiWhitelist, function(symbol) {\\n\\t\\t\\t\\t// Use named references if requested & possible.\\n\\t\\t\\t\\tif (useNamedReferences && has(encodeMap, symbol)) {\\n\\t\\t\\t\\t\\treturn '&' + encodeMap[symbol] + ';';\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\treturn escapeBmpSymbol(symbol);\\n\\t\\t\\t});\\n\\t\\t\\t// Shorten a few escapes that represent two symbols, of which at least one\\n\\t\\t\\t// is within the ASCII range.\\n\\t\\t\\tif (useNamedReferences) {\\n\\t\\t\\t\\tstring = string\\n\\t\\t\\t\\t\\t.replace(/>\\\\u20D2/g, '>⃒')\\n\\t\\t\\t\\t\\t.replace(/<\\\\u20D2/g, '<⃒')\\n\\t\\t\\t\\t\\t.replace(/fj/g, 'fj');\\n\\t\\t\\t}\\n\\t\\t\\t// Encode non-ASCII symbols.\\n\\t\\t\\tif (useNamedReferences) {\\n\\t\\t\\t\\t// Encode non-ASCII symbols that can be replaced with a named reference.\\n\\t\\t\\t\\tstring = string.replace(regexEncodeNonAscii, function(string) {\\n\\t\\t\\t\\t\\t// Note: there is no need to check `has(encodeMap, string)` here.\\n\\t\\t\\t\\t\\treturn '&' + encodeMap[string] + ';';\\n\\t\\t\\t\\t});\\n\\t\\t\\t}\\n\\t\\t\\t// Note: any remaining non-ASCII symbols are handled outside of the `if`.\\n\\t\\t} else if (useNamedReferences) {\\n\\t\\t\\t// Apply named character references.\\n\\t\\t\\t// Encode `<>\\\"'&` using named character references.\\n\\t\\t\\tif (!allowUnsafeSymbols) {\\n\\t\\t\\t\\tstring = string.replace(regexEscape, function(string) {\\n\\t\\t\\t\\t\\treturn '&' + encodeMap[string] + ';'; // no need to check `has()` here\\n\\t\\t\\t\\t});\\n\\t\\t\\t}\\n\\t\\t\\t// Shorten escapes that represent two symbols, of which at least one is\\n\\t\\t\\t// `<>\\\"'&`.\\n\\t\\t\\tstring = string\\n\\t\\t\\t\\t.replace(/>\\\\u20D2/g, '>⃒')\\n\\t\\t\\t\\t.replace(/<\\\\u20D2/g, '<⃒');\\n\\t\\t\\t// Encode non-ASCII symbols that can be replaced with a named reference.\\n\\t\\t\\tstring = string.replace(regexEncodeNonAscii, function(string) {\\n\\t\\t\\t\\t// Note: there is no need to check `has(encodeMap, string)` here.\\n\\t\\t\\t\\treturn '&' + encodeMap[string] + ';';\\n\\t\\t\\t});\\n\\t\\t} else if (!allowUnsafeSymbols) {\\n\\t\\t\\t// Encode `<>\\\"'&` using hexadecimal escapes, now that they’re not handled\\n\\t\\t\\t// using named character references.\\n\\t\\t\\tstring = string.replace(regexEscape, escapeBmpSymbol);\\n\\t\\t}\\n\\t\\treturn string\\n\\t\\t\\t// Encode astral symbols.\\n\\t\\t\\t.replace(regexAstralSymbols, function($0) {\\n\\t\\t\\t\\t// https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae\\n\\t\\t\\t\\tvar high = $0.charCodeAt(0);\\n\\t\\t\\t\\tvar low = $0.charCodeAt(1);\\n\\t\\t\\t\\tvar codePoint = (high - 0xD800) * 0x400 + low - 0xDC00 + 0x10000;\\n\\t\\t\\t\\treturn escapeCodePoint(codePoint);\\n\\t\\t\\t})\\n\\t\\t\\t// Encode any remaining BMP symbols that are not printable ASCII symbols\\n\\t\\t\\t// using a hexadecimal escape.\\n\\t\\t\\t.replace(regexBmpWhitelist, escapeBmpSymbol);\\n\\t};\\n\\t// Expose default options (so they can be overridden globally).\\n\\tencode.options = {\\n\\t\\t'allowUnsafeSymbols': false,\\n\\t\\t'encodeEverything': false,\\n\\t\\t'strict': false,\\n\\t\\t'useNamedReferences': false,\\n\\t\\t'decimal' : false\\n\\t};\\n\\n\\tvar decode = function(html, options) {\\n\\t\\toptions = merge(options, decode.options);\\n\\t\\tvar strict = options.strict;\\n\\t\\tif (strict && regexInvalidEntity.test(html)) {\\n\\t\\t\\tparseError('malformed character reference');\\n\\t\\t}\\n\\t\\treturn html.replace(regexDecode, function($0, $1, $2, $3, $4, $5, $6, $7, $8) {\\n\\t\\t\\tvar codePoint;\\n\\t\\t\\tvar semicolon;\\n\\t\\t\\tvar decDigits;\\n\\t\\t\\tvar hexDigits;\\n\\t\\t\\tvar reference;\\n\\t\\t\\tvar next;\\n\\n\\t\\t\\tif ($1) {\\n\\t\\t\\t\\treference = $1;\\n\\t\\t\\t\\t// Note: there is no need to check `has(decodeMap, reference)`.\\n\\t\\t\\t\\treturn decodeMap[reference];\\n\\t\\t\\t}\\n\\n\\t\\t\\tif ($2) {\\n\\t\\t\\t\\t// Decode named character references without trailing `;`, e.g. `&`.\\n\\t\\t\\t\\t// This is only a parse error if it gets converted to `&`, or if it is\\n\\t\\t\\t\\t// followed by `=` in an attribute context.\\n\\t\\t\\t\\treference = $2;\\n\\t\\t\\t\\tnext = $3;\\n\\t\\t\\t\\tif (next && options.isAttributeValue) {\\n\\t\\t\\t\\t\\tif (strict && next == '=') {\\n\\t\\t\\t\\t\\t\\tparseError('`&` did not start a character reference');\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t\\treturn $0;\\n\\t\\t\\t\\t} else {\\n\\t\\t\\t\\t\\tif (strict) {\\n\\t\\t\\t\\t\\t\\tparseError(\\n\\t\\t\\t\\t\\t\\t\\t'named character reference was not terminated by a semicolon'\\n\\t\\t\\t\\t\\t\\t);\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t\\t// Note: there is no need to check `has(decodeMapLegacy, reference)`.\\n\\t\\t\\t\\t\\treturn decodeMapLegacy[reference] + (next || '');\\n\\t\\t\\t\\t}\\n\\t\\t\\t}\\n\\n\\t\\t\\tif ($4) {\\n\\t\\t\\t\\t// Decode decimal escapes, e.g. `𝌆`.\\n\\t\\t\\t\\tdecDigits = $4;\\n\\t\\t\\t\\tsemicolon = $5;\\n\\t\\t\\t\\tif (strict && !semicolon) {\\n\\t\\t\\t\\t\\tparseError('character reference was not terminated by a semicolon');\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tcodePoint = parseInt(decDigits, 10);\\n\\t\\t\\t\\treturn codePointToSymbol(codePoint, strict);\\n\\t\\t\\t}\\n\\n\\t\\t\\tif ($6) {\\n\\t\\t\\t\\t// Decode hexadecimal escapes, e.g. `𝌆`.\\n\\t\\t\\t\\thexDigits = $6;\\n\\t\\t\\t\\tsemicolon = $7;\\n\\t\\t\\t\\tif (strict && !semicolon) {\\n\\t\\t\\t\\t\\tparseError('character reference was not terminated by a semicolon');\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tcodePoint = parseInt(hexDigits, 16);\\n\\t\\t\\t\\treturn codePointToSymbol(codePoint, strict);\\n\\t\\t\\t}\\n\\n\\t\\t\\t// If we’re still here, `if ($7)` is implied; it’s an ambiguous\\n\\t\\t\\t// ampersand for sure. https://mths.be/notes/ambiguous-ampersands\\n\\t\\t\\tif (strict) {\\n\\t\\t\\t\\tparseError(\\n\\t\\t\\t\\t\\t'named character reference was not terminated by a semicolon'\\n\\t\\t\\t\\t);\\n\\t\\t\\t}\\n\\t\\t\\treturn $0;\\n\\t\\t});\\n\\t};\\n\\t// Expose default options (so they can be overridden globally).\\n\\tdecode.options = {\\n\\t\\t'isAttributeValue': false,\\n\\t\\t'strict': false\\n\\t};\\n\\n\\tvar escape = function(string) {\\n\\t\\treturn string.replace(regexEscape, function($0) {\\n\\t\\t\\t// Note: there is no need to check `has(escapeMap, $0)` here.\\n\\t\\t\\treturn escapeMap[$0];\\n\\t\\t});\\n\\t};\\n\\n\\t/*--------------------------------------------------------------------------*/\\n\\n\\tvar he = {\\n\\t\\t'version': '1.2.0',\\n\\t\\t'encode': encode,\\n\\t\\t'decode': decode,\\n\\t\\t'escape': escape,\\n\\t\\t'unescape': decode\\n\\t};\\n\\n\\t// Some AMD build optimizers, like r.js, check for specific condition patterns\\n\\t// like the following:\\n\\tif (\\n\\t\\ttypeof define == 'function' &&\\n\\t\\ttypeof define.amd == 'object' &&\\n\\t\\tdefine.amd\\n\\t) {\\n\\t\\tdefine(function() {\\n\\t\\t\\treturn he;\\n\\t\\t});\\n\\t}\\telse if (freeExports && !freeExports.nodeType) {\\n\\t\\tif (freeModule) { // in Node.js, io.js, or RingoJS v0.8.0+\\n\\t\\t\\tfreeModule.exports = he;\\n\\t\\t} else { // in Narwhal or RingoJS v0.7.0-\\n\\t\\t\\tfor (var key in he) {\\n\\t\\t\\t\\thas(he, key) && (freeExports[key] = he[key]);\\n\\t\\t\\t}\\n\\t\\t}\\n\\t} else { // in Rhino or a web browser\\n\\t\\troot.he = he;\\n\\t}\\n\\n}(this));\\n\",\"/* globals define,module */\\n/*\\nUsing a Universal Module Loader that should be browser, require, and AMD friendly\\nhttp://ricostacruz.com/cheatsheets/umdjs.html\\n*/\\n;(function(root, factory) {\\n if (typeof define === \\\"function\\\" && define.amd) {\\n define(factory);\\n } else if (typeof exports === \\\"object\\\") {\\n module.exports = factory();\\n } else {\\n root.jsonLogic = factory();\\n }\\n}(this, function() {\\n \\\"use strict\\\";\\n /* globals console:false */\\n\\n if ( ! Array.isArray) {\\n Array.isArray = function(arg) {\\n return Object.prototype.toString.call(arg) === \\\"[object Array]\\\";\\n };\\n }\\n\\n /**\\n * Return an array that contains no duplicates (original not modified)\\n * @param {array} array Original reference array\\n * @return {array} New array with no duplicates\\n */\\n function arrayUnique(array) {\\n var a = [];\\n for (var i=0, l=array.length; i\\\": function(a, b) {\\n return a > b;\\n },\\n \\\">=\\\": function(a, b) {\\n return a >= b;\\n },\\n \\\"<\\\": function(a, b, c) {\\n return (c === undefined) ? a < b : (a < b) && (b < c);\\n },\\n \\\"<=\\\": function(a, b, c) {\\n return (c === undefined) ? a <= b : (a <= b) && (b <= c);\\n },\\n \\\"!!\\\": function(a) {\\n return jsonLogic.truthy(a);\\n },\\n \\\"!\\\": function(a) {\\n return !jsonLogic.truthy(a);\\n },\\n \\\"%\\\": function(a, b) {\\n return a % b;\\n },\\n \\\"log\\\": function(a) {\\n console.log(a); return a;\\n },\\n \\\"in\\\": function(a, b) {\\n if (!b || typeof b.indexOf === \\\"undefined\\\") return false;\\n return (b.indexOf(a) !== -1);\\n },\\n \\\"cat\\\": function() {\\n return Array.prototype.join.call(arguments, \\\"\\\");\\n },\\n \\\"substr\\\": function(source, start, end) {\\n if (end < 0) {\\n // JavaScript doesn't support negative end, this emulates PHP behavior\\n var temp = String(source).substr(start);\\n return temp.substr(0, temp.length + end);\\n }\\n return String(source).substr(start, end);\\n },\\n \\\"+\\\": function() {\\n return Array.prototype.reduce.call(arguments, function(a, b) {\\n return parseFloat(a, 10) + parseFloat(b, 10);\\n }, 0);\\n },\\n \\\"*\\\": function() {\\n return Array.prototype.reduce.call(arguments, function(a, b) {\\n return parseFloat(a, 10) * parseFloat(b, 10);\\n });\\n },\\n \\\"-\\\": function(a, b) {\\n if (b === undefined) {\\n return -a;\\n } else {\\n return a - b;\\n }\\n },\\n \\\"/\\\": function(a, b) {\\n return a / b;\\n },\\n \\\"min\\\": function() {\\n return Math.min.apply(this, arguments);\\n },\\n \\\"max\\\": function() {\\n return Math.max.apply(this, arguments);\\n },\\n \\\"merge\\\": function() {\\n return Array.prototype.reduce.call(arguments, function(a, b) {\\n return a.concat(b);\\n }, []);\\n },\\n \\\"var\\\": function(a, b) {\\n var not_found = (b === undefined) ? null : b;\\n var data = this;\\n if (typeof a === \\\"undefined\\\" || a===\\\"\\\" || a===null) {\\n return data;\\n }\\n var sub_props = String(a).split(\\\".\\\");\\n for (var i = 0; i < sub_props.length; i++) {\\n if (data === null || data === undefined) {\\n return not_found;\\n }\\n // Descending into data\\n data = data[sub_props[i]];\\n if (data === undefined) {\\n return not_found;\\n }\\n }\\n return data;\\n },\\n \\\"missing\\\": function() {\\n /*\\n Missing can receive many keys as many arguments, like {\\\"missing:[1,2]}\\n Missing can also receive *one* argument that is an array of keys,\\n which typically happens if it's actually acting on the output of another command\\n (like 'if' or 'merge')\\n */\\n\\n var missing = [];\\n var keys = Array.isArray(arguments[0]) ? arguments[0] : arguments;\\n\\n for (var i = 0; i < keys.length; i++) {\\n var key = keys[i];\\n var value = jsonLogic.apply({\\\"var\\\": key}, this);\\n if (value === null || value === \\\"\\\") {\\n missing.push(key);\\n }\\n }\\n\\n return missing;\\n },\\n \\\"missing_some\\\": function(need_count, options) {\\n // missing_some takes two arguments, how many (minimum) items must be present, and an array of keys (just like 'missing') to check for presence.\\n var are_missing = jsonLogic.apply({\\\"missing\\\": options}, this);\\n\\n if (options.length - are_missing.length >= need_count) {\\n return [];\\n } else {\\n return are_missing;\\n }\\n },\\n };\\n\\n jsonLogic.is_logic = function(logic) {\\n return (\\n typeof logic === \\\"object\\\" && // An object\\n logic !== null && // but not null\\n ! Array.isArray(logic) && // and not an array\\n Object.keys(logic).length === 1 // with exactly one key\\n );\\n };\\n\\n /*\\n This helper will defer to the JsonLogic spec as a tie-breaker when different language interpreters define different behavior for the truthiness of primitives. E.g., PHP considers empty arrays to be falsy, but Javascript considers them to be truthy. JsonLogic, as an ecosystem, needs one consistent answer.\\n\\n Spec and rationale here: http://jsonlogic.com/truthy\\n */\\n jsonLogic.truthy = function(value) {\\n if (Array.isArray(value) && value.length === 0) {\\n return false;\\n }\\n return !! value;\\n };\\n\\n\\n jsonLogic.get_operator = function(logic) {\\n return Object.keys(logic)[0];\\n };\\n\\n jsonLogic.get_values = function(logic) {\\n return logic[jsonLogic.get_operator(logic)];\\n };\\n\\n jsonLogic.apply = function(logic, data) {\\n // Does this array contain logic? Only one way to find out.\\n if (Array.isArray(logic)) {\\n return logic.map(function(l) {\\n return jsonLogic.apply(l, data);\\n });\\n }\\n // You've recursed to a primitive, stop!\\n if ( ! jsonLogic.is_logic(logic) ) {\\n return logic;\\n }\\n\\n var op = jsonLogic.get_operator(logic);\\n var values = logic[op];\\n var i;\\n var current;\\n var scopedLogic;\\n var scopedData;\\n var initial;\\n\\n // easy syntax for unary operators, like {\\\"var\\\" : \\\"x\\\"} instead of strict {\\\"var\\\" : [\\\"x\\\"]}\\n if ( ! Array.isArray(values)) {\\n values = [values];\\n }\\n\\n // 'if', 'and', and 'or' violate the normal rule of depth-first calculating consequents, let each manage recursion as needed.\\n if (op === \\\"if\\\" || op == \\\"?:\\\") {\\n /* 'if' should be called with a odd number of parameters, 3 or greater\\n This works on the pattern:\\n if( 0 ){ 1 }else{ 2 };\\n if( 0 ){ 1 }else if( 2 ){ 3 }else{ 4 };\\n if( 0 ){ 1 }else if( 2 ){ 3 }else if( 4 ){ 5 }else{ 6 };\\n\\n The implementation is:\\n For pairs of values (0,1 then 2,3 then 4,5 etc)\\n If the first evaluates truthy, evaluate and return the second\\n If the first evaluates falsy, jump to the next pair (e.g, 0,1 to 2,3)\\n given one parameter, evaluate and return it. (it's an Else and all the If/ElseIf were false)\\n given 0 parameters, return NULL (not great practice, but there was no Else)\\n */\\n for (i = 0; i < values.length - 1; i += 2) {\\n if ( jsonLogic.truthy( jsonLogic.apply(values[i], data) ) ) {\\n return jsonLogic.apply(values[i+1], data);\\n }\\n }\\n if (values.length === i+1) {\\n return jsonLogic.apply(values[i], data);\\n }\\n return null;\\n } else if (op === \\\"and\\\") { // Return first falsy, or last\\n for (i=0; i < values.length; i+=1) {\\n current = jsonLogic.apply(values[i], data);\\n if ( ! jsonLogic.truthy(current)) {\\n return current;\\n }\\n }\\n return current; // Last\\n } else if (op === \\\"or\\\") {// Return first truthy, or last\\n for (i=0; i < values.length; i+=1) {\\n current = jsonLogic.apply(values[i], data);\\n if ( jsonLogic.truthy(current) ) {\\n return current;\\n }\\n }\\n return current; // Last\\n } else if (op === \\\"filter\\\") {\\n scopedData = jsonLogic.apply(values[0], data);\\n scopedLogic = values[1];\\n\\n if ( ! Array.isArray(scopedData)) {\\n return [];\\n }\\n // Return only the elements from the array in the first argument,\\n // that return truthy when passed to the logic in the second argument.\\n // For parity with JavaScript, reindex the returned array\\n return scopedData.filter(function(datum) {\\n return jsonLogic.truthy( jsonLogic.apply(scopedLogic, datum));\\n });\\n } else if (op === \\\"map\\\") {\\n scopedData = jsonLogic.apply(values[0], data);\\n scopedLogic = values[1];\\n\\n if ( ! Array.isArray(scopedData)) {\\n return [];\\n }\\n\\n return scopedData.map(function(datum) {\\n return jsonLogic.apply(scopedLogic, datum);\\n });\\n } else if (op === \\\"reduce\\\") {\\n scopedData = jsonLogic.apply(values[0], data);\\n scopedLogic = values[1];\\n initial = typeof values[2] !== \\\"undefined\\\" ? jsonLogic.apply(values[2], data) : null;\\n\\n if ( ! Array.isArray(scopedData)) {\\n return initial;\\n }\\n\\n return scopedData.reduce(\\n function(accumulator, current) {\\n return jsonLogic.apply(\\n scopedLogic,\\n {current: current, accumulator: accumulator}\\n );\\n },\\n initial\\n );\\n } else if (op === \\\"all\\\") {\\n scopedData = jsonLogic.apply(values[0], data);\\n scopedLogic = values[1];\\n // All of an empty set is false. Note, some and none have correct fallback after the for loop\\n if ( ! Array.isArray(scopedData) || ! scopedData.length) {\\n return false;\\n }\\n for (i=0; i < scopedData.length; i+=1) {\\n if ( ! jsonLogic.truthy( jsonLogic.apply(scopedLogic, scopedData[i]) )) {\\n return false; // First falsy, short circuit\\n }\\n }\\n return true; // All were truthy\\n } else if (op === \\\"none\\\") {\\n scopedData = jsonLogic.apply(values[0], data);\\n scopedLogic = values[1];\\n\\n if ( ! Array.isArray(scopedData) || ! scopedData.length) {\\n return true;\\n }\\n for (i=0; i < scopedData.length; i+=1) {\\n if ( jsonLogic.truthy( jsonLogic.apply(scopedLogic, scopedData[i]) )) {\\n return false; // First truthy, short circuit\\n }\\n }\\n return true; // None were truthy\\n } else if (op === \\\"some\\\") {\\n scopedData = jsonLogic.apply(values[0], data);\\n scopedLogic = values[1];\\n\\n if ( ! Array.isArray(scopedData) || ! scopedData.length) {\\n return false;\\n }\\n for (i=0; i < scopedData.length; i+=1) {\\n if ( jsonLogic.truthy( jsonLogic.apply(scopedLogic, scopedData[i]) )) {\\n return true; // First truthy, short circuit\\n }\\n }\\n return false; // None were truthy\\n }\\n\\n // Everyone else gets immediate depth-first recursion\\n values = values.map(function(val) {\\n return jsonLogic.apply(val, data);\\n });\\n\\n\\n // The operation is called with \\\"data\\\" bound to its \\\"this\\\" and \\\"values\\\" passed as arguments.\\n // Structured commands like % or > can name formal arguments while flexible commands (like missing or merge) can operate on the pseudo-array arguments\\n // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments\\n if (operations.hasOwnProperty(op) && typeof operations[op] === \\\"function\\\") {\\n return operations[op].apply(data, values);\\n } else if (op.indexOf(\\\".\\\") > 0) { // Contains a dot, and not in the 0th position\\n var sub_ops = String(op).split(\\\".\\\");\\n var operation = operations;\\n for (i = 0; i < sub_ops.length; i++) {\\n if (!operation.hasOwnProperty(sub_ops[i])) {\\n throw new Error(\\\"Unrecognized operation \\\" + op +\\n \\\" (failed at \\\" + sub_ops.slice(0, i+1).join(\\\".\\\") + \\\")\\\");\\n }\\n // Descending into operations\\n operation = operation[sub_ops[i]];\\n }\\n\\n return operation.apply(data, values);\\n }\\n\\n throw new Error(\\\"Unrecognized operation \\\" + op );\\n };\\n\\n jsonLogic.uses_data = function(logic) {\\n var collection = [];\\n\\n if (jsonLogic.is_logic(logic)) {\\n var op = jsonLogic.get_operator(logic);\\n var values = logic[op];\\n\\n if ( ! Array.isArray(values)) {\\n values = [values];\\n }\\n\\n if (op === \\\"var\\\") {\\n // This doesn't cover the case where the arg to var is itself a rule.\\n collection.push(values[0]);\\n } else {\\n // Recursion!\\n values.forEach(function(val) {\\n collection.push.apply(collection, jsonLogic.uses_data(val) );\\n });\\n }\\n }\\n\\n return arrayUnique(collection);\\n };\\n\\n jsonLogic.add_operation = function(name, code) {\\n operations[name] = code;\\n };\\n\\n jsonLogic.rm_operation = function(name) {\\n delete operations[name];\\n };\\n\\n jsonLogic.rule_like = function(rule, pattern) {\\n // console.log(\\\"Is \\\". JSON.stringify(rule) . \\\" like \\\" . JSON.stringify(pattern) . \\\"?\\\");\\n if (pattern === rule) {\\n return true;\\n } // TODO : Deep object equivalency?\\n if (pattern === \\\"@\\\") {\\n return true;\\n } // Wildcard!\\n if (pattern === \\\"number\\\") {\\n return (typeof rule === \\\"number\\\");\\n }\\n if (pattern === \\\"string\\\") {\\n return (typeof rule === \\\"string\\\");\\n }\\n if (pattern === \\\"array\\\") {\\n // !logic test might be superfluous in JavaScript\\n return Array.isArray(rule) && ! jsonLogic.is_logic(rule);\\n }\\n\\n if (jsonLogic.is_logic(pattern)) {\\n if (jsonLogic.is_logic(rule)) {\\n var pattern_op = jsonLogic.get_operator(pattern);\\n var rule_op = jsonLogic.get_operator(rule);\\n\\n if (pattern_op === \\\"@\\\" || pattern_op === rule_op) {\\n // echo \\\"\\\\nOperators match, go deeper\\\\n\\\";\\n return jsonLogic.rule_like(\\n jsonLogic.get_values(rule, false),\\n jsonLogic.get_values(pattern, false)\\n );\\n }\\n }\\n return false; // pattern is logic, rule isn't, can't be eq\\n }\\n\\n if (Array.isArray(pattern)) {\\n if (Array.isArray(rule)) {\\n if (pattern.length !== rule.length) {\\n return false;\\n }\\n /*\\n Note, array order MATTERS, because we're using this array test logic to consider arguments, where order can matter. (e.g., + is commutative, but '-' or 'if' or 'var' are NOT)\\n */\\n for (var i = 0; i < pattern.length; i += 1) {\\n // If any fail, we fail\\n if ( ! jsonLogic.rule_like(rule[i], pattern[i])) {\\n return false;\\n }\\n }\\n return true; // If they *all* passed, we pass\\n } else {\\n return false; // Pattern is array, rule isn't\\n }\\n }\\n\\n // Not logic, not array, not a === match for rule.\\n return false;\\n };\\n\\n return jsonLogic;\\n}));\\n\",\"const DEFAULT_DELIMITER = \\\"/\\\";\\nconst NOOP_VALUE = (value: string) => value;\\nconst ID_START = /^[$_\\\\p{ID_Start}]$/u;\\nconst ID_CONTINUE = /^[$\\\\u200c\\\\u200d\\\\p{ID_Continue}]$/u;\\n\\n/**\\n * Encode a string into another string.\\n */\\nexport type Encode = (value: string) => string;\\n\\n/**\\n * Decode a string into another string.\\n */\\nexport type Decode = (value: string) => string;\\n\\nexport interface ParseOptions {\\n /**\\n * A function for encoding input strings.\\n */\\n encodePath?: Encode;\\n}\\n\\nexport interface PathToRegexpOptions {\\n /**\\n * Matches the path completely without trailing characters. (default: `true`)\\n */\\n end?: boolean;\\n /**\\n * Allows optional trailing delimiter to match. (default: `true`)\\n */\\n trailing?: boolean;\\n /**\\n * Match will be case sensitive. (default: `false`)\\n */\\n sensitive?: boolean;\\n /**\\n * The default delimiter for segments. (default: `'/'`)\\n */\\n delimiter?: string;\\n}\\n\\nexport interface MatchOptions extends PathToRegexpOptions {\\n /**\\n * Function for decoding strings for params, or `false` to disable entirely. (default: `decodeURIComponent`)\\n */\\n decode?: Decode | false;\\n}\\n\\nexport interface CompileOptions {\\n /**\\n * Function for encoding input strings for output into the path, or `false` to disable entirely. (default: `encodeURIComponent`)\\n */\\n encode?: Encode | false;\\n /**\\n * The default delimiter for segments. (default: `'/'`)\\n */\\n delimiter?: string;\\n}\\n\\ntype TokenType =\\n | \\\"{\\\"\\n | \\\"}\\\"\\n | \\\"wildcard\\\"\\n | \\\"param\\\"\\n | \\\"char\\\"\\n | \\\"escape\\\"\\n | \\\"end\\\"\\n // Reserved for use or ambiguous due to past use.\\n | \\\"(\\\"\\n | \\\")\\\"\\n | \\\"[\\\"\\n | \\\"]\\\"\\n | \\\"+\\\"\\n | \\\"?\\\"\\n | \\\"!\\\";\\n\\n/**\\n * Tokenizer results.\\n */\\ninterface LexToken {\\n type: TokenType;\\n index: number;\\n value: string;\\n}\\n\\nconst SIMPLE_TOKENS: Record = {\\n // Groups.\\n \\\"{\\\": \\\"{\\\",\\n \\\"}\\\": \\\"}\\\",\\n // Reserved.\\n \\\"(\\\": \\\"(\\\",\\n \\\")\\\": \\\")\\\",\\n \\\"[\\\": \\\"[\\\",\\n \\\"]\\\": \\\"]\\\",\\n \\\"+\\\": \\\"+\\\",\\n \\\"?\\\": \\\"?\\\",\\n \\\"!\\\": \\\"!\\\",\\n};\\n\\n/**\\n * Escape text for stringify to path.\\n */\\nfunction escapeText(str: string) {\\n return str.replace(/[{}()\\\\[\\\\]+?!:*\\\\\\\\]/g, \\\"\\\\\\\\$&\\\");\\n}\\n\\n/**\\n * Escape a regular expression string.\\n */\\nfunction escape(str: string) {\\n return str.replace(/[.+*?^${}()[\\\\]|/\\\\\\\\]/g, \\\"\\\\\\\\$&\\\");\\n}\\n\\n/**\\n * Plain text.\\n */\\nexport interface Text {\\n type: \\\"text\\\";\\n value: string;\\n}\\n\\n/**\\n * A parameter designed to match arbitrary text within a segment.\\n */\\nexport interface Parameter {\\n type: \\\"param\\\";\\n name: string;\\n}\\n\\n/**\\n * A wildcard parameter designed to match multiple segments.\\n */\\nexport interface Wildcard {\\n type: \\\"wildcard\\\";\\n name: string;\\n}\\n\\n/**\\n * A set of possible tokens to expand when matching.\\n */\\nexport interface Group {\\n type: \\\"group\\\";\\n tokens: Token[];\\n}\\n\\n/**\\n * A token that corresponds with a regexp capture.\\n */\\nexport type Key = Parameter | Wildcard;\\n\\n/**\\n * A sequence of `path-to-regexp` keys that match capturing groups.\\n */\\nexport type Keys = Array;\\n\\n/**\\n * A sequence of path match characters.\\n */\\nexport type Token = Text | Parameter | Wildcard | Group;\\n\\n/**\\n * Tokenized path instance.\\n */\\nexport class TokenData {\\n constructor(\\n public readonly tokens: Token[],\\n public readonly originalPath?: string,\\n ) {}\\n}\\n\\n/**\\n * ParseError is thrown when there is an error processing the path.\\n */\\nexport class PathError extends TypeError {\\n constructor(\\n message: string,\\n public readonly originalPath: string | undefined,\\n ) {\\n let text = message;\\n if (originalPath) text += `: ${originalPath}`;\\n text += `; visit https://git.new/pathToRegexpError for info`;\\n super(text);\\n }\\n}\\n\\n/**\\n * Parse a string for the raw tokens.\\n */\\nexport function parse(str: string, options: ParseOptions = {}): TokenData {\\n const { encodePath = NOOP_VALUE } = options;\\n const chars = [...str];\\n const tokens: Array = [];\\n let index = 0;\\n let pos = 0;\\n\\n function name() {\\n let value = \\\"\\\";\\n\\n if (ID_START.test(chars[index])) {\\n do {\\n value += chars[index++];\\n } while (ID_CONTINUE.test(chars[index]));\\n } else if (chars[index] === '\\\"') {\\n let quoteStart = index;\\n\\n while (index++ < chars.length) {\\n if (chars[index] === '\\\"') {\\n index++;\\n quoteStart = 0;\\n break;\\n }\\n\\n // Increment over escape characters.\\n if (chars[index] === \\\"\\\\\\\\\\\") index++;\\n\\n value += chars[index];\\n }\\n\\n if (quoteStart) {\\n throw new PathError(`Unterminated quote at index ${quoteStart}`, str);\\n }\\n }\\n\\n if (!value) {\\n throw new PathError(`Missing parameter name at index ${index}`, str);\\n }\\n\\n return value;\\n }\\n\\n while (index < chars.length) {\\n const value = chars[index];\\n const type = SIMPLE_TOKENS[value];\\n\\n if (type) {\\n tokens.push({ type, index: index++, value });\\n } else if (value === \\\"\\\\\\\\\\\") {\\n tokens.push({ type: \\\"escape\\\", index: index++, value: chars[index++] });\\n } else if (value === \\\":\\\") {\\n tokens.push({ type: \\\"param\\\", index: index++, value: name() });\\n } else if (value === \\\"*\\\") {\\n tokens.push({ type: \\\"wildcard\\\", index: index++, value: name() });\\n } else {\\n tokens.push({ type: \\\"char\\\", index: index++, value });\\n }\\n }\\n\\n tokens.push({ type: \\\"end\\\", index, value: \\\"\\\" });\\n\\n function consumeUntil(endType: TokenType): Token[] {\\n const output: Token[] = [];\\n\\n while (true) {\\n const token = tokens[pos++];\\n if (token.type === endType) break;\\n\\n if (token.type === \\\"char\\\" || token.type === \\\"escape\\\") {\\n let path = token.value;\\n let cur = tokens[pos];\\n\\n while (cur.type === \\\"char\\\" || cur.type === \\\"escape\\\") {\\n path += cur.value;\\n cur = tokens[++pos];\\n }\\n\\n output.push({\\n type: \\\"text\\\",\\n value: encodePath(path),\\n });\\n continue;\\n }\\n\\n if (token.type === \\\"param\\\" || token.type === \\\"wildcard\\\") {\\n output.push({\\n type: token.type,\\n name: token.value,\\n });\\n continue;\\n }\\n\\n if (token.type === \\\"{\\\") {\\n output.push({\\n type: \\\"group\\\",\\n tokens: consumeUntil(\\\"}\\\"),\\n });\\n continue;\\n }\\n\\n throw new PathError(\\n `Unexpected ${token.type} at index ${token.index}, expected ${endType}`,\\n str,\\n );\\n }\\n\\n return output;\\n }\\n\\n return new TokenData(consumeUntil(\\\"end\\\"), str);\\n}\\n\\n/**\\n * Compile a string to a template function for the path.\\n */\\nexport function compile

(\\n path: Path,\\n options: CompileOptions & ParseOptions = {},\\n) {\\n const { encode = encodeURIComponent, delimiter = DEFAULT_DELIMITER } =\\n options;\\n const data = typeof path === \\\"object\\\" ? path : parse(path, options);\\n const fn = tokensToFunction(data.tokens, delimiter, encode);\\n\\n return function path(params: P = {} as P) {\\n const [path, ...missing] = fn(params);\\n if (missing.length) {\\n throw new TypeError(`Missing parameters: ${missing.join(\\\", \\\")}`);\\n }\\n return path;\\n };\\n}\\n\\nexport type ParamData = Partial>;\\nexport type PathFunction

= (data?: P) => string;\\n\\nfunction tokensToFunction(\\n tokens: Token[],\\n delimiter: string,\\n encode: Encode | false,\\n) {\\n const encoders = tokens.map((token) =>\\n tokenToFunction(token, delimiter, encode),\\n );\\n\\n return (data: ParamData) => {\\n const result: string[] = [\\\"\\\"];\\n\\n for (const encoder of encoders) {\\n const [value, ...extras] = encoder(data);\\n result[0] += value;\\n result.push(...extras);\\n }\\n\\n return result;\\n };\\n}\\n\\n/**\\n * Convert a single token into a path building function.\\n */\\nfunction tokenToFunction(\\n token: Token,\\n delimiter: string,\\n encode: Encode | false,\\n): (data: ParamData) => string[] {\\n if (token.type === \\\"text\\\") return () => [token.value];\\n\\n if (token.type === \\\"group\\\") {\\n const fn = tokensToFunction(token.tokens, delimiter, encode);\\n\\n return (data) => {\\n const [value, ...missing] = fn(data);\\n if (!missing.length) return [value];\\n return [\\\"\\\"];\\n };\\n }\\n\\n const encodeValue = encode || NOOP_VALUE;\\n\\n if (token.type === \\\"wildcard\\\" && encode !== false) {\\n return (data) => {\\n const value = data[token.name];\\n if (value == null) return [\\\"\\\", token.name];\\n\\n if (!Array.isArray(value) || value.length === 0) {\\n throw new TypeError(`Expected \\\"${token.name}\\\" to be a non-empty array`);\\n }\\n\\n return [\\n value\\n .map((value, index) => {\\n if (typeof value !== \\\"string\\\") {\\n throw new TypeError(\\n `Expected \\\"${token.name}/${index}\\\" to be a string`,\\n );\\n }\\n\\n return encodeValue(value);\\n })\\n .join(delimiter),\\n ];\\n };\\n }\\n\\n return (data) => {\\n const value = data[token.name];\\n if (value == null) return [\\\"\\\", token.name];\\n\\n if (typeof value !== \\\"string\\\") {\\n throw new TypeError(`Expected \\\"${token.name}\\\" to be a string`);\\n }\\n\\n return [encodeValue(value)];\\n };\\n}\\n\\n/**\\n * A match result contains data about the path match.\\n */\\nexport interface MatchResult

{\\n path: string;\\n params: P;\\n}\\n\\n/**\\n * A match is either `false` (no match) or a match result.\\n */\\nexport type Match

= false | MatchResult

;\\n\\n/**\\n * The match function takes a string and returns whether it matched the path.\\n */\\nexport type MatchFunction

= (path: string) => Match

;\\n\\n/**\\n * Supported path types.\\n */\\nexport type Path = string | TokenData;\\n\\n/**\\n * Transform a path into a match function.\\n */\\nexport function match

(\\n path: Path | Path[],\\n options: MatchOptions & ParseOptions = {},\\n): MatchFunction

{\\n const { decode = decodeURIComponent, delimiter = DEFAULT_DELIMITER } =\\n options;\\n const { regexp, keys } = pathToRegexp(path, options);\\n\\n const decoders = keys.map((key) => {\\n if (decode === false) return NOOP_VALUE;\\n if (key.type === \\\"param\\\") return decode;\\n return (value: string) => value.split(delimiter).map(decode);\\n });\\n\\n return function match(input: string) {\\n const m = regexp.exec(input);\\n if (!m) return false;\\n\\n const path = m[0];\\n const params = Object.create(null);\\n\\n for (let i = 1; i < m.length; i++) {\\n if (m[i] === undefined) continue;\\n\\n const key = keys[i - 1];\\n const decoder = decoders[i - 1];\\n params[key.name] = decoder(m[i]);\\n }\\n\\n return { path, params };\\n };\\n}\\n\\nexport function pathToRegexp(\\n path: Path | Path[],\\n options: PathToRegexpOptions & ParseOptions = {},\\n) {\\n const {\\n delimiter = DEFAULT_DELIMITER,\\n end = true,\\n sensitive = false,\\n trailing = true,\\n } = options;\\n const keys: Keys = [];\\n const flags = sensitive ? \\\"\\\" : \\\"i\\\";\\n const sources: string[] = [];\\n\\n for (const input of pathsToArray(path, [])) {\\n const data = typeof input === \\\"object\\\" ? input : parse(input, options);\\n for (const tokens of flatten(data.tokens, 0, [])) {\\n sources.push(toRegExpSource(tokens, delimiter, keys, data.originalPath));\\n }\\n }\\n\\n let pattern = `^(?:${sources.join(\\\"|\\\")})`;\\n if (trailing) pattern += `(?:${escape(delimiter)}$)?`;\\n pattern += end ? \\\"$\\\" : `(?=${escape(delimiter)}|$)`;\\n\\n const regexp = new RegExp(pattern, flags);\\n return { regexp, keys };\\n}\\n\\n/**\\n * Convert a path or array of paths into a flat array.\\n */\\nfunction pathsToArray(paths: Path | Path[], init: Path[]): Path[] {\\n if (Array.isArray(paths)) {\\n for (const p of paths) pathsToArray(p, init);\\n } else {\\n init.push(paths);\\n }\\n return init;\\n}\\n\\n/**\\n * Flattened token set.\\n */\\ntype FlatToken = Text | Parameter | Wildcard;\\n\\n/**\\n * Generate a flat list of sequence tokens from the given tokens.\\n */\\nfunction* flatten(\\n tokens: Token[],\\n index: number,\\n init: FlatToken[],\\n): Generator {\\n if (index === tokens.length) {\\n return yield init;\\n }\\n\\n const token = tokens[index];\\n\\n if (token.type === \\\"group\\\") {\\n for (const seq of flatten(token.tokens, 0, init.slice())) {\\n yield* flatten(tokens, index + 1, seq);\\n }\\n } else {\\n init.push(token);\\n }\\n\\n yield* flatten(tokens, index + 1, init);\\n}\\n\\n/**\\n * Transform a flat sequence of tokens into a regular expression.\\n */\\nfunction toRegExpSource(\\n tokens: FlatToken[],\\n delimiter: string,\\n keys: Keys,\\n originalPath: string | undefined,\\n): string {\\n let result = \\\"\\\";\\n let backtrack = \\\"\\\";\\n let isSafeSegmentParam = true;\\n\\n for (const token of tokens) {\\n if (token.type === \\\"text\\\") {\\n result += escape(token.value);\\n backtrack += token.value;\\n isSafeSegmentParam ||= token.value.includes(delimiter);\\n continue;\\n }\\n\\n if (token.type === \\\"param\\\" || token.type === \\\"wildcard\\\") {\\n if (!isSafeSegmentParam && !backtrack) {\\n throw new PathError(\\n `Missing text before \\\"${token.name}\\\" ${token.type}`,\\n originalPath,\\n );\\n }\\n\\n if (token.type === \\\"param\\\") {\\n result += `(${negate(delimiter, isSafeSegmentParam ? \\\"\\\" : backtrack)}+)`;\\n } else {\\n result += `([\\\\\\\\s\\\\\\\\S]+)`;\\n }\\n\\n keys.push(token);\\n backtrack = \\\"\\\";\\n isSafeSegmentParam = false;\\n continue;\\n }\\n }\\n\\n return result;\\n}\\n\\n/**\\n * Block backtracking on previous text and ignore delimiter string.\\n */\\nfunction negate(delimiter: string, backtrack: string): string {\\n if (backtrack.length < 2) {\\n if (delimiter.length < 2) return `[^${escape(delimiter + backtrack)}]`;\\n return `(?:(?!${escape(delimiter)})[^${escape(backtrack)}])`;\\n }\\n if (delimiter.length < 2) {\\n return `(?:(?!${escape(backtrack)})[^${escape(delimiter)}])`;\\n }\\n return `(?:(?!${escape(backtrack)}|${escape(delimiter)})[\\\\\\\\s\\\\\\\\S])`;\\n}\\n\\n/**\\n * Stringify an array of tokens into a path string.\\n */\\nfunction stringifyTokens(tokens: Token[]): string {\\n let value = \\\"\\\";\\n let i = 0;\\n\\n function name(value: string) {\\n const isSafe = isNameSafe(value) && isNextNameSafe(tokens[i]);\\n return isSafe ? value : JSON.stringify(value);\\n }\\n\\n while (i < tokens.length) {\\n const token = tokens[i++];\\n\\n if (token.type === \\\"text\\\") {\\n value += escapeText(token.value);\\n continue;\\n }\\n\\n if (token.type === \\\"group\\\") {\\n value += `{${stringifyTokens(token.tokens)}}`;\\n continue;\\n }\\n\\n if (token.type === \\\"param\\\") {\\n value += `:${name(token.name)}`;\\n continue;\\n }\\n\\n if (token.type === \\\"wildcard\\\") {\\n value += `*${name(token.name)}`;\\n continue;\\n }\\n\\n throw new TypeError(`Unknown token type: ${(token as any).type}`);\\n }\\n\\n return value;\\n}\\n\\n/**\\n * Stringify token data into a path string.\\n */\\nexport function stringify(data: TokenData): string {\\n return stringifyTokens(data.tokens);\\n}\\n\\n/**\\n * Validate the parameter name contains valid ID characters.\\n */\\nfunction isNameSafe(name: string): boolean {\\n const [first, ...rest] = name;\\n return ID_START.test(first) && rest.every((char) => ID_CONTINUE.test(char));\\n}\\n\\n/**\\n * Validate the next token does not interfere with the current param name.\\n */\\nfunction isNextNameSafe(token: Token | undefined): boolean {\\n if (token && token.type === \\\"text\\\") return !ID_CONTINUE.test(token.value[0]);\\n return true;\\n}\\n\",\"'use strict'\\n\\n// Note: this is the semver.org version of the spec that it implements\\n// Not necessarily the package version of this code.\\nconst SEMVER_SPEC_VERSION = '2.0.0'\\n\\nconst MAX_LENGTH = 256\\nconst MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER ||\\n/* istanbul ignore next */ 9007199254740991\\n\\n// Max safe segment length for coercion.\\nconst MAX_SAFE_COMPONENT_LENGTH = 16\\n\\n// Max safe length for a build identifier. The max length minus 6 characters for\\n// the shortest version with a build 0.0.0+BUILD.\\nconst MAX_SAFE_BUILD_LENGTH = MAX_LENGTH - 6\\n\\nconst RELEASE_TYPES = [\\n 'major',\\n 'premajor',\\n 'minor',\\n 'preminor',\\n 'patch',\\n 'prepatch',\\n 'prerelease',\\n]\\n\\nmodule.exports = {\\n MAX_LENGTH,\\n MAX_SAFE_COMPONENT_LENGTH,\\n MAX_SAFE_BUILD_LENGTH,\\n MAX_SAFE_INTEGER,\\n RELEASE_TYPES,\\n SEMVER_SPEC_VERSION,\\n FLAG_INCLUDE_PRERELEASE: 0b001,\\n FLAG_LOOSE: 0b010,\\n}\\n\",\"'use strict'\\n\\nconst debug = (\\n typeof process === 'object' &&\\n process.env &&\\n process.env.NODE_DEBUG &&\\n /\\\\bsemver\\\\b/i.test(process.env.NODE_DEBUG)\\n) ? (...args) => console.error('SEMVER', ...args)\\n : () => {}\\n\\nmodule.exports = debug\\n\",\"'use strict'\\n\\nconst {\\n MAX_SAFE_COMPONENT_LENGTH,\\n MAX_SAFE_BUILD_LENGTH,\\n MAX_LENGTH,\\n} = require('./constants')\\nconst debug = require('./debug')\\nexports = module.exports = {}\\n\\n// The actual regexps go on exports.re\\nconst re = exports.re = []\\nconst safeRe = exports.safeRe = []\\nconst src = exports.src = []\\nconst safeSrc = exports.safeSrc = []\\nconst t = exports.t = {}\\nlet R = 0\\n\\nconst LETTERDASHNUMBER = '[a-zA-Z0-9-]'\\n\\n// Replace some greedy regex tokens to prevent regex dos issues. These regex are\\n// used internally via the safeRe object since all inputs in this library get\\n// normalized first to trim and collapse all extra whitespace. The original\\n// regexes are exported for userland consumption and lower level usage. A\\n// future breaking change could export the safer regex only with a note that\\n// all input should have extra whitespace removed.\\nconst safeRegexReplacements = [\\n ['\\\\\\\\s', 1],\\n ['\\\\\\\\d', MAX_LENGTH],\\n [LETTERDASHNUMBER, MAX_SAFE_BUILD_LENGTH],\\n]\\n\\nconst makeSafeRegex = (value) => {\\n for (const [token, max] of safeRegexReplacements) {\\n value = value\\n .split(`${token}*`).join(`${token}{0,${max}}`)\\n .split(`${token}+`).join(`${token}{1,${max}}`)\\n }\\n return value\\n}\\n\\nconst createToken = (name, value, isGlobal) => {\\n const safe = makeSafeRegex(value)\\n const index = R++\\n debug(name, index, value)\\n t[name] = index\\n src[index] = value\\n safeSrc[index] = safe\\n re[index] = new RegExp(value, isGlobal ? 'g' : undefined)\\n safeRe[index] = new RegExp(safe, isGlobal ? 'g' : undefined)\\n}\\n\\n// The following Regular Expressions can be used for tokenizing,\\n// validating, and parsing SemVer version strings.\\n\\n// ## Numeric Identifier\\n// A single `0`, or a non-zero digit followed by zero or more digits.\\n\\ncreateToken('NUMERICIDENTIFIER', '0|[1-9]\\\\\\\\d*')\\ncreateToken('NUMERICIDENTIFIERLOOSE', '\\\\\\\\d+')\\n\\n// ## Non-numeric Identifier\\n// Zero or more digits, followed by a letter or hyphen, and then zero or\\n// more letters, digits, or hyphens.\\n\\ncreateToken('NONNUMERICIDENTIFIER', `\\\\\\\\d*[a-zA-Z-]${LETTERDASHNUMBER}*`)\\n\\n// ## Main Version\\n// Three dot-separated numeric identifiers.\\n\\ncreateToken('MAINVERSION', `(${src[t.NUMERICIDENTIFIER]})\\\\\\\\.` +\\n `(${src[t.NUMERICIDENTIFIER]})\\\\\\\\.` +\\n `(${src[t.NUMERICIDENTIFIER]})`)\\n\\ncreateToken('MAINVERSIONLOOSE', `(${src[t.NUMERICIDENTIFIERLOOSE]})\\\\\\\\.` +\\n `(${src[t.NUMERICIDENTIFIERLOOSE]})\\\\\\\\.` +\\n `(${src[t.NUMERICIDENTIFIERLOOSE]})`)\\n\\n// ## Pre-release Version Identifier\\n// A numeric identifier, or a non-numeric identifier.\\n// Non-numberic identifiers include numberic identifiers but can be longer.\\n// Therefore non-numberic identifiers must go first.\\n\\ncreateToken('PRERELEASEIDENTIFIER', `(?:${src[t.NONNUMERICIDENTIFIER]\\n}|${src[t.NUMERICIDENTIFIER]})`)\\n\\ncreateToken('PRERELEASEIDENTIFIERLOOSE', `(?:${src[t.NONNUMERICIDENTIFIER]\\n}|${src[t.NUMERICIDENTIFIERLOOSE]})`)\\n\\n// ## Pre-release Version\\n// Hyphen, followed by one or more dot-separated pre-release version\\n// identifiers.\\n\\ncreateToken('PRERELEASE', `(?:-(${src[t.PRERELEASEIDENTIFIER]\\n}(?:\\\\\\\\.${src[t.PRERELEASEIDENTIFIER]})*))`)\\n\\ncreateToken('PRERELEASELOOSE', `(?:-?(${src[t.PRERELEASEIDENTIFIERLOOSE]\\n}(?:\\\\\\\\.${src[t.PRERELEASEIDENTIFIERLOOSE]})*))`)\\n\\n// ## Build Metadata Identifier\\n// Any combination of digits, letters, or hyphens.\\n\\ncreateToken('BUILDIDENTIFIER', `${LETTERDASHNUMBER}+`)\\n\\n// ## Build Metadata\\n// Plus sign, followed by one or more period-separated build metadata\\n// identifiers.\\n\\ncreateToken('BUILD', `(?:\\\\\\\\+(${src[t.BUILDIDENTIFIER]\\n}(?:\\\\\\\\.${src[t.BUILDIDENTIFIER]})*))`)\\n\\n// ## Full Version String\\n// A main version, followed optionally by a pre-release version and\\n// build metadata.\\n\\n// Note that the only major, minor, patch, and pre-release sections of\\n// the version string are capturing groups. The build metadata is not a\\n// capturing group, because it should not ever be used in version\\n// comparison.\\n\\ncreateToken('FULLPLAIN', `v?${src[t.MAINVERSION]\\n}${src[t.PRERELEASE]}?${\\n src[t.BUILD]}?`)\\n\\ncreateToken('FULL', `^${src[t.FULLPLAIN]}$`)\\n\\n// like full, but allows v1.2.3 and =1.2.3, which people do sometimes.\\n// also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty\\n// common in the npm registry.\\ncreateToken('LOOSEPLAIN', `[v=\\\\\\\\s]*${src[t.MAINVERSIONLOOSE]\\n}${src[t.PRERELEASELOOSE]}?${\\n src[t.BUILD]}?`)\\n\\ncreateToken('LOOSE', `^${src[t.LOOSEPLAIN]}$`)\\n\\ncreateToken('GTLT', '((?:<|>)?=?)')\\n\\n// Something like \\\"2.*\\\" or \\\"1.2.x\\\".\\n// Note that \\\"x.x\\\" is a valid xRange identifer, meaning \\\"any version\\\"\\n// Only the first item is strictly required.\\ncreateToken('XRANGEIDENTIFIERLOOSE', `${src[t.NUMERICIDENTIFIERLOOSE]}|x|X|\\\\\\\\*`)\\ncreateToken('XRANGEIDENTIFIER', `${src[t.NUMERICIDENTIFIER]}|x|X|\\\\\\\\*`)\\n\\ncreateToken('XRANGEPLAIN', `[v=\\\\\\\\s]*(${src[t.XRANGEIDENTIFIER]})` +\\n `(?:\\\\\\\\.(${src[t.XRANGEIDENTIFIER]})` +\\n `(?:\\\\\\\\.(${src[t.XRANGEIDENTIFIER]})` +\\n `(?:${src[t.PRERELEASE]})?${\\n src[t.BUILD]}?` +\\n `)?)?`)\\n\\ncreateToken('XRANGEPLAINLOOSE', `[v=\\\\\\\\s]*(${src[t.XRANGEIDENTIFIERLOOSE]})` +\\n `(?:\\\\\\\\.(${src[t.XRANGEIDENTIFIERLOOSE]})` +\\n `(?:\\\\\\\\.(${src[t.XRANGEIDENTIFIERLOOSE]})` +\\n `(?:${src[t.PRERELEASELOOSE]})?${\\n src[t.BUILD]}?` +\\n `)?)?`)\\n\\ncreateToken('XRANGE', `^${src[t.GTLT]}\\\\\\\\s*${src[t.XRANGEPLAIN]}$`)\\ncreateToken('XRANGELOOSE', `^${src[t.GTLT]}\\\\\\\\s*${src[t.XRANGEPLAINLOOSE]}$`)\\n\\n// Coercion.\\n// Extract anything that could conceivably be a part of a valid semver\\ncreateToken('COERCEPLAIN', `${'(^|[^\\\\\\\\d])' +\\n '(\\\\\\\\d{1,'}${MAX_SAFE_COMPONENT_LENGTH}})` +\\n `(?:\\\\\\\\.(\\\\\\\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` +\\n `(?:\\\\\\\\.(\\\\\\\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?`)\\ncreateToken('COERCE', `${src[t.COERCEPLAIN]}(?:$|[^\\\\\\\\d])`)\\ncreateToken('COERCEFULL', src[t.COERCEPLAIN] +\\n `(?:${src[t.PRERELEASE]})?` +\\n `(?:${src[t.BUILD]})?` +\\n `(?:$|[^\\\\\\\\d])`)\\ncreateToken('COERCERTL', src[t.COERCE], true)\\ncreateToken('COERCERTLFULL', src[t.COERCEFULL], true)\\n\\n// Tilde ranges.\\n// Meaning is \\\"reasonably at or greater than\\\"\\ncreateToken('LONETILDE', '(?:~>?)')\\n\\ncreateToken('TILDETRIM', `(\\\\\\\\s*)${src[t.LONETILDE]}\\\\\\\\s+`, true)\\nexports.tildeTrimReplace = '$1~'\\n\\ncreateToken('TILDE', `^${src[t.LONETILDE]}${src[t.XRANGEPLAIN]}$`)\\ncreateToken('TILDELOOSE', `^${src[t.LONETILDE]}${src[t.XRANGEPLAINLOOSE]}$`)\\n\\n// Caret ranges.\\n// Meaning is \\\"at least and backwards compatible with\\\"\\ncreateToken('LONECARET', '(?:\\\\\\\\^)')\\n\\ncreateToken('CARETTRIM', `(\\\\\\\\s*)${src[t.LONECARET]}\\\\\\\\s+`, true)\\nexports.caretTrimReplace = '$1^'\\n\\ncreateToken('CARET', `^${src[t.LONECARET]}${src[t.XRANGEPLAIN]}$`)\\ncreateToken('CARETLOOSE', `^${src[t.LONECARET]}${src[t.XRANGEPLAINLOOSE]}$`)\\n\\n// A simple gt/lt/eq thing, or just \\\"\\\" to indicate \\\"any version\\\"\\ncreateToken('COMPARATORLOOSE', `^${src[t.GTLT]}\\\\\\\\s*(${src[t.LOOSEPLAIN]})$|^$`)\\ncreateToken('COMPARATOR', `^${src[t.GTLT]}\\\\\\\\s*(${src[t.FULLPLAIN]})$|^$`)\\n\\n// An expression to strip any whitespace between the gtlt and the thing\\n// it modifies, so that `> 1.2.3` ==> `>1.2.3`\\ncreateToken('COMPARATORTRIM', `(\\\\\\\\s*)${src[t.GTLT]\\n}\\\\\\\\s*(${src[t.LOOSEPLAIN]}|${src[t.XRANGEPLAIN]})`, true)\\nexports.comparatorTrimReplace = '$1$2$3'\\n\\n// Something like `1.2.3 - 1.2.4`\\n// Note that these all use the loose form, because they'll be\\n// checked against either the strict or loose comparator form\\n// later.\\ncreateToken('HYPHENRANGE', `^\\\\\\\\s*(${src[t.XRANGEPLAIN]})` +\\n `\\\\\\\\s+-\\\\\\\\s+` +\\n `(${src[t.XRANGEPLAIN]})` +\\n `\\\\\\\\s*$`)\\n\\ncreateToken('HYPHENRANGELOOSE', `^\\\\\\\\s*(${src[t.XRANGEPLAINLOOSE]})` +\\n `\\\\\\\\s+-\\\\\\\\s+` +\\n `(${src[t.XRANGEPLAINLOOSE]})` +\\n `\\\\\\\\s*$`)\\n\\n// Star ranges basically just allow anything at all.\\ncreateToken('STAR', '(<|>)?=?\\\\\\\\s*\\\\\\\\*')\\n// >=0.0.0 is like a star\\ncreateToken('GTE0', '^\\\\\\\\s*>=\\\\\\\\s*0\\\\\\\\.0\\\\\\\\.0\\\\\\\\s*$')\\ncreateToken('GTE0PRE', '^\\\\\\\\s*>=\\\\\\\\s*0\\\\\\\\.0\\\\\\\\.0-0\\\\\\\\s*$')\\n\",\"'use strict'\\n\\n// parse out just the options we care about\\nconst looseOption = Object.freeze({ loose: true })\\nconst emptyOpts = Object.freeze({ })\\nconst parseOptions = options => {\\n if (!options) {\\n return emptyOpts\\n }\\n\\n if (typeof options !== 'object') {\\n return looseOption\\n }\\n\\n return options\\n}\\nmodule.exports = parseOptions\\n\",\"'use strict'\\n\\nconst numeric = /^[0-9]+$/\\nconst compareIdentifiers = (a, b) => {\\n if (typeof a === 'number' && typeof b === 'number') {\\n return a === b ? 0 : a < b ? -1 : 1\\n }\\n\\n const anum = numeric.test(a)\\n const bnum = numeric.test(b)\\n\\n if (anum && bnum) {\\n a = +a\\n b = +b\\n }\\n\\n return a === b ? 0\\n : (anum && !bnum) ? -1\\n : (bnum && !anum) ? 1\\n : a < b ? -1\\n : 1\\n}\\n\\nconst rcompareIdentifiers = (a, b) => compareIdentifiers(b, a)\\n\\nmodule.exports = {\\n compareIdentifiers,\\n rcompareIdentifiers,\\n}\\n\",\"'use strict'\\n\\nconst debug = require('../internal/debug')\\nconst { MAX_LENGTH, MAX_SAFE_INTEGER } = require('../internal/constants')\\nconst { safeRe: re, t } = require('../internal/re')\\n\\nconst parseOptions = require('../internal/parse-options')\\nconst { compareIdentifiers } = require('../internal/identifiers')\\nclass SemVer {\\n constructor (version, options) {\\n options = parseOptions(options)\\n\\n if (version instanceof SemVer) {\\n if (version.loose === !!options.loose &&\\n version.includePrerelease === !!options.includePrerelease) {\\n return version\\n } else {\\n version = version.version\\n }\\n } else if (typeof version !== 'string') {\\n throw new TypeError(`Invalid version. Must be a string. Got type \\\"${typeof version}\\\".`)\\n }\\n\\n if (version.length > MAX_LENGTH) {\\n throw new TypeError(\\n `version is longer than ${MAX_LENGTH} characters`\\n )\\n }\\n\\n debug('SemVer', version, options)\\n this.options = options\\n this.loose = !!options.loose\\n // this isn't actually relevant for versions, but keep it so that we\\n // don't run into trouble passing this.options around.\\n this.includePrerelease = !!options.includePrerelease\\n\\n const m = version.trim().match(options.loose ? re[t.LOOSE] : re[t.FULL])\\n\\n if (!m) {\\n throw new TypeError(`Invalid Version: ${version}`)\\n }\\n\\n this.raw = version\\n\\n // these are actually numbers\\n this.major = +m[1]\\n this.minor = +m[2]\\n this.patch = +m[3]\\n\\n if (this.major > MAX_SAFE_INTEGER || this.major < 0) {\\n throw new TypeError('Invalid major version')\\n }\\n\\n if (this.minor > MAX_SAFE_INTEGER || this.minor < 0) {\\n throw new TypeError('Invalid minor version')\\n }\\n\\n if (this.patch > MAX_SAFE_INTEGER || this.patch < 0) {\\n throw new TypeError('Invalid patch version')\\n }\\n\\n // numberify any prerelease numeric ids\\n if (!m[4]) {\\n this.prerelease = []\\n } else {\\n this.prerelease = m[4].split('.').map((id) => {\\n if (/^[0-9]+$/.test(id)) {\\n const num = +id\\n if (num >= 0 && num < MAX_SAFE_INTEGER) {\\n return num\\n }\\n }\\n return id\\n })\\n }\\n\\n this.build = m[5] ? m[5].split('.') : []\\n this.format()\\n }\\n\\n format () {\\n this.version = `${this.major}.${this.minor}.${this.patch}`\\n if (this.prerelease.length) {\\n this.version += `-${this.prerelease.join('.')}`\\n }\\n return this.version\\n }\\n\\n toString () {\\n return this.version\\n }\\n\\n compare (other) {\\n debug('SemVer.compare', this.version, this.options, other)\\n if (!(other instanceof SemVer)) {\\n if (typeof other === 'string' && other === this.version) {\\n return 0\\n }\\n other = new SemVer(other, this.options)\\n }\\n\\n if (other.version === this.version) {\\n return 0\\n }\\n\\n return this.compareMain(other) || this.comparePre(other)\\n }\\n\\n compareMain (other) {\\n if (!(other instanceof SemVer)) {\\n other = new SemVer(other, this.options)\\n }\\n\\n if (this.major < other.major) {\\n return -1\\n }\\n if (this.major > other.major) {\\n return 1\\n }\\n if (this.minor < other.minor) {\\n return -1\\n }\\n if (this.minor > other.minor) {\\n return 1\\n }\\n if (this.patch < other.patch) {\\n return -1\\n }\\n if (this.patch > other.patch) {\\n return 1\\n }\\n return 0\\n }\\n\\n comparePre (other) {\\n if (!(other instanceof SemVer)) {\\n other = new SemVer(other, this.options)\\n }\\n\\n // NOT having a prerelease is > having one\\n if (this.prerelease.length && !other.prerelease.length) {\\n return -1\\n } else if (!this.prerelease.length && other.prerelease.length) {\\n return 1\\n } else if (!this.prerelease.length && !other.prerelease.length) {\\n return 0\\n }\\n\\n let i = 0\\n do {\\n const a = this.prerelease[i]\\n const b = other.prerelease[i]\\n debug('prerelease compare', i, a, b)\\n if (a === undefined && b === undefined) {\\n return 0\\n } else if (b === undefined) {\\n return 1\\n } else if (a === undefined) {\\n return -1\\n } else if (a === b) {\\n continue\\n } else {\\n return compareIdentifiers(a, b)\\n }\\n } while (++i)\\n }\\n\\n compareBuild (other) {\\n if (!(other instanceof SemVer)) {\\n other = new SemVer(other, this.options)\\n }\\n\\n let i = 0\\n do {\\n const a = this.build[i]\\n const b = other.build[i]\\n debug('build compare', i, a, b)\\n if (a === undefined && b === undefined) {\\n return 0\\n } else if (b === undefined) {\\n return 1\\n } else if (a === undefined) {\\n return -1\\n } else if (a === b) {\\n continue\\n } else {\\n return compareIdentifiers(a, b)\\n }\\n } while (++i)\\n }\\n\\n // preminor will bump the version up to the next minor release, and immediately\\n // down to pre-release. premajor and prepatch work the same way.\\n inc (release, identifier, identifierBase) {\\n if (release.startsWith('pre')) {\\n if (!identifier && identifierBase === false) {\\n throw new Error('invalid increment argument: identifier is empty')\\n }\\n // Avoid an invalid semver results\\n if (identifier) {\\n const match = `-${identifier}`.match(this.options.loose ? re[t.PRERELEASELOOSE] : re[t.PRERELEASE])\\n if (!match || match[1] !== identifier) {\\n throw new Error(`invalid identifier: ${identifier}`)\\n }\\n }\\n }\\n\\n switch (release) {\\n case 'premajor':\\n this.prerelease.length = 0\\n this.patch = 0\\n this.minor = 0\\n this.major++\\n this.inc('pre', identifier, identifierBase)\\n break\\n case 'preminor':\\n this.prerelease.length = 0\\n this.patch = 0\\n this.minor++\\n this.inc('pre', identifier, identifierBase)\\n break\\n case 'prepatch':\\n // If this is already a prerelease, it will bump to the next version\\n // drop any prereleases that might already exist, since they are not\\n // relevant at this point.\\n this.prerelease.length = 0\\n this.inc('patch', identifier, identifierBase)\\n this.inc('pre', identifier, identifierBase)\\n break\\n // If the input is a non-prerelease version, this acts the same as\\n // prepatch.\\n case 'prerelease':\\n if (this.prerelease.length === 0) {\\n this.inc('patch', identifier, identifierBase)\\n }\\n this.inc('pre', identifier, identifierBase)\\n break\\n case 'release':\\n if (this.prerelease.length === 0) {\\n throw new Error(`version ${this.raw} is not a prerelease`)\\n }\\n this.prerelease.length = 0\\n break\\n\\n case 'major':\\n // If this is a pre-major version, bump up to the same major version.\\n // Otherwise increment major.\\n // 1.0.0-5 bumps to 1.0.0\\n // 1.1.0 bumps to 2.0.0\\n if (\\n this.minor !== 0 ||\\n this.patch !== 0 ||\\n this.prerelease.length === 0\\n ) {\\n this.major++\\n }\\n this.minor = 0\\n this.patch = 0\\n this.prerelease = []\\n break\\n case 'minor':\\n // If this is a pre-minor version, bump up to the same minor version.\\n // Otherwise increment minor.\\n // 1.2.0-5 bumps to 1.2.0\\n // 1.2.1 bumps to 1.3.0\\n if (this.patch !== 0 || this.prerelease.length === 0) {\\n this.minor++\\n }\\n this.patch = 0\\n this.prerelease = []\\n break\\n case 'patch':\\n // If this is not a pre-release version, it will increment the patch.\\n // If it is a pre-release it will bump up to the same patch version.\\n // 1.2.0-5 patches to 1.2.0\\n // 1.2.0 patches to 1.2.1\\n if (this.prerelease.length === 0) {\\n this.patch++\\n }\\n this.prerelease = []\\n break\\n // This probably shouldn't be used publicly.\\n // 1.0.0 'pre' would become 1.0.0-0 which is the wrong direction.\\n case 'pre': {\\n const base = Number(identifierBase) ? 1 : 0\\n\\n if (this.prerelease.length === 0) {\\n this.prerelease = [base]\\n } else {\\n let i = this.prerelease.length\\n while (--i >= 0) {\\n if (typeof this.prerelease[i] === 'number') {\\n this.prerelease[i]++\\n i = -2\\n }\\n }\\n if (i === -1) {\\n // didn't increment anything\\n if (identifier === this.prerelease.join('.') && identifierBase === false) {\\n throw new Error('invalid increment argument: identifier already exists')\\n }\\n this.prerelease.push(base)\\n }\\n }\\n if (identifier) {\\n // 1.2.0-beta.1 bumps to 1.2.0-beta.2,\\n // 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0\\n let prerelease = [identifier, base]\\n if (identifierBase === false) {\\n prerelease = [identifier]\\n }\\n if (compareIdentifiers(this.prerelease[0], identifier) === 0) {\\n if (isNaN(this.prerelease[1])) {\\n this.prerelease = prerelease\\n }\\n } else {\\n this.prerelease = prerelease\\n }\\n }\\n break\\n }\\n default:\\n throw new Error(`invalid increment argument: ${release}`)\\n }\\n this.raw = this.format()\\n if (this.build.length) {\\n this.raw += `+${this.build.join('.')}`\\n }\\n return this\\n }\\n}\\n\\nmodule.exports = SemVer\\n\",\"'use strict'\\n\\nconst SemVer = require('../classes/semver')\\nconst parse = (version, options, throwErrors = false) => {\\n if (version instanceof SemVer) {\\n return version\\n }\\n try {\\n return new SemVer(version, options)\\n } catch (er) {\\n if (!throwErrors) {\\n return null\\n }\\n throw er\\n }\\n}\\n\\nmodule.exports = parse\\n\",\"'use strict'\\n\\nconst parse = require('./parse')\\nconst valid = (version, options) => {\\n const v = parse(version, options)\\n return v ? v.version : null\\n}\\nmodule.exports = valid\\n\",\"'use strict'\\n\\nconst parse = require('./parse')\\nconst clean = (version, options) => {\\n const s = parse(version.trim().replace(/^[=v]+/, ''), options)\\n return s ? s.version : null\\n}\\nmodule.exports = clean\\n\",\"'use strict'\\n\\nconst SemVer = require('../classes/semver')\\n\\nconst inc = (version, release, options, identifier, identifierBase) => {\\n if (typeof (options) === 'string') {\\n identifierBase = identifier\\n identifier = options\\n options = undefined\\n }\\n\\n try {\\n return new SemVer(\\n version instanceof SemVer ? version.version : version,\\n options\\n ).inc(release, identifier, identifierBase).version\\n } catch (er) {\\n return null\\n }\\n}\\nmodule.exports = inc\\n\",\"'use strict'\\n\\nconst parse = require('./parse.js')\\n\\nconst diff = (version1, version2) => {\\n const v1 = parse(version1, null, true)\\n const v2 = parse(version2, null, true)\\n const comparison = v1.compare(v2)\\n\\n if (comparison === 0) {\\n return null\\n }\\n\\n const v1Higher = comparison > 0\\n const highVersion = v1Higher ? v1 : v2\\n const lowVersion = v1Higher ? v2 : v1\\n const highHasPre = !!highVersion.prerelease.length\\n const lowHasPre = !!lowVersion.prerelease.length\\n\\n if (lowHasPre && !highHasPre) {\\n // Going from prerelease -> no prerelease requires some special casing\\n\\n // If the low version has only a major, then it will always be a major\\n // Some examples:\\n // 1.0.0-1 -> 1.0.0\\n // 1.0.0-1 -> 1.1.1\\n // 1.0.0-1 -> 2.0.0\\n if (!lowVersion.patch && !lowVersion.minor) {\\n return 'major'\\n }\\n\\n // If the main part has no difference\\n if (lowVersion.compareMain(highVersion) === 0) {\\n if (lowVersion.minor && !lowVersion.patch) {\\n return 'minor'\\n }\\n return 'patch'\\n }\\n }\\n\\n // add the `pre` prefix if we are going to a prerelease version\\n const prefix = highHasPre ? 'pre' : ''\\n\\n if (v1.major !== v2.major) {\\n return prefix + 'major'\\n }\\n\\n if (v1.minor !== v2.minor) {\\n return prefix + 'minor'\\n }\\n\\n if (v1.patch !== v2.patch) {\\n return prefix + 'patch'\\n }\\n\\n // high and low are preleases\\n return 'prerelease'\\n}\\n\\nmodule.exports = diff\\n\",\"'use strict'\\n\\nconst SemVer = require('../classes/semver')\\nconst major = (a, loose) => new SemVer(a, loose).major\\nmodule.exports = major\\n\",\"'use strict'\\n\\nconst SemVer = require('../classes/semver')\\nconst minor = (a, loose) => new SemVer(a, loose).minor\\nmodule.exports = minor\\n\",\"'use strict'\\n\\nconst SemVer = require('../classes/semver')\\nconst patch = (a, loose) => new SemVer(a, loose).patch\\nmodule.exports = patch\\n\",\"'use strict'\\n\\nconst parse = require('./parse')\\nconst prerelease = (version, options) => {\\n const parsed = parse(version, options)\\n return (parsed && parsed.prerelease.length) ? parsed.prerelease : null\\n}\\nmodule.exports = prerelease\\n\",\"'use strict'\\n\\nconst SemVer = require('../classes/semver')\\nconst compare = (a, b, loose) =>\\n new SemVer(a, loose).compare(new SemVer(b, loose))\\n\\nmodule.exports = compare\\n\",\"'use strict'\\n\\nconst compare = require('./compare')\\nconst rcompare = (a, b, loose) => compare(b, a, loose)\\nmodule.exports = rcompare\\n\",\"'use strict'\\n\\nconst compare = require('./compare')\\nconst compareLoose = (a, b) => compare(a, b, true)\\nmodule.exports = compareLoose\\n\",\"'use strict'\\n\\nconst SemVer = require('../classes/semver')\\nconst compareBuild = (a, b, loose) => {\\n const versionA = new SemVer(a, loose)\\n const versionB = new SemVer(b, loose)\\n return versionA.compare(versionB) || versionA.compareBuild(versionB)\\n}\\nmodule.exports = compareBuild\\n\",\"'use strict'\\n\\nconst compareBuild = require('./compare-build')\\nconst sort = (list, loose) => list.sort((a, b) => compareBuild(a, b, loose))\\nmodule.exports = sort\\n\",\"'use strict'\\n\\nconst compareBuild = require('./compare-build')\\nconst rsort = (list, loose) => list.sort((a, b) => compareBuild(b, a, loose))\\nmodule.exports = rsort\\n\",\"'use strict'\\n\\nconst compare = require('./compare')\\nconst gt = (a, b, loose) => compare(a, b, loose) > 0\\nmodule.exports = gt\\n\",\"'use strict'\\n\\nconst compare = require('./compare')\\nconst lt = (a, b, loose) => compare(a, b, loose) < 0\\nmodule.exports = lt\\n\",\"'use strict'\\n\\nconst compare = require('./compare')\\nconst eq = (a, b, loose) => compare(a, b, loose) === 0\\nmodule.exports = eq\\n\",\"'use strict'\\n\\nconst compare = require('./compare')\\nconst neq = (a, b, loose) => compare(a, b, loose) !== 0\\nmodule.exports = neq\\n\",\"'use strict'\\n\\nconst compare = require('./compare')\\nconst gte = (a, b, loose) => compare(a, b, loose) >= 0\\nmodule.exports = gte\\n\",\"'use strict'\\n\\nconst compare = require('./compare')\\nconst lte = (a, b, loose) => compare(a, b, loose) <= 0\\nmodule.exports = lte\\n\",\"'use strict'\\n\\nconst eq = require('./eq')\\nconst neq = require('./neq')\\nconst gt = require('./gt')\\nconst gte = require('./gte')\\nconst lt = require('./lt')\\nconst lte = require('./lte')\\n\\nconst cmp = (a, op, b, loose) => {\\n switch (op) {\\n case '===':\\n if (typeof a === 'object') {\\n a = a.version\\n }\\n if (typeof b === 'object') {\\n b = b.version\\n }\\n return a === b\\n\\n case '!==':\\n if (typeof a === 'object') {\\n a = a.version\\n }\\n if (typeof b === 'object') {\\n b = b.version\\n }\\n return a !== b\\n\\n case '':\\n case '=':\\n case '==':\\n return eq(a, b, loose)\\n\\n case '!=':\\n return neq(a, b, loose)\\n\\n case '>':\\n return gt(a, b, loose)\\n\\n case '>=':\\n return gte(a, b, loose)\\n\\n case '<':\\n return lt(a, b, loose)\\n\\n case '<=':\\n return lte(a, b, loose)\\n\\n default:\\n throw new TypeError(`Invalid operator: ${op}`)\\n }\\n}\\nmodule.exports = cmp\\n\",\"'use strict'\\n\\nconst SemVer = require('../classes/semver')\\nconst parse = require('./parse')\\nconst { safeRe: re, t } = require('../internal/re')\\n\\nconst coerce = (version, options) => {\\n if (version instanceof SemVer) {\\n return version\\n }\\n\\n if (typeof version === 'number') {\\n version = String(version)\\n }\\n\\n if (typeof version !== 'string') {\\n return null\\n }\\n\\n options = options || {}\\n\\n let match = null\\n if (!options.rtl) {\\n match = version.match(options.includePrerelease ? re[t.COERCEFULL] : re[t.COERCE])\\n } else {\\n // Find the right-most coercible string that does not share\\n // a terminus with a more left-ward coercible string.\\n // Eg, '1.2.3.4' wants to coerce '2.3.4', not '3.4' or '4'\\n // With includePrerelease option set, '1.2.3.4-rc' wants to coerce '2.3.4-rc', not '2.3.4'\\n //\\n // Walk through the string checking with a /g regexp\\n // Manually set the index so as to pick up overlapping matches.\\n // Stop when we get a match that ends at the string end, since no\\n // coercible string can be more right-ward without the same terminus.\\n const coerceRtlRegex = options.includePrerelease ? re[t.COERCERTLFULL] : re[t.COERCERTL]\\n let next\\n while ((next = coerceRtlRegex.exec(version)) &&\\n (!match || match.index + match[0].length !== version.length)\\n ) {\\n if (!match ||\\n next.index + next[0].length !== match.index + match[0].length) {\\n match = next\\n }\\n coerceRtlRegex.lastIndex = next.index + next[1].length + next[2].length\\n }\\n // leave it in a clean state\\n coerceRtlRegex.lastIndex = -1\\n }\\n\\n if (match === null) {\\n return null\\n }\\n\\n const major = match[2]\\n const minor = match[3] || '0'\\n const patch = match[4] || '0'\\n const prerelease = options.includePrerelease && match[5] ? `-${match[5]}` : ''\\n const build = options.includePrerelease && match[6] ? `+${match[6]}` : ''\\n\\n return parse(`${major}.${minor}.${patch}${prerelease}${build}`, options)\\n}\\nmodule.exports = coerce\\n\",\"'use strict'\\n\\nclass LRUCache {\\n constructor () {\\n this.max = 1000\\n this.map = new Map()\\n }\\n\\n get (key) {\\n const value = this.map.get(key)\\n if (value === undefined) {\\n return undefined\\n } else {\\n // Remove the key from the map and add it to the end\\n this.map.delete(key)\\n this.map.set(key, value)\\n return value\\n }\\n }\\n\\n delete (key) {\\n return this.map.delete(key)\\n }\\n\\n set (key, value) {\\n const deleted = this.delete(key)\\n\\n if (!deleted && value !== undefined) {\\n // If cache is full, delete the least recently used item\\n if (this.map.size >= this.max) {\\n const firstKey = this.map.keys().next().value\\n this.delete(firstKey)\\n }\\n\\n this.map.set(key, value)\\n }\\n\\n return this\\n }\\n}\\n\\nmodule.exports = LRUCache\\n\",\"'use strict'\\n\\nconst SPACE_CHARACTERS = /\\\\s+/g\\n\\n// hoisted class for cyclic dependency\\nclass Range {\\n constructor (range, options) {\\n options = parseOptions(options)\\n\\n if (range instanceof Range) {\\n if (\\n range.loose === !!options.loose &&\\n range.includePrerelease === !!options.includePrerelease\\n ) {\\n return range\\n } else {\\n return new Range(range.raw, options)\\n }\\n }\\n\\n if (range instanceof Comparator) {\\n // just put it in the set and return\\n this.raw = range.value\\n this.set = [[range]]\\n this.formatted = undefined\\n return this\\n }\\n\\n this.options = options\\n this.loose = !!options.loose\\n this.includePrerelease = !!options.includePrerelease\\n\\n // First reduce all whitespace as much as possible so we do not have to rely\\n // on potentially slow regexes like \\\\s*. This is then stored and used for\\n // future error messages as well.\\n this.raw = range.trim().replace(SPACE_CHARACTERS, ' ')\\n\\n // First, split on ||\\n this.set = this.raw\\n .split('||')\\n // map the range to a 2d array of comparators\\n .map(r => this.parseRange(r.trim()))\\n // throw out any comparator lists that are empty\\n // this generally means that it was not a valid range, which is allowed\\n // in loose mode, but will still throw if the WHOLE range is invalid.\\n .filter(c => c.length)\\n\\n if (!this.set.length) {\\n throw new TypeError(`Invalid SemVer Range: ${this.raw}`)\\n }\\n\\n // if we have any that are not the null set, throw out null sets.\\n if (this.set.length > 1) {\\n // keep the first one, in case they're all null sets\\n const first = this.set[0]\\n this.set = this.set.filter(c => !isNullSet(c[0]))\\n if (this.set.length === 0) {\\n this.set = [first]\\n } else if (this.set.length > 1) {\\n // if we have any that are *, then the range is just *\\n for (const c of this.set) {\\n if (c.length === 1 && isAny(c[0])) {\\n this.set = [c]\\n break\\n }\\n }\\n }\\n }\\n\\n this.formatted = undefined\\n }\\n\\n get range () {\\n if (this.formatted === undefined) {\\n this.formatted = ''\\n for (let i = 0; i < this.set.length; i++) {\\n if (i > 0) {\\n this.formatted += '||'\\n }\\n const comps = this.set[i]\\n for (let k = 0; k < comps.length; k++) {\\n if (k > 0) {\\n this.formatted += ' '\\n }\\n this.formatted += comps[k].toString().trim()\\n }\\n }\\n }\\n return this.formatted\\n }\\n\\n format () {\\n return this.range\\n }\\n\\n toString () {\\n return this.range\\n }\\n\\n parseRange (range) {\\n // memoize range parsing for performance.\\n // this is a very hot path, and fully deterministic.\\n const memoOpts =\\n (this.options.includePrerelease && FLAG_INCLUDE_PRERELEASE) |\\n (this.options.loose && FLAG_LOOSE)\\n const memoKey = memoOpts + ':' + range\\n const cached = cache.get(memoKey)\\n if (cached) {\\n return cached\\n }\\n\\n const loose = this.options.loose\\n // `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4`\\n const hr = loose ? re[t.HYPHENRANGELOOSE] : re[t.HYPHENRANGE]\\n range = range.replace(hr, hyphenReplace(this.options.includePrerelease))\\n debug('hyphen replace', range)\\n\\n // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5`\\n range = range.replace(re[t.COMPARATORTRIM], comparatorTrimReplace)\\n debug('comparator trim', range)\\n\\n // `~ 1.2.3` => `~1.2.3`\\n range = range.replace(re[t.TILDETRIM], tildeTrimReplace)\\n debug('tilde trim', range)\\n\\n // `^ 1.2.3` => `^1.2.3`\\n range = range.replace(re[t.CARETTRIM], caretTrimReplace)\\n debug('caret trim', range)\\n\\n // At this point, the range is completely trimmed and\\n // ready to be split into comparators.\\n\\n let rangeList = range\\n .split(' ')\\n .map(comp => parseComparator(comp, this.options))\\n .join(' ')\\n .split(/\\\\s+/)\\n // >=0.0.0 is equivalent to *\\n .map(comp => replaceGTE0(comp, this.options))\\n\\n if (loose) {\\n // in loose mode, throw out any that are not valid comparators\\n rangeList = rangeList.filter(comp => {\\n debug('loose invalid filter', comp, this.options)\\n return !!comp.match(re[t.COMPARATORLOOSE])\\n })\\n }\\n debug('range list', rangeList)\\n\\n // if any comparators are the null set, then replace with JUST null set\\n // if more than one comparator, remove any * comparators\\n // also, don't include the same comparator more than once\\n const rangeMap = new Map()\\n const comparators = rangeList.map(comp => new Comparator(comp, this.options))\\n for (const comp of comparators) {\\n if (isNullSet(comp)) {\\n return [comp]\\n }\\n rangeMap.set(comp.value, comp)\\n }\\n if (rangeMap.size > 1 && rangeMap.has('')) {\\n rangeMap.delete('')\\n }\\n\\n const result = [...rangeMap.values()]\\n cache.set(memoKey, result)\\n return result\\n }\\n\\n intersects (range, options) {\\n if (!(range instanceof Range)) {\\n throw new TypeError('a Range is required')\\n }\\n\\n return this.set.some((thisComparators) => {\\n return (\\n isSatisfiable(thisComparators, options) &&\\n range.set.some((rangeComparators) => {\\n return (\\n isSatisfiable(rangeComparators, options) &&\\n thisComparators.every((thisComparator) => {\\n return rangeComparators.every((rangeComparator) => {\\n return thisComparator.intersects(rangeComparator, options)\\n })\\n })\\n )\\n })\\n )\\n })\\n }\\n\\n // if ANY of the sets match ALL of its comparators, then pass\\n test (version) {\\n if (!version) {\\n return false\\n }\\n\\n if (typeof version === 'string') {\\n try {\\n version = new SemVer(version, this.options)\\n } catch (er) {\\n return false\\n }\\n }\\n\\n for (let i = 0; i < this.set.length; i++) {\\n if (testSet(this.set[i], version, this.options)) {\\n return true\\n }\\n }\\n return false\\n }\\n}\\n\\nmodule.exports = Range\\n\\nconst LRU = require('../internal/lrucache')\\nconst cache = new LRU()\\n\\nconst parseOptions = require('../internal/parse-options')\\nconst Comparator = require('./comparator')\\nconst debug = require('../internal/debug')\\nconst SemVer = require('./semver')\\nconst {\\n safeRe: re,\\n t,\\n comparatorTrimReplace,\\n tildeTrimReplace,\\n caretTrimReplace,\\n} = require('../internal/re')\\nconst { FLAG_INCLUDE_PRERELEASE, FLAG_LOOSE } = require('../internal/constants')\\n\\nconst isNullSet = c => c.value === '<0.0.0-0'\\nconst isAny = c => c.value === ''\\n\\n// take a set of comparators and determine whether there\\n// exists a version which can satisfy it\\nconst isSatisfiable = (comparators, options) => {\\n let result = true\\n const remainingComparators = comparators.slice()\\n let testComparator = remainingComparators.pop()\\n\\n while (result && remainingComparators.length) {\\n result = remainingComparators.every((otherComparator) => {\\n return testComparator.intersects(otherComparator, options)\\n })\\n\\n testComparator = remainingComparators.pop()\\n }\\n\\n return result\\n}\\n\\n// comprised of xranges, tildes, stars, and gtlt's at this point.\\n// already replaced the hyphen ranges\\n// turn into a set of JUST comparators.\\nconst parseComparator = (comp, options) => {\\n comp = comp.replace(re[t.BUILD], '')\\n debug('comp', comp, options)\\n comp = replaceCarets(comp, options)\\n debug('caret', comp)\\n comp = replaceTildes(comp, options)\\n debug('tildes', comp)\\n comp = replaceXRanges(comp, options)\\n debug('xrange', comp)\\n comp = replaceStars(comp, options)\\n debug('stars', comp)\\n return comp\\n}\\n\\nconst isX = id => !id || id.toLowerCase() === 'x' || id === '*'\\n\\n// ~, ~> --> * (any, kinda silly)\\n// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0-0\\n// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0-0\\n// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0-0\\n// ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0-0\\n// ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0-0\\n// ~0.0.1 --> >=0.0.1 <0.1.0-0\\nconst replaceTildes = (comp, options) => {\\n return comp\\n .trim()\\n .split(/\\\\s+/)\\n .map((c) => replaceTilde(c, options))\\n .join(' ')\\n}\\n\\nconst replaceTilde = (comp, options) => {\\n const r = options.loose ? re[t.TILDELOOSE] : re[t.TILDE]\\n return comp.replace(r, (_, M, m, p, pr) => {\\n debug('tilde', comp, _, M, m, p, pr)\\n let ret\\n\\n if (isX(M)) {\\n ret = ''\\n } else if (isX(m)) {\\n ret = `>=${M}.0.0 <${+M + 1}.0.0-0`\\n } else if (isX(p)) {\\n // ~1.2 == >=1.2.0 <1.3.0-0\\n ret = `>=${M}.${m}.0 <${M}.${+m + 1}.0-0`\\n } else if (pr) {\\n debug('replaceTilde pr', pr)\\n ret = `>=${M}.${m}.${p}-${pr\\n } <${M}.${+m + 1}.0-0`\\n } else {\\n // ~1.2.3 == >=1.2.3 <1.3.0-0\\n ret = `>=${M}.${m}.${p\\n } <${M}.${+m + 1}.0-0`\\n }\\n\\n debug('tilde return', ret)\\n return ret\\n })\\n}\\n\\n// ^ --> * (any, kinda silly)\\n// ^2, ^2.x, ^2.x.x --> >=2.0.0 <3.0.0-0\\n// ^2.0, ^2.0.x --> >=2.0.0 <3.0.0-0\\n// ^1.2, ^1.2.x --> >=1.2.0 <2.0.0-0\\n// ^1.2.3 --> >=1.2.3 <2.0.0-0\\n// ^1.2.0 --> >=1.2.0 <2.0.0-0\\n// ^0.0.1 --> >=0.0.1 <0.0.2-0\\n// ^0.1.0 --> >=0.1.0 <0.2.0-0\\nconst replaceCarets = (comp, options) => {\\n return comp\\n .trim()\\n .split(/\\\\s+/)\\n .map((c) => replaceCaret(c, options))\\n .join(' ')\\n}\\n\\nconst replaceCaret = (comp, options) => {\\n debug('caret', comp, options)\\n const r = options.loose ? re[t.CARETLOOSE] : re[t.CARET]\\n const z = options.includePrerelease ? '-0' : ''\\n return comp.replace(r, (_, M, m, p, pr) => {\\n debug('caret', comp, _, M, m, p, pr)\\n let ret\\n\\n if (isX(M)) {\\n ret = ''\\n } else if (isX(m)) {\\n ret = `>=${M}.0.0${z} <${+M + 1}.0.0-0`\\n } else if (isX(p)) {\\n if (M === '0') {\\n ret = `>=${M}.${m}.0${z} <${M}.${+m + 1}.0-0`\\n } else {\\n ret = `>=${M}.${m}.0${z} <${+M + 1}.0.0-0`\\n }\\n } else if (pr) {\\n debug('replaceCaret pr', pr)\\n if (M === '0') {\\n if (m === '0') {\\n ret = `>=${M}.${m}.${p}-${pr\\n } <${M}.${m}.${+p + 1}-0`\\n } else {\\n ret = `>=${M}.${m}.${p}-${pr\\n } <${M}.${+m + 1}.0-0`\\n }\\n } else {\\n ret = `>=${M}.${m}.${p}-${pr\\n } <${+M + 1}.0.0-0`\\n }\\n } else {\\n debug('no pr')\\n if (M === '0') {\\n if (m === '0') {\\n ret = `>=${M}.${m}.${p\\n }${z} <${M}.${m}.${+p + 1}-0`\\n } else {\\n ret = `>=${M}.${m}.${p\\n }${z} <${M}.${+m + 1}.0-0`\\n }\\n } else {\\n ret = `>=${M}.${m}.${p\\n } <${+M + 1}.0.0-0`\\n }\\n }\\n\\n debug('caret return', ret)\\n return ret\\n })\\n}\\n\\nconst replaceXRanges = (comp, options) => {\\n debug('replaceXRanges', comp, options)\\n return comp\\n .split(/\\\\s+/)\\n .map((c) => replaceXRange(c, options))\\n .join(' ')\\n}\\n\\nconst replaceXRange = (comp, options) => {\\n comp = comp.trim()\\n const r = options.loose ? re[t.XRANGELOOSE] : re[t.XRANGE]\\n return comp.replace(r, (ret, gtlt, M, m, p, pr) => {\\n debug('xRange', comp, ret, gtlt, M, m, p, pr)\\n const xM = isX(M)\\n const xm = xM || isX(m)\\n const xp = xm || isX(p)\\n const anyX = xp\\n\\n if (gtlt === '=' && anyX) {\\n gtlt = ''\\n }\\n\\n // if we're including prereleases in the match, then we need\\n // to fix this to -0, the lowest possible prerelease value\\n pr = options.includePrerelease ? '-0' : ''\\n\\n if (xM) {\\n if (gtlt === '>' || gtlt === '<') {\\n // nothing is allowed\\n ret = '<0.0.0-0'\\n } else {\\n // nothing is forbidden\\n ret = '*'\\n }\\n } else if (gtlt && anyX) {\\n // we know patch is an x, because we have any x at all.\\n // replace X with 0\\n if (xm) {\\n m = 0\\n }\\n p = 0\\n\\n if (gtlt === '>') {\\n // >1 => >=2.0.0\\n // >1.2 => >=1.3.0\\n gtlt = '>='\\n if (xm) {\\n M = +M + 1\\n m = 0\\n p = 0\\n } else {\\n m = +m + 1\\n p = 0\\n }\\n } else if (gtlt === '<=') {\\n // <=0.7.x is actually <0.8.0, since any 0.7.x should\\n // pass. Similarly, <=7.x is actually <8.0.0, etc.\\n gtlt = '<'\\n if (xm) {\\n M = +M + 1\\n } else {\\n m = +m + 1\\n }\\n }\\n\\n if (gtlt === '<') {\\n pr = '-0'\\n }\\n\\n ret = `${gtlt + M}.${m}.${p}${pr}`\\n } else if (xm) {\\n ret = `>=${M}.0.0${pr} <${+M + 1}.0.0-0`\\n } else if (xp) {\\n ret = `>=${M}.${m}.0${pr\\n } <${M}.${+m + 1}.0-0`\\n }\\n\\n debug('xRange return', ret)\\n\\n return ret\\n })\\n}\\n\\n// Because * is AND-ed with everything else in the comparator,\\n// and '' means \\\"any version\\\", just remove the *s entirely.\\nconst replaceStars = (comp, options) => {\\n debug('replaceStars', comp, options)\\n // Looseness is ignored here. star is always as loose as it gets!\\n return comp\\n .trim()\\n .replace(re[t.STAR], '')\\n}\\n\\nconst replaceGTE0 = (comp, options) => {\\n debug('replaceGTE0', comp, options)\\n return comp\\n .trim()\\n .replace(re[options.includePrerelease ? t.GTE0PRE : t.GTE0], '')\\n}\\n\\n// This function is passed to string.replace(re[t.HYPHENRANGE])\\n// M, m, patch, prerelease, build\\n// 1.2 - 3.4.5 => >=1.2.0 <=3.4.5\\n// 1.2.3 - 3.4 => >=1.2.0 <3.5.0-0 Any 3.4.x will do\\n// 1.2 - 3.4 => >=1.2.0 <3.5.0-0\\n// TODO build?\\nconst hyphenReplace = incPr => ($0,\\n from, fM, fm, fp, fpr, fb,\\n to, tM, tm, tp, tpr) => {\\n if (isX(fM)) {\\n from = ''\\n } else if (isX(fm)) {\\n from = `>=${fM}.0.0${incPr ? '-0' : ''}`\\n } else if (isX(fp)) {\\n from = `>=${fM}.${fm}.0${incPr ? '-0' : ''}`\\n } else if (fpr) {\\n from = `>=${from}`\\n } else {\\n from = `>=${from}${incPr ? '-0' : ''}`\\n }\\n\\n if (isX(tM)) {\\n to = ''\\n } else if (isX(tm)) {\\n to = `<${+tM + 1}.0.0-0`\\n } else if (isX(tp)) {\\n to = `<${tM}.${+tm + 1}.0-0`\\n } else if (tpr) {\\n to = `<=${tM}.${tm}.${tp}-${tpr}`\\n } else if (incPr) {\\n to = `<${tM}.${tm}.${+tp + 1}-0`\\n } else {\\n to = `<=${to}`\\n }\\n\\n return `${from} ${to}`.trim()\\n}\\n\\nconst testSet = (set, version, options) => {\\n for (let i = 0; i < set.length; i++) {\\n if (!set[i].test(version)) {\\n return false\\n }\\n }\\n\\n if (version.prerelease.length && !options.includePrerelease) {\\n // Find the set of versions that are allowed to have prereleases\\n // For example, ^1.2.3-pr.1 desugars to >=1.2.3-pr.1 <2.0.0\\n // That should allow `1.2.3-pr.2` to pass.\\n // However, `1.2.4-alpha.notready` should NOT be allowed,\\n // even though it's within the range set by the comparators.\\n for (let i = 0; i < set.length; i++) {\\n debug(set[i].semver)\\n if (set[i].semver === Comparator.ANY) {\\n continue\\n }\\n\\n if (set[i].semver.prerelease.length > 0) {\\n const allowed = set[i].semver\\n if (allowed.major === version.major &&\\n allowed.minor === version.minor &&\\n allowed.patch === version.patch) {\\n return true\\n }\\n }\\n }\\n\\n // Version has a -pre, but it's not one of the ones we like.\\n return false\\n }\\n\\n return true\\n}\\n\",\"'use strict'\\n\\nconst ANY = Symbol('SemVer ANY')\\n// hoisted class for cyclic dependency\\nclass Comparator {\\n static get ANY () {\\n return ANY\\n }\\n\\n constructor (comp, options) {\\n options = parseOptions(options)\\n\\n if (comp instanceof Comparator) {\\n if (comp.loose === !!options.loose) {\\n return comp\\n } else {\\n comp = comp.value\\n }\\n }\\n\\n comp = comp.trim().split(/\\\\s+/).join(' ')\\n debug('comparator', comp, options)\\n this.options = options\\n this.loose = !!options.loose\\n this.parse(comp)\\n\\n if (this.semver === ANY) {\\n this.value = ''\\n } else {\\n this.value = this.operator + this.semver.version\\n }\\n\\n debug('comp', this)\\n }\\n\\n parse (comp) {\\n const r = this.options.loose ? re[t.COMPARATORLOOSE] : re[t.COMPARATOR]\\n const m = comp.match(r)\\n\\n if (!m) {\\n throw new TypeError(`Invalid comparator: ${comp}`)\\n }\\n\\n this.operator = m[1] !== undefined ? m[1] : ''\\n if (this.operator === '=') {\\n this.operator = ''\\n }\\n\\n // if it literally is just '>' or '' then allow anything.\\n if (!m[2]) {\\n this.semver = ANY\\n } else {\\n this.semver = new SemVer(m[2], this.options.loose)\\n }\\n }\\n\\n toString () {\\n return this.value\\n }\\n\\n test (version) {\\n debug('Comparator.test', version, this.options.loose)\\n\\n if (this.semver === ANY || version === ANY) {\\n return true\\n }\\n\\n if (typeof version === 'string') {\\n try {\\n version = new SemVer(version, this.options)\\n } catch (er) {\\n return false\\n }\\n }\\n\\n return cmp(version, this.operator, this.semver, this.options)\\n }\\n\\n intersects (comp, options) {\\n if (!(comp instanceof Comparator)) {\\n throw new TypeError('a Comparator is required')\\n }\\n\\n if (this.operator === '') {\\n if (this.value === '') {\\n return true\\n }\\n return new Range(comp.value, options).test(this.value)\\n } else if (comp.operator === '') {\\n if (comp.value === '') {\\n return true\\n }\\n return new Range(this.value, options).test(comp.semver)\\n }\\n\\n options = parseOptions(options)\\n\\n // Special cases where nothing can possibly be lower\\n if (options.includePrerelease &&\\n (this.value === '<0.0.0-0' || comp.value === '<0.0.0-0')) {\\n return false\\n }\\n if (!options.includePrerelease &&\\n (this.value.startsWith('<0.0.0') || comp.value.startsWith('<0.0.0'))) {\\n return false\\n }\\n\\n // Same direction increasing (> or >=)\\n if (this.operator.startsWith('>') && comp.operator.startsWith('>')) {\\n return true\\n }\\n // Same direction decreasing (< or <=)\\n if (this.operator.startsWith('<') && comp.operator.startsWith('<')) {\\n return true\\n }\\n // same SemVer and both sides are inclusive (<= or >=)\\n if (\\n (this.semver.version === comp.semver.version) &&\\n this.operator.includes('=') && comp.operator.includes('=')) {\\n return true\\n }\\n // opposite directions less than\\n if (cmp(this.semver, '<', comp.semver, options) &&\\n this.operator.startsWith('>') && comp.operator.startsWith('<')) {\\n return true\\n }\\n // opposite directions greater than\\n if (cmp(this.semver, '>', comp.semver, options) &&\\n this.operator.startsWith('<') && comp.operator.startsWith('>')) {\\n return true\\n }\\n return false\\n }\\n}\\n\\nmodule.exports = Comparator\\n\\nconst parseOptions = require('../internal/parse-options')\\nconst { safeRe: re, t } = require('../internal/re')\\nconst cmp = require('../functions/cmp')\\nconst debug = require('../internal/debug')\\nconst SemVer = require('./semver')\\nconst Range = require('./range')\\n\",\"'use strict'\\n\\nconst Range = require('../classes/range')\\nconst satisfies = (version, range, options) => {\\n try {\\n range = new Range(range, options)\\n } catch (er) {\\n return false\\n }\\n return range.test(version)\\n}\\nmodule.exports = satisfies\\n\",\"'use strict'\\n\\nconst Range = require('../classes/range')\\n\\n// Mostly just for testing and legacy API reasons\\nconst toComparators = (range, options) =>\\n new Range(range, options).set\\n .map(comp => comp.map(c => c.value).join(' ').trim().split(' '))\\n\\nmodule.exports = toComparators\\n\",\"'use strict'\\n\\nconst SemVer = require('../classes/semver')\\nconst Range = require('../classes/range')\\n\\nconst maxSatisfying = (versions, range, options) => {\\n let max = null\\n let maxSV = null\\n let rangeObj = null\\n try {\\n rangeObj = new Range(range, options)\\n } catch (er) {\\n return null\\n }\\n versions.forEach((v) => {\\n if (rangeObj.test(v)) {\\n // satisfies(v, range, options)\\n if (!max || maxSV.compare(v) === -1) {\\n // compare(max, v, true)\\n max = v\\n maxSV = new SemVer(max, options)\\n }\\n }\\n })\\n return max\\n}\\nmodule.exports = maxSatisfying\\n\",\"'use strict'\\n\\nconst SemVer = require('../classes/semver')\\nconst Range = require('../classes/range')\\nconst minSatisfying = (versions, range, options) => {\\n let min = null\\n let minSV = null\\n let rangeObj = null\\n try {\\n rangeObj = new Range(range, options)\\n } catch (er) {\\n return null\\n }\\n versions.forEach((v) => {\\n if (rangeObj.test(v)) {\\n // satisfies(v, range, options)\\n if (!min || minSV.compare(v) === 1) {\\n // compare(min, v, true)\\n min = v\\n minSV = new SemVer(min, options)\\n }\\n }\\n })\\n return min\\n}\\nmodule.exports = minSatisfying\\n\",\"'use strict'\\n\\nconst SemVer = require('../classes/semver')\\nconst Range = require('../classes/range')\\nconst gt = require('../functions/gt')\\n\\nconst minVersion = (range, loose) => {\\n range = new Range(range, loose)\\n\\n let minver = new SemVer('0.0.0')\\n if (range.test(minver)) {\\n return minver\\n }\\n\\n minver = new SemVer('0.0.0-0')\\n if (range.test(minver)) {\\n return minver\\n }\\n\\n minver = null\\n for (let i = 0; i < range.set.length; ++i) {\\n const comparators = range.set[i]\\n\\n let setMin = null\\n comparators.forEach((comparator) => {\\n // Clone to avoid manipulating the comparator's semver object.\\n const compver = new SemVer(comparator.semver.version)\\n switch (comparator.operator) {\\n case '>':\\n if (compver.prerelease.length === 0) {\\n compver.patch++\\n } else {\\n compver.prerelease.push(0)\\n }\\n compver.raw = compver.format()\\n /* fallthrough */\\n case '':\\n case '>=':\\n if (!setMin || gt(compver, setMin)) {\\n setMin = compver\\n }\\n break\\n case '<':\\n case '<=':\\n /* Ignore maximum versions */\\n break\\n /* istanbul ignore next */\\n default:\\n throw new Error(`Unexpected operation: ${comparator.operator}`)\\n }\\n })\\n if (setMin && (!minver || gt(minver, setMin))) {\\n minver = setMin\\n }\\n }\\n\\n if (minver && range.test(minver)) {\\n return minver\\n }\\n\\n return null\\n}\\nmodule.exports = minVersion\\n\",\"'use strict'\\n\\nconst Range = require('../classes/range')\\nconst validRange = (range, options) => {\\n try {\\n // Return '*' instead of '' so that truthiness works.\\n // This will throw if it's invalid anyway\\n return new Range(range, options).range || '*'\\n } catch (er) {\\n return null\\n }\\n}\\nmodule.exports = validRange\\n\",\"'use strict'\\n\\nconst SemVer = require('../classes/semver')\\nconst Comparator = require('../classes/comparator')\\nconst { ANY } = Comparator\\nconst Range = require('../classes/range')\\nconst satisfies = require('../functions/satisfies')\\nconst gt = require('../functions/gt')\\nconst lt = require('../functions/lt')\\nconst lte = require('../functions/lte')\\nconst gte = require('../functions/gte')\\n\\nconst outside = (version, range, hilo, options) => {\\n version = new SemVer(version, options)\\n range = new Range(range, options)\\n\\n let gtfn, ltefn, ltfn, comp, ecomp\\n switch (hilo) {\\n case '>':\\n gtfn = gt\\n ltefn = lte\\n ltfn = lt\\n comp = '>'\\n ecomp = '>='\\n break\\n case '<':\\n gtfn = lt\\n ltefn = gte\\n ltfn = gt\\n comp = '<'\\n ecomp = '<='\\n break\\n default:\\n throw new TypeError('Must provide a hilo val of \\\"<\\\" or \\\">\\\"')\\n }\\n\\n // If it satisfies the range it is not outside\\n if (satisfies(version, range, options)) {\\n return false\\n }\\n\\n // From now on, variable terms are as if we're in \\\"gtr\\\" mode.\\n // but note that everything is flipped for the \\\"ltr\\\" function.\\n\\n for (let i = 0; i < range.set.length; ++i) {\\n const comparators = range.set[i]\\n\\n let high = null\\n let low = null\\n\\n comparators.forEach((comparator) => {\\n if (comparator.semver === ANY) {\\n comparator = new Comparator('>=0.0.0')\\n }\\n high = high || comparator\\n low = low || comparator\\n if (gtfn(comparator.semver, high.semver, options)) {\\n high = comparator\\n } else if (ltfn(comparator.semver, low.semver, options)) {\\n low = comparator\\n }\\n })\\n\\n // If the edge version comparator has a operator then our version\\n // isn't outside it\\n if (high.operator === comp || high.operator === ecomp) {\\n return false\\n }\\n\\n // If the lowest version comparator has an operator and our version\\n // is less than it then it isn't higher than the range\\n if ((!low.operator || low.operator === comp) &&\\n ltefn(version, low.semver)) {\\n return false\\n } else if (low.operator === ecomp && ltfn(version, low.semver)) {\\n return false\\n }\\n }\\n return true\\n}\\n\\nmodule.exports = outside\\n\",\"'use strict'\\n\\n// Determine if version is greater than all the versions possible in the range.\\nconst outside = require('./outside')\\nconst gtr = (version, range, options) => outside(version, range, '>', options)\\nmodule.exports = gtr\\n\",\"'use strict'\\n\\nconst outside = require('./outside')\\n// Determine if version is less than all the versions possible in the range\\nconst ltr = (version, range, options) => outside(version, range, '<', options)\\nmodule.exports = ltr\\n\",\"'use strict'\\n\\nconst Range = require('../classes/range')\\nconst intersects = (r1, r2, options) => {\\n r1 = new Range(r1, options)\\n r2 = new Range(r2, options)\\n return r1.intersects(r2, options)\\n}\\nmodule.exports = intersects\\n\",\"'use strict'\\n\\n// given a set of versions and a range, create a \\\"simplified\\\" range\\n// that includes the same versions that the original range does\\n// If the original range is shorter than the simplified one, return that.\\nconst satisfies = require('../functions/satisfies.js')\\nconst compare = require('../functions/compare.js')\\nmodule.exports = (versions, range, options) => {\\n const set = []\\n let first = null\\n let prev = null\\n const v = versions.sort((a, b) => compare(a, b, options))\\n for (const version of v) {\\n const included = satisfies(version, range, options)\\n if (included) {\\n prev = version\\n if (!first) {\\n first = version\\n }\\n } else {\\n if (prev) {\\n set.push([first, prev])\\n }\\n prev = null\\n first = null\\n }\\n }\\n if (first) {\\n set.push([first, null])\\n }\\n\\n const ranges = []\\n for (const [min, max] of set) {\\n if (min === max) {\\n ranges.push(min)\\n } else if (!max && min === v[0]) {\\n ranges.push('*')\\n } else if (!max) {\\n ranges.push(`>=${min}`)\\n } else if (min === v[0]) {\\n ranges.push(`<=${max}`)\\n } else {\\n ranges.push(`${min} - ${max}`)\\n }\\n }\\n const simplified = ranges.join(' || ')\\n const original = typeof range.raw === 'string' ? range.raw : String(range)\\n return simplified.length < original.length ? simplified : range\\n}\\n\",\"'use strict'\\n\\nconst Range = require('../classes/range.js')\\nconst Comparator = require('../classes/comparator.js')\\nconst { ANY } = Comparator\\nconst satisfies = require('../functions/satisfies.js')\\nconst compare = require('../functions/compare.js')\\n\\n// Complex range `r1 || r2 || ...` is a subset of `R1 || R2 || ...` iff:\\n// - Every simple range `r1, r2, ...` is a null set, OR\\n// - Every simple range `r1, r2, ...` which is not a null set is a subset of\\n// some `R1, R2, ...`\\n//\\n// Simple range `c1 c2 ...` is a subset of simple range `C1 C2 ...` iff:\\n// - If c is only the ANY comparator\\n// - If C is only the ANY comparator, return true\\n// - Else if in prerelease mode, return false\\n// - else replace c with `[>=0.0.0]`\\n// - If C is only the ANY comparator\\n// - if in prerelease mode, return true\\n// - else replace C with `[>=0.0.0]`\\n// - Let EQ be the set of = comparators in c\\n// - If EQ is more than one, return true (null set)\\n// - Let GT be the highest > or >= comparator in c\\n// - Let LT be the lowest < or <= comparator in c\\n// - If GT and LT, and GT.semver > LT.semver, return true (null set)\\n// - If any C is a = range, and GT or LT are set, return false\\n// - If EQ\\n// - If GT, and EQ does not satisfy GT, return true (null set)\\n// - If LT, and EQ does not satisfy LT, return true (null set)\\n// - If EQ satisfies every C, return true\\n// - Else return false\\n// - If GT\\n// - If GT.semver is lower than any > or >= comp in C, return false\\n// - If GT is >=, and GT.semver does not satisfy every C, return false\\n// - If GT.semver has a prerelease, and not in prerelease mode\\n// - If no C has a prerelease and the GT.semver tuple, return false\\n// - If LT\\n// - If LT.semver is greater than any < or <= comp in C, return false\\n// - If LT is <=, and LT.semver does not satisfy every C, return false\\n// - If GT.semver has a prerelease, and not in prerelease mode\\n// - If no C has a prerelease and the LT.semver tuple, return false\\n// - Else return true\\n\\nconst subset = (sub, dom, options = {}) => {\\n if (sub === dom) {\\n return true\\n }\\n\\n sub = new Range(sub, options)\\n dom = new Range(dom, options)\\n let sawNonNull = false\\n\\n OUTER: for (const simpleSub of sub.set) {\\n for (const simpleDom of dom.set) {\\n const isSub = simpleSubset(simpleSub, simpleDom, options)\\n sawNonNull = sawNonNull || isSub !== null\\n if (isSub) {\\n continue OUTER\\n }\\n }\\n // the null set is a subset of everything, but null simple ranges in\\n // a complex range should be ignored. so if we saw a non-null range,\\n // then we know this isn't a subset, but if EVERY simple range was null,\\n // then it is a subset.\\n if (sawNonNull) {\\n return false\\n }\\n }\\n return true\\n}\\n\\nconst minimumVersionWithPreRelease = [new Comparator('>=0.0.0-0')]\\nconst minimumVersion = [new Comparator('>=0.0.0')]\\n\\nconst simpleSubset = (sub, dom, options) => {\\n if (sub === dom) {\\n return true\\n }\\n\\n if (sub.length === 1 && sub[0].semver === ANY) {\\n if (dom.length === 1 && dom[0].semver === ANY) {\\n return true\\n } else if (options.includePrerelease) {\\n sub = minimumVersionWithPreRelease\\n } else {\\n sub = minimumVersion\\n }\\n }\\n\\n if (dom.length === 1 && dom[0].semver === ANY) {\\n if (options.includePrerelease) {\\n return true\\n } else {\\n dom = minimumVersion\\n }\\n }\\n\\n const eqSet = new Set()\\n let gt, lt\\n for (const c of sub) {\\n if (c.operator === '>' || c.operator === '>=') {\\n gt = higherGT(gt, c, options)\\n } else if (c.operator === '<' || c.operator === '<=') {\\n lt = lowerLT(lt, c, options)\\n } else {\\n eqSet.add(c.semver)\\n }\\n }\\n\\n if (eqSet.size > 1) {\\n return null\\n }\\n\\n let gtltComp\\n if (gt && lt) {\\n gtltComp = compare(gt.semver, lt.semver, options)\\n if (gtltComp > 0) {\\n return null\\n } else if (gtltComp === 0 && (gt.operator !== '>=' || lt.operator !== '<=')) {\\n return null\\n }\\n }\\n\\n // will iterate one or zero times\\n for (const eq of eqSet) {\\n if (gt && !satisfies(eq, String(gt), options)) {\\n return null\\n }\\n\\n if (lt && !satisfies(eq, String(lt), options)) {\\n return null\\n }\\n\\n for (const c of dom) {\\n if (!satisfies(eq, String(c), options)) {\\n return false\\n }\\n }\\n\\n return true\\n }\\n\\n let higher, lower\\n let hasDomLT, hasDomGT\\n // if the subset has a prerelease, we need a comparator in the superset\\n // with the same tuple and a prerelease, or it's not a subset\\n let needDomLTPre = lt &&\\n !options.includePrerelease &&\\n lt.semver.prerelease.length ? lt.semver : false\\n let needDomGTPre = gt &&\\n !options.includePrerelease &&\\n gt.semver.prerelease.length ? gt.semver : false\\n // exception: <1.2.3-0 is the same as <1.2.3\\n if (needDomLTPre && needDomLTPre.prerelease.length === 1 &&\\n lt.operator === '<' && needDomLTPre.prerelease[0] === 0) {\\n needDomLTPre = false\\n }\\n\\n for (const c of dom) {\\n hasDomGT = hasDomGT || c.operator === '>' || c.operator === '>='\\n hasDomLT = hasDomLT || c.operator === '<' || c.operator === '<='\\n if (gt) {\\n if (needDomGTPre) {\\n if (c.semver.prerelease && c.semver.prerelease.length &&\\n c.semver.major === needDomGTPre.major &&\\n c.semver.minor === needDomGTPre.minor &&\\n c.semver.patch === needDomGTPre.patch) {\\n needDomGTPre = false\\n }\\n }\\n if (c.operator === '>' || c.operator === '>=') {\\n higher = higherGT(gt, c, options)\\n if (higher === c && higher !== gt) {\\n return false\\n }\\n } else if (gt.operator === '>=' && !satisfies(gt.semver, String(c), options)) {\\n return false\\n }\\n }\\n if (lt) {\\n if (needDomLTPre) {\\n if (c.semver.prerelease && c.semver.prerelease.length &&\\n c.semver.major === needDomLTPre.major &&\\n c.semver.minor === needDomLTPre.minor &&\\n c.semver.patch === needDomLTPre.patch) {\\n needDomLTPre = false\\n }\\n }\\n if (c.operator === '<' || c.operator === '<=') {\\n lower = lowerLT(lt, c, options)\\n if (lower === c && lower !== lt) {\\n return false\\n }\\n } else if (lt.operator === '<=' && !satisfies(lt.semver, String(c), options)) {\\n return false\\n }\\n }\\n if (!c.operator && (lt || gt) && gtltComp !== 0) {\\n return false\\n }\\n }\\n\\n // if there was a < or >, and nothing in the dom, then must be false\\n // UNLESS it was limited by another range in the other direction.\\n // Eg, >1.0.0 <1.0.1 is still a subset of <2.0.0\\n if (gt && hasDomLT && !lt && gtltComp !== 0) {\\n return false\\n }\\n\\n if (lt && hasDomGT && !gt && gtltComp !== 0) {\\n return false\\n }\\n\\n // we needed a prerelease range in a specific tuple, but didn't get one\\n // then this isn't a subset. eg >=1.2.3-pre is not a subset of >=1.0.0,\\n // because it includes prereleases in the 1.2.3 tuple\\n if (needDomGTPre || needDomLTPre) {\\n return false\\n }\\n\\n return true\\n}\\n\\n// >=1.2.3 is lower than >1.2.3\\nconst higherGT = (a, b, options) => {\\n if (!a) {\\n return b\\n }\\n const comp = compare(a.semver, b.semver, options)\\n return comp > 0 ? a\\n : comp < 0 ? b\\n : b.operator === '>' && a.operator === '>=' ? b\\n : a\\n}\\n\\n// <=1.2.3 is higher than <1.2.3\\nconst lowerLT = (a, b, options) => {\\n if (!a) {\\n return b\\n }\\n const comp = compare(a.semver, b.semver, options)\\n return comp < 0 ? a\\n : comp > 0 ? b\\n : b.operator === '<' && a.operator === '<=' ? b\\n : a\\n}\\n\\nmodule.exports = subset\\n\",\"'use strict'\\n\\n// just pre-load all the stuff that index.js lazily exports\\nconst internalRe = require('./internal/re')\\nconst constants = require('./internal/constants')\\nconst SemVer = require('./classes/semver')\\nconst identifiers = require('./internal/identifiers')\\nconst parse = require('./functions/parse')\\nconst valid = require('./functions/valid')\\nconst clean = require('./functions/clean')\\nconst inc = require('./functions/inc')\\nconst diff = require('./functions/diff')\\nconst major = require('./functions/major')\\nconst minor = require('./functions/minor')\\nconst patch = require('./functions/patch')\\nconst prerelease = require('./functions/prerelease')\\nconst compare = require('./functions/compare')\\nconst rcompare = require('./functions/rcompare')\\nconst compareLoose = require('./functions/compare-loose')\\nconst compareBuild = require('./functions/compare-build')\\nconst sort = require('./functions/sort')\\nconst rsort = require('./functions/rsort')\\nconst gt = require('./functions/gt')\\nconst lt = require('./functions/lt')\\nconst eq = require('./functions/eq')\\nconst neq = require('./functions/neq')\\nconst gte = require('./functions/gte')\\nconst lte = require('./functions/lte')\\nconst cmp = require('./functions/cmp')\\nconst coerce = require('./functions/coerce')\\nconst Comparator = require('./classes/comparator')\\nconst Range = require('./classes/range')\\nconst satisfies = require('./functions/satisfies')\\nconst toComparators = require('./ranges/to-comparators')\\nconst maxSatisfying = require('./ranges/max-satisfying')\\nconst minSatisfying = require('./ranges/min-satisfying')\\nconst minVersion = require('./ranges/min-version')\\nconst validRange = require('./ranges/valid')\\nconst outside = require('./ranges/outside')\\nconst gtr = require('./ranges/gtr')\\nconst ltr = require('./ranges/ltr')\\nconst intersects = require('./ranges/intersects')\\nconst simplifyRange = require('./ranges/simplify')\\nconst subset = require('./ranges/subset')\\nmodule.exports = {\\n parse,\\n valid,\\n clean,\\n inc,\\n diff,\\n major,\\n minor,\\n patch,\\n prerelease,\\n compare,\\n rcompare,\\n compareLoose,\\n compareBuild,\\n sort,\\n rsort,\\n gt,\\n lt,\\n eq,\\n neq,\\n gte,\\n lte,\\n cmp,\\n coerce,\\n Comparator,\\n Range,\\n satisfies,\\n toComparators,\\n maxSatisfying,\\n minSatisfying,\\n minVersion,\\n validRange,\\n outside,\\n gtr,\\n ltr,\\n intersects,\\n simplifyRange,\\n subset,\\n SemVer,\\n re: internalRe.re,\\n src: internalRe.src,\\n tokens: internalRe.t,\\n SEMVER_SPEC_VERSION: constants.SEMVER_SPEC_VERSION,\\n RELEASE_TYPES: constants.RELEASE_TYPES,\\n compareIdentifiers: identifiers.compareIdentifiers,\\n rcompareIdentifiers: identifiers.rcompareIdentifiers,\\n}\\n\",\"/*! crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */\\n/* vim: set ts=2: */\\n/*exported CRC32 */\\nvar CRC32;\\n(function (factory) {\\n\\t/*jshint ignore:start */\\n\\t/*eslint-disable */\\n\\tif(typeof DO_NOT_EXPORT_CRC === 'undefined') {\\n\\t\\tif('object' === typeof exports) {\\n\\t\\t\\tfactory(exports);\\n\\t\\t} else if ('function' === typeof define && define.amd) {\\n\\t\\t\\tdefine(function () {\\n\\t\\t\\t\\tvar module = {};\\n\\t\\t\\t\\tfactory(module);\\n\\t\\t\\t\\treturn module;\\n\\t\\t\\t});\\n\\t\\t} else {\\n\\t\\t\\tfactory(CRC32 = {});\\n\\t\\t}\\n\\t} else {\\n\\t\\tfactory(CRC32 = {});\\n\\t}\\n\\t/*eslint-enable */\\n\\t/*jshint ignore:end */\\n}(function(CRC32) {\\nCRC32.version = '1.2.2';\\n/*global Int32Array */\\nfunction signed_crc_table() {\\n\\tvar c = 0, table = new Array(256);\\n\\n\\tfor(var n =0; n != 256; ++n){\\n\\t\\tc = n;\\n\\t\\tc = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));\\n\\t\\tc = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));\\n\\t\\tc = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));\\n\\t\\tc = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));\\n\\t\\tc = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));\\n\\t\\tc = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));\\n\\t\\tc = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));\\n\\t\\tc = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));\\n\\t\\ttable[n] = c;\\n\\t}\\n\\n\\treturn typeof Int32Array !== 'undefined' ? new Int32Array(table) : table;\\n}\\n\\nvar T0 = signed_crc_table();\\nfunction slice_by_16_tables(T) {\\n\\tvar c = 0, v = 0, n = 0, table = typeof Int32Array !== 'undefined' ? new Int32Array(4096) : new Array(4096) ;\\n\\n\\tfor(n = 0; n != 256; ++n) table[n] = T[n];\\n\\tfor(n = 0; n != 256; ++n) {\\n\\t\\tv = T[n];\\n\\t\\tfor(c = 256 + n; c < 4096; c += 256) v = table[c] = (v >>> 8) ^ T[v & 0xFF];\\n\\t}\\n\\tvar out = [];\\n\\tfor(n = 1; n != 16; ++n) out[n - 1] = typeof Int32Array !== 'undefined' ? table.subarray(n * 256, n * 256 + 256) : table.slice(n * 256, n * 256 + 256);\\n\\treturn out;\\n}\\nvar TT = slice_by_16_tables(T0);\\nvar T1 = TT[0], T2 = TT[1], T3 = TT[2], T4 = TT[3], T5 = TT[4];\\nvar T6 = TT[5], T7 = TT[6], T8 = TT[7], T9 = TT[8], Ta = TT[9];\\nvar Tb = TT[10], Tc = TT[11], Td = TT[12], Te = TT[13], Tf = TT[14];\\nfunction crc32_bstr(bstr, seed) {\\n\\tvar C = seed ^ -1;\\n\\tfor(var i = 0, L = bstr.length; i < L;) C = (C>>>8) ^ T0[(C^bstr.charCodeAt(i++))&0xFF];\\n\\treturn ~C;\\n}\\n\\nfunction crc32_buf(B, seed) {\\n\\tvar C = seed ^ -1, L = B.length - 15, i = 0;\\n\\tfor(; i < L;) C =\\n\\t\\tTf[B[i++] ^ (C & 255)] ^\\n\\t\\tTe[B[i++] ^ ((C >> 8) & 255)] ^\\n\\t\\tTd[B[i++] ^ ((C >> 16) & 255)] ^\\n\\t\\tTc[B[i++] ^ (C >>> 24)] ^\\n\\t\\tTb[B[i++]] ^ Ta[B[i++]] ^ T9[B[i++]] ^ T8[B[i++]] ^\\n\\t\\tT7[B[i++]] ^ T6[B[i++]] ^ T5[B[i++]] ^ T4[B[i++]] ^\\n\\t\\tT3[B[i++]] ^ T2[B[i++]] ^ T1[B[i++]] ^ T0[B[i++]];\\n\\tL += 15;\\n\\twhile(i < L) C = (C>>>8) ^ T0[(C^B[i++])&0xFF];\\n\\treturn ~C;\\n}\\n\\nfunction crc32_str(str, seed) {\\n\\tvar C = seed ^ -1;\\n\\tfor(var i = 0, L = str.length, c = 0, d = 0; i < L;) {\\n\\t\\tc = str.charCodeAt(i++);\\n\\t\\tif(c < 0x80) {\\n\\t\\t\\tC = (C>>>8) ^ T0[(C^c)&0xFF];\\n\\t\\t} else if(c < 0x800) {\\n\\t\\t\\tC = (C>>>8) ^ T0[(C ^ (192|((c>>6)&31)))&0xFF];\\n\\t\\t\\tC = (C>>>8) ^ T0[(C ^ (128|(c&63)))&0xFF];\\n\\t\\t} else if(c >= 0xD800 && c < 0xE000) {\\n\\t\\t\\tc = (c&1023)+64; d = str.charCodeAt(i++)&1023;\\n\\t\\t\\tC = (C>>>8) ^ T0[(C ^ (240|((c>>8)&7)))&0xFF];\\n\\t\\t\\tC = (C>>>8) ^ T0[(C ^ (128|((c>>2)&63)))&0xFF];\\n\\t\\t\\tC = (C>>>8) ^ T0[(C ^ (128|((d>>6)&15)|((c&3)<<4)))&0xFF];\\n\\t\\t\\tC = (C>>>8) ^ T0[(C ^ (128|(d&63)))&0xFF];\\n\\t\\t} else {\\n\\t\\t\\tC = (C>>>8) ^ T0[(C ^ (224|((c>>12)&15)))&0xFF];\\n\\t\\t\\tC = (C>>>8) ^ T0[(C ^ (128|((c>>6)&63)))&0xFF];\\n\\t\\t\\tC = (C>>>8) ^ T0[(C ^ (128|(c&63)))&0xFF];\\n\\t\\t}\\n\\t}\\n\\treturn ~C;\\n}\\nCRC32.table = T0;\\n// $FlowIgnore\\nCRC32.bstr = crc32_bstr;\\n// $FlowIgnore\\nCRC32.buf = crc32_buf;\\n// $FlowIgnore\\nCRC32.str = crc32_str;\\n}));\\n\",\"import { toByteArray, fromByteArray } from 'base64-js';\\nimport { inflateSync } from 'fflate';\\nimport deepEqual from 'fast-deep-equal';\\nimport stableStringify from 'fast-json-stable-stringify';\\nimport he from 'he';\\nimport jsonLogic from 'json-logic-js';\\nimport LinkifyIt from 'linkify-it';\\nimport MarkdownIt from 'markdown-it';\\nimport { sha256 } from '@noble/hashes/sha256';\\nimport { bytesToHex } from '@noble/hashes/utils';\\nimport { match as pathMatch } from 'path-to-regexp';\\nimport semver from 'semver';\\nimport TinyQueue from 'tinyqueue';\\nimport CRC32 from 'crc-32';\\n\\nlet summary;\\ntry {\\n const metadataText = Host.v2.document.get('pack/metadata.json');\\n const ruleText = Host.v2.document.get('rules/findings.json');\\n const compressedAttachment = Host.v2.document.get('pack/attachment.deflated');\\n const payload = Host.v2.document.get('bytes/payload');\\n const extraPayload = Host.v2.document.get('bytes/flagship-extra');\\n\\n const metadata = JSON.parse(metadataText);\\n const docPaths = metadata.links ?? ['docs/a.md', 'docs/b.md'];\\n const docs = docPaths.map((docPath) => ({\\n docPath,\\n text: Host.v2.document.get(docPath),\\n }));\\n const markdown = new MarkdownIt({ linkify: true });\\n const linkify = new LinkifyIt();\\n const markdownSource = docs.map((doc) => doc.text).join('\\\\n');\\n const markdownTokens = markdown.parse(markdownSource, {});\\n const linkMatches = docs\\n .flatMap((doc) => linkify.match(doc.text) ?? [])\\n .map((item) => item.url);\\n\\n const releaseChecks = (metadata.requires ?? []).map((range) =>\\n semver.satisfies(metadata.release, range),\\n );\\n const rules = JSON.parse(ruleText);\\n const findingInput = {\\n linkCount: linkMatches.length,\\n releaseOk: releaseChecks.every(Boolean),\\n };\\n const ruleInputStable = deepEqual(\\n findingInput,\\n JSON.parse(stableStringify(findingInput)),\\n );\\n const rulePasses = Boolean(jsonLogic.apply(rules, findingInput));\\n\\n const queue = new TinyQueue(\\n [],\\n (left, right) => left.priority - right.priority,\\n );\\n for (const link of linkMatches) {\\n queue.push({ link, priority: link.length });\\n }\\n const orderedLinks = [];\\n while (queue.length > 0) {\\n orderedLinks.push(queue.pop().link);\\n }\\n\\n const decompressed = inflateSync(compressedAttachment);\\n const attachmentRoundTrip = toByteArray(fromByteArray(decompressed));\\n const mergedBinary = new Uint8Array(\\n attachmentRoundTrip.length + payload.length + extraPayload.length,\\n );\\n mergedBinary.set(attachmentRoundTrip, 0);\\n mergedBinary.set(payload, attachmentRoundTrip.length);\\n mergedBinary.set(extraPayload, attachmentRoundTrip.length + payload.length);\\n const digestHex = bytesToHex(sha256(mergedBinary));\\n const crc32 = (CRC32.buf(mergedBinary) >>> 0).toString(16).padStart(8, '0');\\n\\n const decodedEntities = he.decode('<b>safe</b>');\\n const versionCapture = pathMatch('/document/:id/version/:version')(\\n '/document/42/version/1.2.3',\\n );\\n const orderedFindings = [\\n { id: 'links', value: linkMatches.length },\\n { id: 'rules', value: Number(rulePasses) },\\n { id: 'tokens', value: markdownTokens.length },\\n ].sort((left, right) => left.id.localeCompare(right.id));\\n\\n Promise.resolve('scheduled').then(() => undefined);\\n queueMicrotask(() => undefined);\\n\\n for (const doc of docs) {\\n Host.v2.emit({\\n type: 'knowledge-pack-doc',\\n docPath: doc.docPath,\\n length: doc.text.length,\\n });\\n }\\n\\n summary = {\\n status: 'ok',\\n packId: metadata.packId,\\n release: metadata.release,\\n checks: releaseChecks,\\n docTokenCount: markdownTokens.length,\\n linkCount: linkMatches.length,\\n uniqueLinks: [...new Set(orderedLinks)],\\n binary: {\\n byteLength: mergedBinary.length,\\n digestHex,\\n crc32,\\n },\\n decodedEntities,\\n versionCapture,\\n findings: orderedFindings,\\n ruleInputStable,\\n rulePasses,\\n };\\n} catch (error) {\\n summary = {\\n status: 'error',\\n message: String(error instanceof Error ? error.message : error),\\n };\\n}\\n\\nHost.v2.emit({\\n type: 'knowledge-pack-summary',\\n summaryHash: bytesToHex(\\n sha256(\\n toByteArray(\\n fromByteArray(\\n new Uint8Array([\\n ...Host.v2.document.get('bytes/payload'),\\n ...Host.v2.document.get('bytes/flagship-extra'),\\n ]),\\n ),\\n ),\\n ),\\n ),\\n status: summary.status,\\n});\\n\\nexport default summary;\\n\",\"// DEFLATE is a complex format; to read this code, you should probably check the RFC first:\\n// https://tools.ietf.org/html/rfc1951\\n// You may also wish to take a look at the guide I made about this program:\\n// https://gist.github.com/101arrowz/253f31eb5abc3d9275ab943003ffecad\\n// Some of the following code is similar to that of UZIP.js:\\n// https://github.com/photopea/UZIP.js\\n// However, the vast majority of the codebase has diverged from UZIP.js to increase performance and reduce bundle size.\\n// Sometimes 0 will appear where -1 would be more appropriate. This is because using a uint\\n// is better for memory in most engines (I *think*).\\nvar ch2 = {};\\nvar wk = (function (c, id, msg, transfer, cb) {\\n var w = new Worker(ch2[id] || (ch2[id] = URL.createObjectURL(new Blob([\\n c + ';addEventListener(\\\"error\\\",function(e){e=e.error;postMessage({$e$:[e.message,e.code,e.stack]})})'\\n ], { type: 'text/javascript' }))));\\n w.onmessage = function (e) {\\n var d = e.data, ed = d.$e$;\\n if (ed) {\\n var err = new Error(ed[0]);\\n err['code'] = ed[1];\\n err.stack = ed[2];\\n cb(err, null);\\n }\\n else\\n cb(null, d);\\n };\\n w.postMessage(msg, transfer);\\n return w;\\n});\\n\\n// aliases for shorter compressed code (most minifers don't do this)\\nvar u8 = Uint8Array, u16 = Uint16Array, i32 = Int32Array;\\n// fixed length extra bits\\nvar fleb = new u8([0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, /* unused */ 0, 0, /* impossible */ 0]);\\n// fixed distance extra bits\\nvar fdeb = new u8([0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, /* unused */ 0, 0]);\\n// code length index map\\nvar clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]);\\n// get base, reverse index map from extra bits\\nvar freb = function (eb, start) {\\n var b = new u16(31);\\n for (var i = 0; i < 31; ++i) {\\n b[i] = start += 1 << eb[i - 1];\\n }\\n // numbers here are at max 18 bits\\n var r = new i32(b[30]);\\n for (var i = 1; i < 30; ++i) {\\n for (var j = b[i]; j < b[i + 1]; ++j) {\\n r[j] = ((j - b[i]) << 5) | i;\\n }\\n }\\n return { b: b, r: r };\\n};\\nvar _a = freb(fleb, 2), fl = _a.b, revfl = _a.r;\\n// we can ignore the fact that the other numbers are wrong; they never happen anyway\\nfl[28] = 258, revfl[258] = 28;\\nvar _b = freb(fdeb, 0), fd = _b.b, revfd = _b.r;\\n// map of value to reverse (assuming 16 bits)\\nvar rev = new u16(32768);\\nfor (var i = 0; i < 32768; ++i) {\\n // reverse table algorithm from SO\\n var x = ((i & 0xAAAA) >> 1) | ((i & 0x5555) << 1);\\n x = ((x & 0xCCCC) >> 2) | ((x & 0x3333) << 2);\\n x = ((x & 0xF0F0) >> 4) | ((x & 0x0F0F) << 4);\\n rev[i] = (((x & 0xFF00) >> 8) | ((x & 0x00FF) << 8)) >> 1;\\n}\\n// create huffman tree from u8 \\\"map\\\": index -> code length for code index\\n// mb (max bits) must be at most 15\\n// TODO: optimize/split up?\\nvar hMap = (function (cd, mb, r) {\\n var s = cd.length;\\n // index\\n var i = 0;\\n // u16 \\\"map\\\": index -> # of codes with bit length = index\\n var l = new u16(mb);\\n // length of cd must be 288 (total # of codes)\\n for (; i < s; ++i) {\\n if (cd[i])\\n ++l[cd[i] - 1];\\n }\\n // u16 \\\"map\\\": index -> minimum code for bit length = index\\n var le = new u16(mb);\\n for (i = 1; i < mb; ++i) {\\n le[i] = (le[i - 1] + l[i - 1]) << 1;\\n }\\n var co;\\n if (r) {\\n // u16 \\\"map\\\": index -> number of actual bits, symbol for code\\n co = new u16(1 << mb);\\n // bits to remove for reverser\\n var rvb = 15 - mb;\\n for (i = 0; i < s; ++i) {\\n // ignore 0 lengths\\n if (cd[i]) {\\n // num encoding both symbol and bits read\\n var sv = (i << 4) | cd[i];\\n // free bits\\n var r_1 = mb - cd[i];\\n // start value\\n var v = le[cd[i] - 1]++ << r_1;\\n // m is end value\\n for (var m = v | ((1 << r_1) - 1); v <= m; ++v) {\\n // every 16 bit value starting with the code yields the same result\\n co[rev[v] >> rvb] = sv;\\n }\\n }\\n }\\n }\\n else {\\n co = new u16(s);\\n for (i = 0; i < s; ++i) {\\n if (cd[i]) {\\n co[i] = rev[le[cd[i] - 1]++] >> (15 - cd[i]);\\n }\\n }\\n }\\n return co;\\n});\\n// fixed length tree\\nvar flt = new u8(288);\\nfor (var i = 0; i < 144; ++i)\\n flt[i] = 8;\\nfor (var i = 144; i < 256; ++i)\\n flt[i] = 9;\\nfor (var i = 256; i < 280; ++i)\\n flt[i] = 7;\\nfor (var i = 280; i < 288; ++i)\\n flt[i] = 8;\\n// fixed distance tree\\nvar fdt = new u8(32);\\nfor (var i = 0; i < 32; ++i)\\n fdt[i] = 5;\\n// fixed length map\\nvar flm = /*#__PURE__*/ hMap(flt, 9, 0), flrm = /*#__PURE__*/ hMap(flt, 9, 1);\\n// fixed distance map\\nvar fdm = /*#__PURE__*/ hMap(fdt, 5, 0), fdrm = /*#__PURE__*/ hMap(fdt, 5, 1);\\n// find max of array\\nvar max = function (a) {\\n var m = a[0];\\n for (var i = 1; i < a.length; ++i) {\\n if (a[i] > m)\\n m = a[i];\\n }\\n return m;\\n};\\n// read d, starting at bit p and mask with m\\nvar bits = function (d, p, m) {\\n var o = (p / 8) | 0;\\n return ((d[o] | (d[o + 1] << 8)) >> (p & 7)) & m;\\n};\\n// read d, starting at bit p continuing for at least 16 bits\\nvar bits16 = function (d, p) {\\n var o = (p / 8) | 0;\\n return ((d[o] | (d[o + 1] << 8) | (d[o + 2] << 16)) >> (p & 7));\\n};\\n// get end of byte\\nvar shft = function (p) { return ((p + 7) / 8) | 0; };\\n// typed array slice - allows garbage collector to free original reference,\\n// while being more compatible than .slice\\nvar slc = function (v, s, e) {\\n if (s == null || s < 0)\\n s = 0;\\n if (e == null || e > v.length)\\n e = v.length;\\n // can't use .constructor in case user-supplied\\n return new u8(v.subarray(s, e));\\n};\\n/**\\n * Codes for errors generated within this library\\n */\\nexport var FlateErrorCode = {\\n UnexpectedEOF: 0,\\n InvalidBlockType: 1,\\n InvalidLengthLiteral: 2,\\n InvalidDistance: 3,\\n StreamFinished: 4,\\n NoStreamHandler: 5,\\n InvalidHeader: 6,\\n NoCallback: 7,\\n InvalidUTF8: 8,\\n ExtraFieldTooLong: 9,\\n InvalidDate: 10,\\n FilenameTooLong: 11,\\n StreamFinishing: 12,\\n InvalidZipData: 13,\\n UnknownCompressionMethod: 14\\n};\\n// error codes\\nvar ec = [\\n 'unexpected EOF',\\n 'invalid block type',\\n 'invalid length/literal',\\n 'invalid distance',\\n 'stream finished',\\n 'no stream handler',\\n ,\\n 'no callback',\\n 'invalid UTF-8 data',\\n 'extra field too long',\\n 'date not in range 1980-2099',\\n 'filename too long',\\n 'stream finishing',\\n 'invalid zip data'\\n // determined by unknown compression method\\n];\\n;\\nvar err = function (ind, msg, nt) {\\n var e = new Error(msg || ec[ind]);\\n e.code = ind;\\n if (Error.captureStackTrace)\\n Error.captureStackTrace(e, err);\\n if (!nt)\\n throw e;\\n return e;\\n};\\n// expands raw DEFLATE data\\nvar inflt = function (dat, st, buf, dict) {\\n // source length dict length\\n var sl = dat.length, dl = dict ? dict.length : 0;\\n if (!sl || st.f && !st.l)\\n return buf || new u8(0);\\n var noBuf = !buf;\\n // have to estimate size\\n var resize = noBuf || st.i != 2;\\n // no state\\n var noSt = st.i;\\n // Assumes roughly 33% compression ratio average\\n if (noBuf)\\n buf = new u8(sl * 3);\\n // ensure buffer can fit at least l elements\\n var cbuf = function (l) {\\n var bl = buf.length;\\n // need to increase size to fit\\n if (l > bl) {\\n // Double or set to necessary, whichever is greater\\n var nbuf = new u8(Math.max(bl * 2, l));\\n nbuf.set(buf);\\n buf = nbuf;\\n }\\n };\\n // last chunk bitpos bytes\\n var final = st.f || 0, pos = st.p || 0, bt = st.b || 0, lm = st.l, dm = st.d, lbt = st.m, dbt = st.n;\\n // total bits\\n var tbts = sl * 8;\\n do {\\n if (!lm) {\\n // BFINAL - this is only 1 when last chunk is next\\n final = bits(dat, pos, 1);\\n // type: 0 = no compression, 1 = fixed huffman, 2 = dynamic huffman\\n var type = bits(dat, pos + 1, 3);\\n pos += 3;\\n if (!type) {\\n // go to end of byte boundary\\n var s = shft(pos) + 4, l = dat[s - 4] | (dat[s - 3] << 8), t = s + l;\\n if (t > sl) {\\n if (noSt)\\n err(0);\\n break;\\n }\\n // ensure size\\n if (resize)\\n cbuf(bt + l);\\n // Copy over uncompressed data\\n buf.set(dat.subarray(s, t), bt);\\n // Get new bitpos, update byte count\\n st.b = bt += l, st.p = pos = t * 8, st.f = final;\\n continue;\\n }\\n else if (type == 1)\\n lm = flrm, dm = fdrm, lbt = 9, dbt = 5;\\n else if (type == 2) {\\n // literal lengths\\n var hLit = bits(dat, pos, 31) + 257, hcLen = bits(dat, pos + 10, 15) + 4;\\n var tl = hLit + bits(dat, pos + 5, 31) + 1;\\n pos += 14;\\n // length+distance tree\\n var ldt = new u8(tl);\\n // code length tree\\n var clt = new u8(19);\\n for (var i = 0; i < hcLen; ++i) {\\n // use index map to get real code\\n clt[clim[i]] = bits(dat, pos + i * 3, 7);\\n }\\n pos += hcLen * 3;\\n // code lengths bits\\n var clb = max(clt), clbmsk = (1 << clb) - 1;\\n // code lengths map\\n var clm = hMap(clt, clb, 1);\\n for (var i = 0; i < tl;) {\\n var r = clm[bits(dat, pos, clbmsk)];\\n // bits read\\n pos += r & 15;\\n // symbol\\n var s = r >> 4;\\n // code length to copy\\n if (s < 16) {\\n ldt[i++] = s;\\n }\\n else {\\n // copy count\\n var c = 0, n = 0;\\n if (s == 16)\\n n = 3 + bits(dat, pos, 3), pos += 2, c = ldt[i - 1];\\n else if (s == 17)\\n n = 3 + bits(dat, pos, 7), pos += 3;\\n else if (s == 18)\\n n = 11 + bits(dat, pos, 127), pos += 7;\\n while (n--)\\n ldt[i++] = c;\\n }\\n }\\n // length tree distance tree\\n var lt = ldt.subarray(0, hLit), dt = ldt.subarray(hLit);\\n // max length bits\\n lbt = max(lt);\\n // max dist bits\\n dbt = max(dt);\\n lm = hMap(lt, lbt, 1);\\n dm = hMap(dt, dbt, 1);\\n }\\n else\\n err(1);\\n if (pos > tbts) {\\n if (noSt)\\n err(0);\\n break;\\n }\\n }\\n // Make sure the buffer can hold this + the largest possible addition\\n // Maximum chunk size (practically, theoretically infinite) is 2^17\\n if (resize)\\n cbuf(bt + 131072);\\n var lms = (1 << lbt) - 1, dms = (1 << dbt) - 1;\\n var lpos = pos;\\n for (;; lpos = pos) {\\n // bits read, code\\n var c = lm[bits16(dat, pos) & lms], sym = c >> 4;\\n pos += c & 15;\\n if (pos > tbts) {\\n if (noSt)\\n err(0);\\n break;\\n }\\n if (!c)\\n err(2);\\n if (sym < 256)\\n buf[bt++] = sym;\\n else if (sym == 256) {\\n lpos = pos, lm = null;\\n break;\\n }\\n else {\\n var add = sym - 254;\\n // no extra bits needed if less\\n if (sym > 264) {\\n // index\\n var i = sym - 257, b = fleb[i];\\n add = bits(dat, pos, (1 << b) - 1) + fl[i];\\n pos += b;\\n }\\n // dist\\n var d = dm[bits16(dat, pos) & dms], dsym = d >> 4;\\n if (!d)\\n err(3);\\n pos += d & 15;\\n var dt = fd[dsym];\\n if (dsym > 3) {\\n var b = fdeb[dsym];\\n dt += bits16(dat, pos) & (1 << b) - 1, pos += b;\\n }\\n if (pos > tbts) {\\n if (noSt)\\n err(0);\\n break;\\n }\\n if (resize)\\n cbuf(bt + 131072);\\n var end = bt + add;\\n if (bt < dt) {\\n var shift = dl - dt, dend = Math.min(dt, end);\\n if (shift + bt < 0)\\n err(3);\\n for (; bt < dend; ++bt)\\n buf[bt] = dict[shift + bt];\\n }\\n for (; bt < end; ++bt)\\n buf[bt] = buf[bt - dt];\\n }\\n }\\n st.l = lm, st.p = lpos, st.b = bt, st.f = final;\\n if (lm)\\n final = 1, st.m = lbt, st.d = dm, st.n = dbt;\\n } while (!final);\\n // don't reallocate for streams or user buffers\\n return bt != buf.length && noBuf ? slc(buf, 0, bt) : buf.subarray(0, bt);\\n};\\n// starting at p, write the minimum number of bits that can hold v to d\\nvar wbits = function (d, p, v) {\\n v <<= p & 7;\\n var o = (p / 8) | 0;\\n d[o] |= v;\\n d[o + 1] |= v >> 8;\\n};\\n// starting at p, write the minimum number of bits (>8) that can hold v to d\\nvar wbits16 = function (d, p, v) {\\n v <<= p & 7;\\n var o = (p / 8) | 0;\\n d[o] |= v;\\n d[o + 1] |= v >> 8;\\n d[o + 2] |= v >> 16;\\n};\\n// creates code lengths from a frequency table\\nvar hTree = function (d, mb) {\\n // Need extra info to make a tree\\n var t = [];\\n for (var i = 0; i < d.length; ++i) {\\n if (d[i])\\n t.push({ s: i, f: d[i] });\\n }\\n var s = t.length;\\n var t2 = t.slice();\\n if (!s)\\n return { t: et, l: 0 };\\n if (s == 1) {\\n var v = new u8(t[0].s + 1);\\n v[t[0].s] = 1;\\n return { t: v, l: 1 };\\n }\\n t.sort(function (a, b) { return a.f - b.f; });\\n // after i2 reaches last ind, will be stopped\\n // freq must be greater than largest possible number of symbols\\n t.push({ s: -1, f: 25001 });\\n var l = t[0], r = t[1], i0 = 0, i1 = 1, i2 = 2;\\n t[0] = { s: -1, f: l.f + r.f, l: l, r: r };\\n // efficient algorithm from UZIP.js\\n // i0 is lookbehind, i2 is lookahead - after processing two low-freq\\n // symbols that combined have high freq, will start processing i2 (high-freq,\\n // non-composite) symbols instead\\n // see https://reddit.com/r/photopea/comments/ikekht/uzipjs_questions/\\n while (i1 != s - 1) {\\n l = t[t[i0].f < t[i2].f ? i0++ : i2++];\\n r = t[i0 != i1 && t[i0].f < t[i2].f ? i0++ : i2++];\\n t[i1++] = { s: -1, f: l.f + r.f, l: l, r: r };\\n }\\n var maxSym = t2[0].s;\\n for (var i = 1; i < s; ++i) {\\n if (t2[i].s > maxSym)\\n maxSym = t2[i].s;\\n }\\n // code lengths\\n var tr = new u16(maxSym + 1);\\n // max bits in tree\\n var mbt = ln(t[i1 - 1], tr, 0);\\n if (mbt > mb) {\\n // more algorithms from UZIP.js\\n // TODO: find out how this code works (debt)\\n // ind debt\\n var i = 0, dt = 0;\\n // left cost\\n var lft = mbt - mb, cst = 1 << lft;\\n t2.sort(function (a, b) { return tr[b.s] - tr[a.s] || a.f - b.f; });\\n for (; i < s; ++i) {\\n var i2_1 = t2[i].s;\\n if (tr[i2_1] > mb) {\\n dt += cst - (1 << (mbt - tr[i2_1]));\\n tr[i2_1] = mb;\\n }\\n else\\n break;\\n }\\n dt >>= lft;\\n while (dt > 0) {\\n var i2_2 = t2[i].s;\\n if (tr[i2_2] < mb)\\n dt -= 1 << (mb - tr[i2_2]++ - 1);\\n else\\n ++i;\\n }\\n for (; i >= 0 && dt; --i) {\\n var i2_3 = t2[i].s;\\n if (tr[i2_3] == mb) {\\n --tr[i2_3];\\n ++dt;\\n }\\n }\\n mbt = mb;\\n }\\n return { t: new u8(tr), l: mbt };\\n};\\n// get the max length and assign length codes\\nvar ln = function (n, l, d) {\\n return n.s == -1\\n ? Math.max(ln(n.l, l, d + 1), ln(n.r, l, d + 1))\\n : (l[n.s] = d);\\n};\\n// length codes generation\\nvar lc = function (c) {\\n var s = c.length;\\n // Note that the semicolon was intentional\\n while (s && !c[--s])\\n ;\\n var cl = new u16(++s);\\n // ind num streak\\n var cli = 0, cln = c[0], cls = 1;\\n var w = function (v) { cl[cli++] = v; };\\n for (var i = 1; i <= s; ++i) {\\n if (c[i] == cln && i != s)\\n ++cls;\\n else {\\n if (!cln && cls > 2) {\\n for (; cls > 138; cls -= 138)\\n w(32754);\\n if (cls > 2) {\\n w(cls > 10 ? ((cls - 11) << 5) | 28690 : ((cls - 3) << 5) | 12305);\\n cls = 0;\\n }\\n }\\n else if (cls > 3) {\\n w(cln), --cls;\\n for (; cls > 6; cls -= 6)\\n w(8304);\\n if (cls > 2)\\n w(((cls - 3) << 5) | 8208), cls = 0;\\n }\\n while (cls--)\\n w(cln);\\n cls = 1;\\n cln = c[i];\\n }\\n }\\n return { c: cl.subarray(0, cli), n: s };\\n};\\n// calculate the length of output from tree, code lengths\\nvar clen = function (cf, cl) {\\n var l = 0;\\n for (var i = 0; i < cl.length; ++i)\\n l += cf[i] * cl[i];\\n return l;\\n};\\n// writes a fixed block\\n// returns the new bit pos\\nvar wfblk = function (out, pos, dat) {\\n // no need to write 00 as type: TypedArray defaults to 0\\n var s = dat.length;\\n var o = shft(pos + 2);\\n out[o] = s & 255;\\n out[o + 1] = s >> 8;\\n out[o + 2] = out[o] ^ 255;\\n out[o + 3] = out[o + 1] ^ 255;\\n for (var i = 0; i < s; ++i)\\n out[o + i + 4] = dat[i];\\n return (o + 4 + s) * 8;\\n};\\n// writes a block\\nvar wblk = function (dat, out, final, syms, lf, df, eb, li, bs, bl, p) {\\n wbits(out, p++, final);\\n ++lf[256];\\n var _a = hTree(lf, 15), dlt = _a.t, mlb = _a.l;\\n var _b = hTree(df, 15), ddt = _b.t, mdb = _b.l;\\n var _c = lc(dlt), lclt = _c.c, nlc = _c.n;\\n var _d = lc(ddt), lcdt = _d.c, ndc = _d.n;\\n var lcfreq = new u16(19);\\n for (var i = 0; i < lclt.length; ++i)\\n ++lcfreq[lclt[i] & 31];\\n for (var i = 0; i < lcdt.length; ++i)\\n ++lcfreq[lcdt[i] & 31];\\n var _e = hTree(lcfreq, 7), lct = _e.t, mlcb = _e.l;\\n var nlcc = 19;\\n for (; nlcc > 4 && !lct[clim[nlcc - 1]]; --nlcc)\\n ;\\n var flen = (bl + 5) << 3;\\n var ftlen = clen(lf, flt) + clen(df, fdt) + eb;\\n var dtlen = clen(lf, dlt) + clen(df, ddt) + eb + 14 + 3 * nlcc + clen(lcfreq, lct) + 2 * lcfreq[16] + 3 * lcfreq[17] + 7 * lcfreq[18];\\n if (bs >= 0 && flen <= ftlen && flen <= dtlen)\\n return wfblk(out, p, dat.subarray(bs, bs + bl));\\n var lm, ll, dm, dl;\\n wbits(out, p, 1 + (dtlen < ftlen)), p += 2;\\n if (dtlen < ftlen) {\\n lm = hMap(dlt, mlb, 0), ll = dlt, dm = hMap(ddt, mdb, 0), dl = ddt;\\n var llm = hMap(lct, mlcb, 0);\\n wbits(out, p, nlc - 257);\\n wbits(out, p + 5, ndc - 1);\\n wbits(out, p + 10, nlcc - 4);\\n p += 14;\\n for (var i = 0; i < nlcc; ++i)\\n wbits(out, p + 3 * i, lct[clim[i]]);\\n p += 3 * nlcc;\\n var lcts = [lclt, lcdt];\\n for (var it = 0; it < 2; ++it) {\\n var clct = lcts[it];\\n for (var i = 0; i < clct.length; ++i) {\\n var len = clct[i] & 31;\\n wbits(out, p, llm[len]), p += lct[len];\\n if (len > 15)\\n wbits(out, p, (clct[i] >> 5) & 127), p += clct[i] >> 12;\\n }\\n }\\n }\\n else {\\n lm = flm, ll = flt, dm = fdm, dl = fdt;\\n }\\n for (var i = 0; i < li; ++i) {\\n var sym = syms[i];\\n if (sym > 255) {\\n var len = (sym >> 18) & 31;\\n wbits16(out, p, lm[len + 257]), p += ll[len + 257];\\n if (len > 7)\\n wbits(out, p, (sym >> 23) & 31), p += fleb[len];\\n var dst = sym & 31;\\n wbits16(out, p, dm[dst]), p += dl[dst];\\n if (dst > 3)\\n wbits16(out, p, (sym >> 5) & 8191), p += fdeb[dst];\\n }\\n else {\\n wbits16(out, p, lm[sym]), p += ll[sym];\\n }\\n }\\n wbits16(out, p, lm[256]);\\n return p + ll[256];\\n};\\n// deflate options (nice << 13) | chain\\nvar deo = /*#__PURE__*/ new i32([65540, 131080, 131088, 131104, 262176, 1048704, 1048832, 2114560, 2117632]);\\n// empty\\nvar et = /*#__PURE__*/ new u8(0);\\n// compresses data into a raw DEFLATE buffer\\nvar dflt = function (dat, lvl, plvl, pre, post, st) {\\n var s = st.z || dat.length;\\n var o = new u8(pre + s + 5 * (1 + Math.ceil(s / 7000)) + post);\\n // writing to this writes to the output buffer\\n var w = o.subarray(pre, o.length - post);\\n var lst = st.l;\\n var pos = (st.r || 0) & 7;\\n if (lvl) {\\n if (pos)\\n w[0] = st.r >> 3;\\n var opt = deo[lvl - 1];\\n var n = opt >> 13, c = opt & 8191;\\n var msk_1 = (1 << plvl) - 1;\\n // prev 2-byte val map curr 2-byte val map\\n var prev = st.p || new u16(32768), head = st.h || new u16(msk_1 + 1);\\n var bs1_1 = Math.ceil(plvl / 3), bs2_1 = 2 * bs1_1;\\n var hsh = function (i) { return (dat[i] ^ (dat[i + 1] << bs1_1) ^ (dat[i + 2] << bs2_1)) & msk_1; };\\n // 24576 is an arbitrary number of maximum symbols per block\\n // 424 buffer for last block\\n var syms = new i32(25000);\\n // length/literal freq distance freq\\n var lf = new u16(288), df = new u16(32);\\n // l/lcnt exbits index l/lind waitdx blkpos\\n var lc_1 = 0, eb = 0, i = st.i || 0, li = 0, wi = st.w || 0, bs = 0;\\n for (; i + 2 < s; ++i) {\\n // hash value\\n var hv = hsh(i);\\n // index mod 32768 previous index mod\\n var imod = i & 32767, pimod = head[hv];\\n prev[imod] = pimod;\\n head[hv] = imod;\\n // We always should modify head and prev, but only add symbols if\\n // this data is not yet processed (\\\"wait\\\" for wait index)\\n if (wi <= i) {\\n // bytes remaining\\n var rem = s - i;\\n if ((lc_1 > 7000 || li > 24576) && (rem > 423 || !lst)) {\\n pos = wblk(dat, w, 0, syms, lf, df, eb, li, bs, i - bs, pos);\\n li = lc_1 = eb = 0, bs = i;\\n for (var j = 0; j < 286; ++j)\\n lf[j] = 0;\\n for (var j = 0; j < 30; ++j)\\n df[j] = 0;\\n }\\n // len dist chain\\n var l = 2, d = 0, ch_1 = c, dif = imod - pimod & 32767;\\n if (rem > 2 && hv == hsh(i - dif)) {\\n var maxn = Math.min(n, rem) - 1;\\n var maxd = Math.min(32767, i);\\n // max possible length\\n // not capped at dif because decompressors implement \\\"rolling\\\" index population\\n var ml = Math.min(258, rem);\\n while (dif <= maxd && --ch_1 && imod != pimod) {\\n if (dat[i + l] == dat[i + l - dif]) {\\n var nl = 0;\\n for (; nl < ml && dat[i + nl] == dat[i + nl - dif]; ++nl)\\n ;\\n if (nl > l) {\\n l = nl, d = dif;\\n // break out early when we reach \\\"nice\\\" (we are satisfied enough)\\n if (nl > maxn)\\n break;\\n // now, find the rarest 2-byte sequence within this\\n // length of literals and search for that instead.\\n // Much faster than just using the start\\n var mmd = Math.min(dif, nl - 2);\\n var md = 0;\\n for (var j = 0; j < mmd; ++j) {\\n var ti = i - dif + j & 32767;\\n var pti = prev[ti];\\n var cd = ti - pti & 32767;\\n if (cd > md)\\n md = cd, pimod = ti;\\n }\\n }\\n }\\n // check the previous match\\n imod = pimod, pimod = prev[imod];\\n dif += imod - pimod & 32767;\\n }\\n }\\n // d will be nonzero only when a match was found\\n if (d) {\\n // store both dist and len data in one int32\\n // Make sure this is recognized as a len/dist with 28th bit (2^28)\\n syms[li++] = 268435456 | (revfl[l] << 18) | revfd[d];\\n var lin = revfl[l] & 31, din = revfd[d] & 31;\\n eb += fleb[lin] + fdeb[din];\\n ++lf[257 + lin];\\n ++df[din];\\n wi = i + l;\\n ++lc_1;\\n }\\n else {\\n syms[li++] = dat[i];\\n ++lf[dat[i]];\\n }\\n }\\n }\\n for (i = Math.max(i, wi); i < s; ++i) {\\n syms[li++] = dat[i];\\n ++lf[dat[i]];\\n }\\n pos = wblk(dat, w, lst, syms, lf, df, eb, li, bs, i - bs, pos);\\n if (!lst) {\\n st.r = (pos & 7) | w[(pos / 8) | 0] << 3;\\n // shft(pos) now 1 less if pos & 7 != 0\\n pos -= 7;\\n st.h = head, st.p = prev, st.i = i, st.w = wi;\\n }\\n }\\n else {\\n for (var i = st.w || 0; i < s + lst; i += 65535) {\\n // end\\n var e = i + 65535;\\n if (e >= s) {\\n // write final block\\n w[(pos / 8) | 0] = lst;\\n e = s;\\n }\\n pos = wfblk(w, pos + 1, dat.subarray(i, e));\\n }\\n st.i = s;\\n }\\n return slc(o, 0, pre + shft(pos) + post);\\n};\\n// CRC32 table\\nvar crct = /*#__PURE__*/ (function () {\\n var t = new Int32Array(256);\\n for (var i = 0; i < 256; ++i) {\\n var c = i, k = 9;\\n while (--k)\\n c = ((c & 1) && -306674912) ^ (c >>> 1);\\n t[i] = c;\\n }\\n return t;\\n})();\\n// CRC32\\nvar crc = function () {\\n var c = -1;\\n return {\\n p: function (d) {\\n // closures have awful performance\\n var cr = c;\\n for (var i = 0; i < d.length; ++i)\\n cr = crct[(cr & 255) ^ d[i]] ^ (cr >>> 8);\\n c = cr;\\n },\\n d: function () { return ~c; }\\n };\\n};\\n// Adler32\\nvar adler = function () {\\n var a = 1, b = 0;\\n return {\\n p: function (d) {\\n // closures have awful performance\\n var n = a, m = b;\\n var l = d.length | 0;\\n for (var i = 0; i != l;) {\\n var e = Math.min(i + 2655, l);\\n for (; i < e; ++i)\\n m += n += d[i];\\n n = (n & 65535) + 15 * (n >> 16), m = (m & 65535) + 15 * (m >> 16);\\n }\\n a = n, b = m;\\n },\\n d: function () {\\n a %= 65521, b %= 65521;\\n return (a & 255) << 24 | (a & 0xFF00) << 8 | (b & 255) << 8 | (b >> 8);\\n }\\n };\\n};\\n;\\n// deflate with opts\\nvar dopt = function (dat, opt, pre, post, st) {\\n if (!st) {\\n st = { l: 1 };\\n if (opt.dictionary) {\\n var dict = opt.dictionary.subarray(-32768);\\n var newDat = new u8(dict.length + dat.length);\\n newDat.set(dict);\\n newDat.set(dat, dict.length);\\n dat = newDat;\\n st.w = dict.length;\\n }\\n }\\n return dflt(dat, opt.level == null ? 6 : opt.level, opt.mem == null ? (st.l ? Math.ceil(Math.max(8, Math.min(13, Math.log(dat.length))) * 1.5) : 20) : (12 + opt.mem), pre, post, st);\\n};\\n// Walmart object spread\\nvar mrg = function (a, b) {\\n var o = {};\\n for (var k in a)\\n o[k] = a[k];\\n for (var k in b)\\n o[k] = b[k];\\n return o;\\n};\\n// worker clone\\n// This is possibly the craziest part of the entire codebase, despite how simple it may seem.\\n// The only parameter to this function is a closure that returns an array of variables outside of the function scope.\\n// We're going to try to figure out the variable names used in the closure as strings because that is crucial for workerization.\\n// We will return an object mapping of true variable name to value (basically, the current scope as a JS object).\\n// The reason we can't just use the original variable names is minifiers mangling the toplevel scope.\\n// This took me three weeks to figure out how to do.\\nvar wcln = function (fn, fnStr, td) {\\n var dt = fn();\\n var st = fn.toString();\\n var ks = st.slice(st.indexOf('[') + 1, st.lastIndexOf(']')).replace(/\\\\s+/g, '').split(',');\\n for (var i = 0; i < dt.length; ++i) {\\n var v = dt[i], k = ks[i];\\n if (typeof v == 'function') {\\n fnStr += ';' + k + '=';\\n var st_1 = v.toString();\\n if (v.prototype) {\\n // for global objects\\n if (st_1.indexOf('[native code]') != -1) {\\n var spInd = st_1.indexOf(' ', 8) + 1;\\n fnStr += st_1.slice(spInd, st_1.indexOf('(', spInd));\\n }\\n else {\\n fnStr += st_1;\\n for (var t in v.prototype)\\n fnStr += ';' + k + '.prototype.' + t + '=' + v.prototype[t].toString();\\n }\\n }\\n else\\n fnStr += st_1;\\n }\\n else\\n td[k] = v;\\n }\\n return fnStr;\\n};\\nvar ch = [];\\n// clone bufs\\nvar cbfs = function (v) {\\n var tl = [];\\n for (var k in v) {\\n if (v[k].buffer) {\\n tl.push((v[k] = new v[k].constructor(v[k])).buffer);\\n }\\n }\\n return tl;\\n};\\n// use a worker to execute code\\nvar wrkr = function (fns, init, id, cb) {\\n if (!ch[id]) {\\n var fnStr = '', td_1 = {}, m = fns.length - 1;\\n for (var i = 0; i < m; ++i)\\n fnStr = wcln(fns[i], fnStr, td_1);\\n ch[id] = { c: wcln(fns[m], fnStr, td_1), e: td_1 };\\n }\\n var td = mrg({}, ch[id].e);\\n return wk(ch[id].c + ';onmessage=function(e){for(var k in e.data)self[k]=e.data[k];onmessage=' + init.toString() + '}', id, td, cbfs(td), cb);\\n};\\n// base async inflate fn\\nvar bInflt = function () { return [u8, u16, i32, fleb, fdeb, clim, fl, fd, flrm, fdrm, rev, ec, hMap, max, bits, bits16, shft, slc, err, inflt, inflateSync, pbf, gopt]; };\\nvar bDflt = function () { return [u8, u16, i32, fleb, fdeb, clim, revfl, revfd, flm, flt, fdm, fdt, rev, deo, et, hMap, wbits, wbits16, hTree, ln, lc, clen, wfblk, wblk, shft, slc, dflt, dopt, deflateSync, pbf]; };\\n// gzip extra\\nvar gze = function () { return [gzh, gzhl, wbytes, crc, crct]; };\\n// gunzip extra\\nvar guze = function () { return [gzs, gzl]; };\\n// zlib extra\\nvar zle = function () { return [zlh, wbytes, adler]; };\\n// unzlib extra\\nvar zule = function () { return [zls]; };\\n// post buf\\nvar pbf = function (msg) { return postMessage(msg, [msg.buffer]); };\\n// get opts\\nvar gopt = function (o) { return o && {\\n out: o.size && new u8(o.size),\\n dictionary: o.dictionary\\n}; };\\n// async helper\\nvar cbify = function (dat, opts, fns, init, id, cb) {\\n var w = wrkr(fns, init, id, function (err, dat) {\\n w.terminate();\\n cb(err, dat);\\n });\\n w.postMessage([dat, opts], opts.consume ? [dat.buffer] : []);\\n return function () { w.terminate(); };\\n};\\n// auto stream\\nvar astrm = function (strm) {\\n strm.ondata = function (dat, final) { return postMessage([dat, final], [dat.buffer]); };\\n return function (ev) {\\n if (ev.data.length) {\\n strm.push(ev.data[0], ev.data[1]);\\n postMessage([ev.data[0].length]);\\n }\\n else\\n strm.flush();\\n };\\n};\\n// async stream attach\\nvar astrmify = function (fns, strm, opts, init, id, flush, ext) {\\n var t;\\n var w = wrkr(fns, init, id, function (err, dat) {\\n if (err)\\n w.terminate(), strm.ondata.call(strm, err);\\n else if (!Array.isArray(dat))\\n ext(dat);\\n else if (dat.length == 1) {\\n strm.queuedSize -= dat[0];\\n if (strm.ondrain)\\n strm.ondrain(dat[0]);\\n }\\n else {\\n if (dat[1])\\n w.terminate();\\n strm.ondata.call(strm, err, dat[0], dat[1]);\\n }\\n });\\n w.postMessage(opts);\\n strm.queuedSize = 0;\\n strm.push = function (d, f) {\\n if (!strm.ondata)\\n err(5);\\n if (t)\\n strm.ondata(err(4, 0, 1), null, !!f);\\n strm.queuedSize += d.length;\\n w.postMessage([d, t = f], [d.buffer]);\\n };\\n strm.terminate = function () { w.terminate(); };\\n if (flush) {\\n strm.flush = function () { w.postMessage([]); };\\n }\\n};\\n// read 2 bytes\\nvar b2 = function (d, b) { return d[b] | (d[b + 1] << 8); };\\n// read 4 bytes\\nvar b4 = function (d, b) { return (d[b] | (d[b + 1] << 8) | (d[b + 2] << 16) | (d[b + 3] << 24)) >>> 0; };\\nvar b8 = function (d, b) { return b4(d, b) + (b4(d, b + 4) * 4294967296); };\\n// write bytes\\nvar wbytes = function (d, b, v) {\\n for (; v; ++b)\\n d[b] = v, v >>>= 8;\\n};\\n// gzip header\\nvar gzh = function (c, o) {\\n var fn = o.filename;\\n c[0] = 31, c[1] = 139, c[2] = 8, c[8] = o.level < 2 ? 4 : o.level == 9 ? 2 : 0, c[9] = 3; // assume Unix\\n if (o.mtime != 0)\\n wbytes(c, 4, Math.floor(new Date(o.mtime || Date.now()) / 1000));\\n if (fn) {\\n c[3] = 8;\\n for (var i = 0; i <= fn.length; ++i)\\n c[i + 10] = fn.charCodeAt(i);\\n }\\n};\\n// gzip footer: -8 to -4 = CRC, -4 to -0 is length\\n// gzip start\\nvar gzs = function (d) {\\n if (d[0] != 31 || d[1] != 139 || d[2] != 8)\\n err(6, 'invalid gzip data');\\n var flg = d[3];\\n var st = 10;\\n if (flg & 4)\\n st += (d[10] | d[11] << 8) + 2;\\n for (var zs = (flg >> 3 & 1) + (flg >> 4 & 1); zs > 0; zs -= !d[st++])\\n ;\\n return st + (flg & 2);\\n};\\n// gzip length\\nvar gzl = function (d) {\\n var l = d.length;\\n return (d[l - 4] | d[l - 3] << 8 | d[l - 2] << 16 | d[l - 1] << 24) >>> 0;\\n};\\n// gzip header length\\nvar gzhl = function (o) { return 10 + (o.filename ? o.filename.length + 1 : 0); };\\n// zlib header\\nvar zlh = function (c, o) {\\n var lv = o.level, fl = lv == 0 ? 0 : lv < 6 ? 1 : lv == 9 ? 3 : 2;\\n c[0] = 120, c[1] = (fl << 6) | (o.dictionary && 32);\\n c[1] |= 31 - ((c[0] << 8) | c[1]) % 31;\\n if (o.dictionary) {\\n var h = adler();\\n h.p(o.dictionary);\\n wbytes(c, 2, h.d());\\n }\\n};\\n// zlib start\\nvar zls = function (d, dict) {\\n if ((d[0] & 15) != 8 || (d[0] >> 4) > 7 || ((d[0] << 8 | d[1]) % 31))\\n err(6, 'invalid zlib data');\\n if ((d[1] >> 5 & 1) == +!dict)\\n err(6, 'invalid zlib data: ' + (d[1] & 32 ? 'need' : 'unexpected') + ' dictionary');\\n return (d[1] >> 3 & 4) + 2;\\n};\\nfunction StrmOpt(opts, cb) {\\n if (typeof opts == 'function')\\n cb = opts, opts = {};\\n this.ondata = cb;\\n return opts;\\n}\\n/**\\n * Streaming DEFLATE compression\\n */\\nvar Deflate = /*#__PURE__*/ (function () {\\n function Deflate(opts, cb) {\\n if (typeof opts == 'function')\\n cb = opts, opts = {};\\n this.ondata = cb;\\n this.o = opts || {};\\n this.s = { l: 0, i: 32768, w: 32768, z: 32768 };\\n // Buffer length must always be 0 mod 32768 for index calculations to be correct when modifying head and prev\\n // 98304 = 32768 (lookback) + 65536 (common chunk size)\\n this.b = new u8(98304);\\n if (this.o.dictionary) {\\n var dict = this.o.dictionary.subarray(-32768);\\n this.b.set(dict, 32768 - dict.length);\\n this.s.i = 32768 - dict.length;\\n }\\n }\\n Deflate.prototype.p = function (c, f) {\\n this.ondata(dopt(c, this.o, 0, 0, this.s), f);\\n };\\n /**\\n * Pushes a chunk to be deflated\\n * @param chunk The chunk to push\\n * @param final Whether this is the last chunk\\n */\\n Deflate.prototype.push = function (chunk, final) {\\n if (!this.ondata)\\n err(5);\\n if (this.s.l)\\n err(4);\\n var endLen = chunk.length + this.s.z;\\n if (endLen > this.b.length) {\\n if (endLen > 2 * this.b.length - 32768) {\\n var newBuf = new u8(endLen & -32768);\\n newBuf.set(this.b.subarray(0, this.s.z));\\n this.b = newBuf;\\n }\\n var split = this.b.length - this.s.z;\\n this.b.set(chunk.subarray(0, split), this.s.z);\\n this.s.z = this.b.length;\\n this.p(this.b, false);\\n this.b.set(this.b.subarray(-32768));\\n this.b.set(chunk.subarray(split), 32768);\\n this.s.z = chunk.length - split + 32768;\\n this.s.i = 32766, this.s.w = 32768;\\n }\\n else {\\n this.b.set(chunk, this.s.z);\\n this.s.z += chunk.length;\\n }\\n this.s.l = final & 1;\\n if (this.s.z > this.s.w + 8191 || final) {\\n this.p(this.b, final || false);\\n this.s.w = this.s.i, this.s.i -= 2;\\n }\\n };\\n /**\\n * Flushes buffered uncompressed data. Useful to immediately retrieve the\\n * deflated output for small inputs.\\n */\\n Deflate.prototype.flush = function () {\\n if (!this.ondata)\\n err(5);\\n if (this.s.l)\\n err(4);\\n this.p(this.b, false);\\n this.s.w = this.s.i, this.s.i -= 2;\\n };\\n return Deflate;\\n}());\\nexport { Deflate };\\n/**\\n * Asynchronous streaming DEFLATE compression\\n */\\nvar AsyncDeflate = /*#__PURE__*/ (function () {\\n function AsyncDeflate(opts, cb) {\\n astrmify([\\n bDflt,\\n function () { return [astrm, Deflate]; }\\n ], this, StrmOpt.call(this, opts, cb), function (ev) {\\n var strm = new Deflate(ev.data);\\n onmessage = astrm(strm);\\n }, 6, 1);\\n }\\n return AsyncDeflate;\\n}());\\nexport { AsyncDeflate };\\nexport function deflate(data, opts, cb) {\\n if (!cb)\\n cb = opts, opts = {};\\n if (typeof cb != 'function')\\n err(7);\\n return cbify(data, opts, [\\n bDflt,\\n ], function (ev) { return pbf(deflateSync(ev.data[0], ev.data[1])); }, 0, cb);\\n}\\n/**\\n * Compresses data with DEFLATE without any wrapper\\n * @param data The data to compress\\n * @param opts The compression options\\n * @returns The deflated version of the data\\n */\\nexport function deflateSync(data, opts) {\\n return dopt(data, opts || {}, 0, 0);\\n}\\n/**\\n * Streaming DEFLATE decompression\\n */\\nvar Inflate = /*#__PURE__*/ (function () {\\n function Inflate(opts, cb) {\\n // no StrmOpt here to avoid adding to workerizer\\n if (typeof opts == 'function')\\n cb = opts, opts = {};\\n this.ondata = cb;\\n var dict = opts && opts.dictionary && opts.dictionary.subarray(-32768);\\n this.s = { i: 0, b: dict ? dict.length : 0 };\\n this.o = new u8(32768);\\n this.p = new u8(0);\\n if (dict)\\n this.o.set(dict);\\n }\\n Inflate.prototype.e = function (c) {\\n if (!this.ondata)\\n err(5);\\n if (this.d)\\n err(4);\\n if (!this.p.length)\\n this.p = c;\\n else if (c.length) {\\n var n = new u8(this.p.length + c.length);\\n n.set(this.p), n.set(c, this.p.length), this.p = n;\\n }\\n };\\n Inflate.prototype.c = function (final) {\\n this.s.i = +(this.d = final || false);\\n var bts = this.s.b;\\n var dt = inflt(this.p, this.s, this.o);\\n this.ondata(slc(dt, bts, this.s.b), this.d);\\n this.o = slc(dt, this.s.b - 32768), this.s.b = this.o.length;\\n this.p = slc(this.p, (this.s.p / 8) | 0), this.s.p &= 7;\\n };\\n /**\\n * Pushes a chunk to be inflated\\n * @param chunk The chunk to push\\n * @param final Whether this is the final chunk\\n */\\n Inflate.prototype.push = function (chunk, final) {\\n this.e(chunk), this.c(final);\\n };\\n return Inflate;\\n}());\\nexport { Inflate };\\n/**\\n * Asynchronous streaming DEFLATE decompression\\n */\\nvar AsyncInflate = /*#__PURE__*/ (function () {\\n function AsyncInflate(opts, cb) {\\n astrmify([\\n bInflt,\\n function () { return [astrm, Inflate]; }\\n ], this, StrmOpt.call(this, opts, cb), function (ev) {\\n var strm = new Inflate(ev.data);\\n onmessage = astrm(strm);\\n }, 7, 0);\\n }\\n return AsyncInflate;\\n}());\\nexport { AsyncInflate };\\nexport function inflate(data, opts, cb) {\\n if (!cb)\\n cb = opts, opts = {};\\n if (typeof cb != 'function')\\n err(7);\\n return cbify(data, opts, [\\n bInflt\\n ], function (ev) { return pbf(inflateSync(ev.data[0], gopt(ev.data[1]))); }, 1, cb);\\n}\\n/**\\n * Expands DEFLATE data with no wrapper\\n * @param data The data to decompress\\n * @param opts The decompression options\\n * @returns The decompressed version of the data\\n */\\nexport function inflateSync(data, opts) {\\n return inflt(data, { i: 2 }, opts && opts.out, opts && opts.dictionary);\\n}\\n// before you yell at me for not just using extends, my reason is that TS inheritance is hard to workerize.\\n/**\\n * Streaming GZIP compression\\n */\\nvar Gzip = /*#__PURE__*/ (function () {\\n function Gzip(opts, cb) {\\n this.c = crc();\\n this.l = 0;\\n this.v = 1;\\n Deflate.call(this, opts, cb);\\n }\\n /**\\n * Pushes a chunk to be GZIPped\\n * @param chunk The chunk to push\\n * @param final Whether this is the last chunk\\n */\\n Gzip.prototype.push = function (chunk, final) {\\n this.c.p(chunk);\\n this.l += chunk.length;\\n Deflate.prototype.push.call(this, chunk, final);\\n };\\n Gzip.prototype.p = function (c, f) {\\n var raw = dopt(c, this.o, this.v && gzhl(this.o), f && 8, this.s);\\n if (this.v)\\n gzh(raw, this.o), this.v = 0;\\n if (f)\\n wbytes(raw, raw.length - 8, this.c.d()), wbytes(raw, raw.length - 4, this.l);\\n this.ondata(raw, f);\\n };\\n /**\\n * Flushes buffered uncompressed data. Useful to immediately retrieve the\\n * GZIPped output for small inputs.\\n */\\n Gzip.prototype.flush = function () {\\n Deflate.prototype.flush.call(this);\\n };\\n return Gzip;\\n}());\\nexport { Gzip };\\n/**\\n * Asynchronous streaming GZIP compression\\n */\\nvar AsyncGzip = /*#__PURE__*/ (function () {\\n function AsyncGzip(opts, cb) {\\n astrmify([\\n bDflt,\\n gze,\\n function () { return [astrm, Deflate, Gzip]; }\\n ], this, StrmOpt.call(this, opts, cb), function (ev) {\\n var strm = new Gzip(ev.data);\\n onmessage = astrm(strm);\\n }, 8, 1);\\n }\\n return AsyncGzip;\\n}());\\nexport { AsyncGzip };\\nexport function gzip(data, opts, cb) {\\n if (!cb)\\n cb = opts, opts = {};\\n if (typeof cb != 'function')\\n err(7);\\n return cbify(data, opts, [\\n bDflt,\\n gze,\\n function () { return [gzipSync]; }\\n ], function (ev) { return pbf(gzipSync(ev.data[0], ev.data[1])); }, 2, cb);\\n}\\n/**\\n * Compresses data with GZIP\\n * @param data The data to compress\\n * @param opts The compression options\\n * @returns The gzipped version of the data\\n */\\nexport function gzipSync(data, opts) {\\n if (!opts)\\n opts = {};\\n var c = crc(), l = data.length;\\n c.p(data);\\n var d = dopt(data, opts, gzhl(opts), 8), s = d.length;\\n return gzh(d, opts), wbytes(d, s - 8, c.d()), wbytes(d, s - 4, l), d;\\n}\\n/**\\n * Streaming single or multi-member GZIP decompression\\n */\\nvar Gunzip = /*#__PURE__*/ (function () {\\n function Gunzip(opts, cb) {\\n this.v = 1;\\n this.r = 0;\\n Inflate.call(this, opts, cb);\\n }\\n /**\\n * Pushes a chunk to be GUNZIPped\\n * @param chunk The chunk to push\\n * @param final Whether this is the last chunk\\n */\\n Gunzip.prototype.push = function (chunk, final) {\\n Inflate.prototype.e.call(this, chunk);\\n this.r += chunk.length;\\n if (this.v) {\\n var p = this.p.subarray(this.v - 1);\\n var s = p.length > 3 ? gzs(p) : 4;\\n if (s > p.length) {\\n if (!final)\\n return;\\n }\\n else if (this.v > 1 && this.onmember) {\\n this.onmember(this.r - p.length);\\n }\\n this.p = p.subarray(s), this.v = 0;\\n }\\n // necessary to prevent TS from using the closure value\\n // This allows for workerization to function correctly\\n Inflate.prototype.c.call(this, final);\\n // process concatenated GZIP\\n if (this.s.f && !this.s.l && !final) {\\n this.v = shft(this.s.p) + 9;\\n this.s = { i: 0 };\\n this.o = new u8(0);\\n this.push(new u8(0), final);\\n }\\n };\\n return Gunzip;\\n}());\\nexport { Gunzip };\\n/**\\n * Asynchronous streaming single or multi-member GZIP decompression\\n */\\nvar AsyncGunzip = /*#__PURE__*/ (function () {\\n function AsyncGunzip(opts, cb) {\\n var _this = this;\\n astrmify([\\n bInflt,\\n guze,\\n function () { return [astrm, Inflate, Gunzip]; }\\n ], this, StrmOpt.call(this, opts, cb), function (ev) {\\n var strm = new Gunzip(ev.data);\\n strm.onmember = function (offset) { return postMessage(offset); };\\n onmessage = astrm(strm);\\n }, 9, 0, function (offset) { return _this.onmember && _this.onmember(offset); });\\n }\\n return AsyncGunzip;\\n}());\\nexport { AsyncGunzip };\\nexport function gunzip(data, opts, cb) {\\n if (!cb)\\n cb = opts, opts = {};\\n if (typeof cb != 'function')\\n err(7);\\n return cbify(data, opts, [\\n bInflt,\\n guze,\\n function () { return [gunzipSync]; }\\n ], function (ev) { return pbf(gunzipSync(ev.data[0], ev.data[1])); }, 3, cb);\\n}\\n/**\\n * Expands GZIP data\\n * @param data The data to decompress\\n * @param opts The decompression options\\n * @returns The decompressed version of the data\\n */\\nexport function gunzipSync(data, opts) {\\n var st = gzs(data);\\n if (st + 8 > data.length)\\n err(6, 'invalid gzip data');\\n return inflt(data.subarray(st, -8), { i: 2 }, opts && opts.out || new u8(gzl(data)), opts && opts.dictionary);\\n}\\n/**\\n * Streaming Zlib compression\\n */\\nvar Zlib = /*#__PURE__*/ (function () {\\n function Zlib(opts, cb) {\\n this.c = adler();\\n this.v = 1;\\n Deflate.call(this, opts, cb);\\n }\\n /**\\n * Pushes a chunk to be zlibbed\\n * @param chunk The chunk to push\\n * @param final Whether this is the last chunk\\n */\\n Zlib.prototype.push = function (chunk, final) {\\n this.c.p(chunk);\\n Deflate.prototype.push.call(this, chunk, final);\\n };\\n Zlib.prototype.p = function (c, f) {\\n var raw = dopt(c, this.o, this.v && (this.o.dictionary ? 6 : 2), f && 4, this.s);\\n if (this.v)\\n zlh(raw, this.o), this.v = 0;\\n if (f)\\n wbytes(raw, raw.length - 4, this.c.d());\\n this.ondata(raw, f);\\n };\\n /**\\n * Flushes buffered uncompressed data. Useful to immediately retrieve the\\n * zlibbed output for small inputs.\\n */\\n Zlib.prototype.flush = function () {\\n Deflate.prototype.flush.call(this);\\n };\\n return Zlib;\\n}());\\nexport { Zlib };\\n/**\\n * Asynchronous streaming Zlib compression\\n */\\nvar AsyncZlib = /*#__PURE__*/ (function () {\\n function AsyncZlib(opts, cb) {\\n astrmify([\\n bDflt,\\n zle,\\n function () { return [astrm, Deflate, Zlib]; }\\n ], this, StrmOpt.call(this, opts, cb), function (ev) {\\n var strm = new Zlib(ev.data);\\n onmessage = astrm(strm);\\n }, 10, 1);\\n }\\n return AsyncZlib;\\n}());\\nexport { AsyncZlib };\\nexport function zlib(data, opts, cb) {\\n if (!cb)\\n cb = opts, opts = {};\\n if (typeof cb != 'function')\\n err(7);\\n return cbify(data, opts, [\\n bDflt,\\n zle,\\n function () { return [zlibSync]; }\\n ], function (ev) { return pbf(zlibSync(ev.data[0], ev.data[1])); }, 4, cb);\\n}\\n/**\\n * Compress data with Zlib\\n * @param data The data to compress\\n * @param opts The compression options\\n * @returns The zlib-compressed version of the data\\n */\\nexport function zlibSync(data, opts) {\\n if (!opts)\\n opts = {};\\n var a = adler();\\n a.p(data);\\n var d = dopt(data, opts, opts.dictionary ? 6 : 2, 4);\\n return zlh(d, opts), wbytes(d, d.length - 4, a.d()), d;\\n}\\n/**\\n * Streaming Zlib decompression\\n */\\nvar Unzlib = /*#__PURE__*/ (function () {\\n function Unzlib(opts, cb) {\\n Inflate.call(this, opts, cb);\\n this.v = opts && opts.dictionary ? 2 : 1;\\n }\\n /**\\n * Pushes a chunk to be unzlibbed\\n * @param chunk The chunk to push\\n * @param final Whether this is the last chunk\\n */\\n Unzlib.prototype.push = function (chunk, final) {\\n Inflate.prototype.e.call(this, chunk);\\n if (this.v) {\\n if (this.p.length < 6 && !final)\\n return;\\n this.p = this.p.subarray(zls(this.p, this.v - 1)), this.v = 0;\\n }\\n if (final) {\\n if (this.p.length < 4)\\n err(6, 'invalid zlib data');\\n this.p = this.p.subarray(0, -4);\\n }\\n // necessary to prevent TS from using the closure value\\n // This allows for workerization to function correctly\\n Inflate.prototype.c.call(this, final);\\n };\\n return Unzlib;\\n}());\\nexport { Unzlib };\\n/**\\n * Asynchronous streaming Zlib decompression\\n */\\nvar AsyncUnzlib = /*#__PURE__*/ (function () {\\n function AsyncUnzlib(opts, cb) {\\n astrmify([\\n bInflt,\\n zule,\\n function () { return [astrm, Inflate, Unzlib]; }\\n ], this, StrmOpt.call(this, opts, cb), function (ev) {\\n var strm = new Unzlib(ev.data);\\n onmessage = astrm(strm);\\n }, 11, 0);\\n }\\n return AsyncUnzlib;\\n}());\\nexport { AsyncUnzlib };\\nexport function unzlib(data, opts, cb) {\\n if (!cb)\\n cb = opts, opts = {};\\n if (typeof cb != 'function')\\n err(7);\\n return cbify(data, opts, [\\n bInflt,\\n zule,\\n function () { return [unzlibSync]; }\\n ], function (ev) { return pbf(unzlibSync(ev.data[0], gopt(ev.data[1]))); }, 5, cb);\\n}\\n/**\\n * Expands Zlib data\\n * @param data The data to decompress\\n * @param opts The decompression options\\n * @returns The decompressed version of the data\\n */\\nexport function unzlibSync(data, opts) {\\n return inflt(data.subarray(zls(data, opts && opts.dictionary), -4), { i: 2 }, opts && opts.out, opts && opts.dictionary);\\n}\\n// Default algorithm for compression (used because having a known output size allows faster decompression)\\nexport { gzip as compress, AsyncGzip as AsyncCompress };\\nexport { gzipSync as compressSync, Gzip as Compress };\\n/**\\n * Streaming GZIP, Zlib, or raw DEFLATE decompression\\n */\\nvar Decompress = /*#__PURE__*/ (function () {\\n function Decompress(opts, cb) {\\n this.o = StrmOpt.call(this, opts, cb) || {};\\n this.G = Gunzip;\\n this.I = Inflate;\\n this.Z = Unzlib;\\n }\\n // init substream\\n // overriden by AsyncDecompress\\n Decompress.prototype.i = function () {\\n var _this = this;\\n this.s.ondata = function (dat, final) {\\n _this.ondata(dat, final);\\n };\\n };\\n /**\\n * Pushes a chunk to be decompressed\\n * @param chunk The chunk to push\\n * @param final Whether this is the last chunk\\n */\\n Decompress.prototype.push = function (chunk, final) {\\n if (!this.ondata)\\n err(5);\\n if (!this.s) {\\n if (this.p && this.p.length) {\\n var n = new u8(this.p.length + chunk.length);\\n n.set(this.p), n.set(chunk, this.p.length);\\n }\\n else\\n this.p = chunk;\\n if (this.p.length > 2) {\\n this.s = (this.p[0] == 31 && this.p[1] == 139 && this.p[2] == 8)\\n ? new this.G(this.o)\\n : ((this.p[0] & 15) != 8 || (this.p[0] >> 4) > 7 || ((this.p[0] << 8 | this.p[1]) % 31))\\n ? new this.I(this.o)\\n : new this.Z(this.o);\\n this.i();\\n this.s.push(this.p, final);\\n this.p = null;\\n }\\n }\\n else\\n this.s.push(chunk, final);\\n };\\n return Decompress;\\n}());\\nexport { Decompress };\\n/**\\n * Asynchronous streaming GZIP, Zlib, or raw DEFLATE decompression\\n */\\nvar AsyncDecompress = /*#__PURE__*/ (function () {\\n function AsyncDecompress(opts, cb) {\\n Decompress.call(this, opts, cb);\\n this.queuedSize = 0;\\n this.G = AsyncGunzip;\\n this.I = AsyncInflate;\\n this.Z = AsyncUnzlib;\\n }\\n AsyncDecompress.prototype.i = function () {\\n var _this = this;\\n this.s.ondata = function (err, dat, final) {\\n _this.ondata(err, dat, final);\\n };\\n this.s.ondrain = function (size) {\\n _this.queuedSize -= size;\\n if (_this.ondrain)\\n _this.ondrain(size);\\n };\\n };\\n /**\\n * Pushes a chunk to be decompressed\\n * @param chunk The chunk to push\\n * @param final Whether this is the last chunk\\n */\\n AsyncDecompress.prototype.push = function (chunk, final) {\\n this.queuedSize += chunk.length;\\n Decompress.prototype.push.call(this, chunk, final);\\n };\\n return AsyncDecompress;\\n}());\\nexport { AsyncDecompress };\\nexport function decompress(data, opts, cb) {\\n if (!cb)\\n cb = opts, opts = {};\\n if (typeof cb != 'function')\\n err(7);\\n return (data[0] == 31 && data[1] == 139 && data[2] == 8)\\n ? gunzip(data, opts, cb)\\n : ((data[0] & 15) != 8 || (data[0] >> 4) > 7 || ((data[0] << 8 | data[1]) % 31))\\n ? inflate(data, opts, cb)\\n : unzlib(data, opts, cb);\\n}\\n/**\\n * Expands compressed GZIP, Zlib, or raw DEFLATE data, automatically detecting the format\\n * @param data The data to decompress\\n * @param opts The decompression options\\n * @returns The decompressed version of the data\\n */\\nexport function decompressSync(data, opts) {\\n return (data[0] == 31 && data[1] == 139 && data[2] == 8)\\n ? gunzipSync(data, opts)\\n : ((data[0] & 15) != 8 || (data[0] >> 4) > 7 || ((data[0] << 8 | data[1]) % 31))\\n ? inflateSync(data, opts)\\n : unzlibSync(data, opts);\\n}\\n// flatten a directory structure\\nvar fltn = function (d, p, t, o) {\\n for (var k in d) {\\n var val = d[k], n = p + k, op = o;\\n if (Array.isArray(val))\\n op = mrg(o, val[1]), val = val[0];\\n if (val instanceof u8)\\n t[n] = [val, op];\\n else {\\n t[n += '/'] = [new u8(0), op];\\n fltn(val, n, t, o);\\n }\\n }\\n};\\n// text encoder\\nvar te = typeof TextEncoder != 'undefined' && /*#__PURE__*/ new TextEncoder();\\n// text decoder\\nvar td = typeof TextDecoder != 'undefined' && /*#__PURE__*/ new TextDecoder();\\n// text decoder stream\\nvar tds = 0;\\ntry {\\n td.decode(et, { stream: true });\\n tds = 1;\\n}\\ncatch (e) { }\\n// decode UTF8\\nvar dutf8 = function (d) {\\n for (var r = '', i = 0;;) {\\n var c = d[i++];\\n var eb = (c > 127) + (c > 223) + (c > 239);\\n if (i + eb > d.length)\\n return { s: r, r: slc(d, i - 1) };\\n if (!eb)\\n r += String.fromCharCode(c);\\n else if (eb == 3) {\\n c = ((c & 15) << 18 | (d[i++] & 63) << 12 | (d[i++] & 63) << 6 | (d[i++] & 63)) - 65536,\\n r += String.fromCharCode(55296 | (c >> 10), 56320 | (c & 1023));\\n }\\n else if (eb & 1)\\n r += String.fromCharCode((c & 31) << 6 | (d[i++] & 63));\\n else\\n r += String.fromCharCode((c & 15) << 12 | (d[i++] & 63) << 6 | (d[i++] & 63));\\n }\\n};\\n/**\\n * Streaming UTF-8 decoding\\n */\\nvar DecodeUTF8 = /*#__PURE__*/ (function () {\\n /**\\n * Creates a UTF-8 decoding stream\\n * @param cb The callback to call whenever data is decoded\\n */\\n function DecodeUTF8(cb) {\\n this.ondata = cb;\\n if (tds)\\n this.t = new TextDecoder();\\n else\\n this.p = et;\\n }\\n /**\\n * Pushes a chunk to be decoded from UTF-8 binary\\n * @param chunk The chunk to push\\n * @param final Whether this is the last chunk\\n */\\n DecodeUTF8.prototype.push = function (chunk, final) {\\n if (!this.ondata)\\n err(5);\\n final = !!final;\\n if (this.t) {\\n this.ondata(this.t.decode(chunk, { stream: true }), final);\\n if (final) {\\n if (this.t.decode().length)\\n err(8);\\n this.t = null;\\n }\\n return;\\n }\\n if (!this.p)\\n err(4);\\n var dat = new u8(this.p.length + chunk.length);\\n dat.set(this.p);\\n dat.set(chunk, this.p.length);\\n var _a = dutf8(dat), s = _a.s, r = _a.r;\\n if (final) {\\n if (r.length)\\n err(8);\\n this.p = null;\\n }\\n else\\n this.p = r;\\n this.ondata(s, final);\\n };\\n return DecodeUTF8;\\n}());\\nexport { DecodeUTF8 };\\n/**\\n * Streaming UTF-8 encoding\\n */\\nvar EncodeUTF8 = /*#__PURE__*/ (function () {\\n /**\\n * Creates a UTF-8 decoding stream\\n * @param cb The callback to call whenever data is encoded\\n */\\n function EncodeUTF8(cb) {\\n this.ondata = cb;\\n }\\n /**\\n * Pushes a chunk to be encoded to UTF-8\\n * @param chunk The string data to push\\n * @param final Whether this is the last chunk\\n */\\n EncodeUTF8.prototype.push = function (chunk, final) {\\n if (!this.ondata)\\n err(5);\\n if (this.d)\\n err(4);\\n this.ondata(strToU8(chunk), this.d = final || false);\\n };\\n return EncodeUTF8;\\n}());\\nexport { EncodeUTF8 };\\n/**\\n * Converts a string into a Uint8Array for use with compression/decompression methods\\n * @param str The string to encode\\n * @param latin1 Whether or not to interpret the data as Latin-1. This should\\n * not need to be true unless decoding a binary string.\\n * @returns The string encoded in UTF-8/Latin-1 binary\\n */\\nexport function strToU8(str, latin1) {\\n if (latin1) {\\n var ar_1 = new u8(str.length);\\n for (var i = 0; i < str.length; ++i)\\n ar_1[i] = str.charCodeAt(i);\\n return ar_1;\\n }\\n if (te)\\n return te.encode(str);\\n var l = str.length;\\n var ar = new u8(str.length + (str.length >> 1));\\n var ai = 0;\\n var w = function (v) { ar[ai++] = v; };\\n for (var i = 0; i < l; ++i) {\\n if (ai + 5 > ar.length) {\\n var n = new u8(ai + 8 + ((l - i) << 1));\\n n.set(ar);\\n ar = n;\\n }\\n var c = str.charCodeAt(i);\\n if (c < 128 || latin1)\\n w(c);\\n else if (c < 2048)\\n w(192 | (c >> 6)), w(128 | (c & 63));\\n else if (c > 55295 && c < 57344)\\n c = 65536 + (c & 1023 << 10) | (str.charCodeAt(++i) & 1023),\\n w(240 | (c >> 18)), w(128 | ((c >> 12) & 63)), w(128 | ((c >> 6) & 63)), w(128 | (c & 63));\\n else\\n w(224 | (c >> 12)), w(128 | ((c >> 6) & 63)), w(128 | (c & 63));\\n }\\n return slc(ar, 0, ai);\\n}\\n/**\\n * Converts a Uint8Array to a string\\n * @param dat The data to decode to string\\n * @param latin1 Whether or not to interpret the data as Latin-1. This should\\n * not need to be true unless encoding to binary string.\\n * @returns The original UTF-8/Latin-1 string\\n */\\nexport function strFromU8(dat, latin1) {\\n if (latin1) {\\n var r = '';\\n for (var i = 0; i < dat.length; i += 16384)\\n r += String.fromCharCode.apply(null, dat.subarray(i, i + 16384));\\n return r;\\n }\\n else if (td) {\\n return td.decode(dat);\\n }\\n else {\\n var _a = dutf8(dat), s = _a.s, r = _a.r;\\n if (r.length)\\n err(8);\\n return s;\\n }\\n}\\n;\\n// deflate bit flag\\nvar dbf = function (l) { return l == 1 ? 3 : l < 6 ? 2 : l == 9 ? 1 : 0; };\\n// skip local zip header\\nvar slzh = function (d, b) { return b + 30 + b2(d, b + 26) + b2(d, b + 28); };\\n// read zip header\\nvar zh = function (d, b, z) {\\n var fnl = b2(d, b + 28), fn = strFromU8(d.subarray(b + 46, b + 46 + fnl), !(b2(d, b + 8) & 2048)), es = b + 46 + fnl, bs = b4(d, b + 20);\\n var _a = z && bs == 4294967295 ? z64e(d, es) : [bs, b4(d, b + 24), b4(d, b + 42)], sc = _a[0], su = _a[1], off = _a[2];\\n return [b2(d, b + 10), sc, su, fn, es + b2(d, b + 30) + b2(d, b + 32), off];\\n};\\n// read zip64 extra field\\nvar z64e = function (d, b) {\\n for (; b2(d, b) != 1; b += 4 + b2(d, b + 2))\\n ;\\n return [b8(d, b + 12), b8(d, b + 4), b8(d, b + 20)];\\n};\\n// extra field length\\nvar exfl = function (ex) {\\n var le = 0;\\n if (ex) {\\n for (var k in ex) {\\n var l = ex[k].length;\\n if (l > 65535)\\n err(9);\\n le += l + 4;\\n }\\n }\\n return le;\\n};\\n// write zip header\\nvar wzh = function (d, b, f, fn, u, c, ce, co) {\\n var fl = fn.length, ex = f.extra, col = co && co.length;\\n var exl = exfl(ex);\\n wbytes(d, b, ce != null ? 0x2014B50 : 0x4034B50), b += 4;\\n if (ce != null)\\n d[b++] = 20, d[b++] = f.os;\\n d[b] = 20, b += 2; // spec compliance? what's that?\\n d[b++] = (f.flag << 1) | (c < 0 && 8), d[b++] = u && 8;\\n d[b++] = f.compression & 255, d[b++] = f.compression >> 8;\\n var dt = new Date(f.mtime == null ? Date.now() : f.mtime), y = dt.getFullYear() - 1980;\\n if (y < 0 || y > 119)\\n err(10);\\n wbytes(d, b, (y << 25) | ((dt.getMonth() + 1) << 21) | (dt.getDate() << 16) | (dt.getHours() << 11) | (dt.getMinutes() << 5) | (dt.getSeconds() >> 1)), b += 4;\\n if (c != -1) {\\n wbytes(d, b, f.crc);\\n wbytes(d, b + 4, c < 0 ? -c - 2 : c);\\n wbytes(d, b + 8, f.size);\\n }\\n wbytes(d, b + 12, fl);\\n wbytes(d, b + 14, exl), b += 16;\\n if (ce != null) {\\n wbytes(d, b, col);\\n wbytes(d, b + 6, f.attrs);\\n wbytes(d, b + 10, ce), b += 14;\\n }\\n d.set(fn, b);\\n b += fl;\\n if (exl) {\\n for (var k in ex) {\\n var exf = ex[k], l = exf.length;\\n wbytes(d, b, +k);\\n wbytes(d, b + 2, l);\\n d.set(exf, b + 4), b += 4 + l;\\n }\\n }\\n if (col)\\n d.set(co, b), b += col;\\n return b;\\n};\\n// write zip footer (end of central directory)\\nvar wzf = function (o, b, c, d, e) {\\n wbytes(o, b, 0x6054B50); // skip disk\\n wbytes(o, b + 8, c);\\n wbytes(o, b + 10, c);\\n wbytes(o, b + 12, d);\\n wbytes(o, b + 16, e);\\n};\\n/**\\n * A pass-through stream to keep data uncompressed in a ZIP archive.\\n */\\nvar ZipPassThrough = /*#__PURE__*/ (function () {\\n /**\\n * Creates a pass-through stream that can be added to ZIP archives\\n * @param filename The filename to associate with this data stream\\n */\\n function ZipPassThrough(filename) {\\n this.filename = filename;\\n this.c = crc();\\n this.size = 0;\\n this.compression = 0;\\n }\\n /**\\n * Processes a chunk and pushes to the output stream. You can override this\\n * method in a subclass for custom behavior, but by default this passes\\n * the data through. You must call this.ondata(err, chunk, final) at some\\n * point in this method.\\n * @param chunk The chunk to process\\n * @param final Whether this is the last chunk\\n */\\n ZipPassThrough.prototype.process = function (chunk, final) {\\n this.ondata(null, chunk, final);\\n };\\n /**\\n * Pushes a chunk to be added. If you are subclassing this with a custom\\n * compression algorithm, note that you must push data from the source\\n * file only, pre-compression.\\n * @param chunk The chunk to push\\n * @param final Whether this is the last chunk\\n */\\n ZipPassThrough.prototype.push = function (chunk, final) {\\n if (!this.ondata)\\n err(5);\\n this.c.p(chunk);\\n this.size += chunk.length;\\n if (final)\\n this.crc = this.c.d();\\n this.process(chunk, final || false);\\n };\\n return ZipPassThrough;\\n}());\\nexport { ZipPassThrough };\\n// I don't extend because TypeScript extension adds 1kB of runtime bloat\\n/**\\n * Streaming DEFLATE compression for ZIP archives. Prefer using AsyncZipDeflate\\n * for better performance\\n */\\nvar ZipDeflate = /*#__PURE__*/ (function () {\\n /**\\n * Creates a DEFLATE stream that can be added to ZIP archives\\n * @param filename The filename to associate with this data stream\\n * @param opts The compression options\\n */\\n function ZipDeflate(filename, opts) {\\n var _this = this;\\n if (!opts)\\n opts = {};\\n ZipPassThrough.call(this, filename);\\n this.d = new Deflate(opts, function (dat, final) {\\n _this.ondata(null, dat, final);\\n });\\n this.compression = 8;\\n this.flag = dbf(opts.level);\\n }\\n ZipDeflate.prototype.process = function (chunk, final) {\\n try {\\n this.d.push(chunk, final);\\n }\\n catch (e) {\\n this.ondata(e, null, final);\\n }\\n };\\n /**\\n * Pushes a chunk to be deflated\\n * @param chunk The chunk to push\\n * @param final Whether this is the last chunk\\n */\\n ZipDeflate.prototype.push = function (chunk, final) {\\n ZipPassThrough.prototype.push.call(this, chunk, final);\\n };\\n return ZipDeflate;\\n}());\\nexport { ZipDeflate };\\n/**\\n * Asynchronous streaming DEFLATE compression for ZIP archives\\n */\\nvar AsyncZipDeflate = /*#__PURE__*/ (function () {\\n /**\\n * Creates an asynchronous DEFLATE stream that can be added to ZIP archives\\n * @param filename The filename to associate with this data stream\\n * @param opts The compression options\\n */\\n function AsyncZipDeflate(filename, opts) {\\n var _this = this;\\n if (!opts)\\n opts = {};\\n ZipPassThrough.call(this, filename);\\n this.d = new AsyncDeflate(opts, function (err, dat, final) {\\n _this.ondata(err, dat, final);\\n });\\n this.compression = 8;\\n this.flag = dbf(opts.level);\\n this.terminate = this.d.terminate;\\n }\\n AsyncZipDeflate.prototype.process = function (chunk, final) {\\n this.d.push(chunk, final);\\n };\\n /**\\n * Pushes a chunk to be deflated\\n * @param chunk The chunk to push\\n * @param final Whether this is the last chunk\\n */\\n AsyncZipDeflate.prototype.push = function (chunk, final) {\\n ZipPassThrough.prototype.push.call(this, chunk, final);\\n };\\n return AsyncZipDeflate;\\n}());\\nexport { AsyncZipDeflate };\\n// TODO: Better tree shaking\\n/**\\n * A zippable archive to which files can incrementally be added\\n */\\nvar Zip = /*#__PURE__*/ (function () {\\n /**\\n * Creates an empty ZIP archive to which files can be added\\n * @param cb The callback to call whenever data for the generated ZIP archive\\n * is available\\n */\\n function Zip(cb) {\\n this.ondata = cb;\\n this.u = [];\\n this.d = 1;\\n }\\n /**\\n * Adds a file to the ZIP archive\\n * @param file The file stream to add\\n */\\n Zip.prototype.add = function (file) {\\n var _this = this;\\n if (!this.ondata)\\n err(5);\\n // finishing or finished\\n if (this.d & 2)\\n this.ondata(err(4 + (this.d & 1) * 8, 0, 1), null, false);\\n else {\\n var f = strToU8(file.filename), fl_1 = f.length;\\n var com = file.comment, o = com && strToU8(com);\\n var u = fl_1 != file.filename.length || (o && (com.length != o.length));\\n var hl_1 = fl_1 + exfl(file.extra) + 30;\\n if (fl_1 > 65535)\\n this.ondata(err(11, 0, 1), null, false);\\n var header = new u8(hl_1);\\n wzh(header, 0, file, f, u, -1);\\n var chks_1 = [header];\\n var pAll_1 = function () {\\n for (var _i = 0, chks_2 = chks_1; _i < chks_2.length; _i++) {\\n var chk = chks_2[_i];\\n _this.ondata(null, chk, false);\\n }\\n chks_1 = [];\\n };\\n var tr_1 = this.d;\\n this.d = 0;\\n var ind_1 = this.u.length;\\n var uf_1 = mrg(file, {\\n f: f,\\n u: u,\\n o: o,\\n t: function () {\\n if (file.terminate)\\n file.terminate();\\n },\\n r: function () {\\n pAll_1();\\n if (tr_1) {\\n var nxt = _this.u[ind_1 + 1];\\n if (nxt)\\n nxt.r();\\n else\\n _this.d = 1;\\n }\\n tr_1 = 1;\\n }\\n });\\n var cl_1 = 0;\\n file.ondata = function (err, dat, final) {\\n if (err) {\\n _this.ondata(err, dat, final);\\n _this.terminate();\\n }\\n else {\\n cl_1 += dat.length;\\n chks_1.push(dat);\\n if (final) {\\n var dd = new u8(16);\\n wbytes(dd, 0, 0x8074B50);\\n wbytes(dd, 4, file.crc);\\n wbytes(dd, 8, cl_1);\\n wbytes(dd, 12, file.size);\\n chks_1.push(dd);\\n uf_1.c = cl_1, uf_1.b = hl_1 + cl_1 + 16, uf_1.crc = file.crc, uf_1.size = file.size;\\n if (tr_1)\\n uf_1.r();\\n tr_1 = 1;\\n }\\n else if (tr_1)\\n pAll_1();\\n }\\n };\\n this.u.push(uf_1);\\n }\\n };\\n /**\\n * Ends the process of adding files and prepares to emit the final chunks.\\n * This *must* be called after adding all desired files for the resulting\\n * ZIP file to work properly.\\n */\\n Zip.prototype.end = function () {\\n var _this = this;\\n if (this.d & 2) {\\n this.ondata(err(4 + (this.d & 1) * 8, 0, 1), null, true);\\n return;\\n }\\n if (this.d)\\n this.e();\\n else\\n this.u.push({\\n r: function () {\\n if (!(_this.d & 1))\\n return;\\n _this.u.splice(-1, 1);\\n _this.e();\\n },\\n t: function () { }\\n });\\n this.d = 3;\\n };\\n Zip.prototype.e = function () {\\n var bt = 0, l = 0, tl = 0;\\n for (var _i = 0, _a = this.u; _i < _a.length; _i++) {\\n var f = _a[_i];\\n tl += 46 + f.f.length + exfl(f.extra) + (f.o ? f.o.length : 0);\\n }\\n var out = new u8(tl + 22);\\n for (var _b = 0, _c = this.u; _b < _c.length; _b++) {\\n var f = _c[_b];\\n wzh(out, bt, f, f.f, f.u, -f.c - 2, l, f.o);\\n bt += 46 + f.f.length + exfl(f.extra) + (f.o ? f.o.length : 0), l += f.b;\\n }\\n wzf(out, bt, this.u.length, tl, l);\\n this.ondata(null, out, true);\\n this.d = 2;\\n };\\n /**\\n * A method to terminate any internal workers used by the stream. Subsequent\\n * calls to add() will fail.\\n */\\n Zip.prototype.terminate = function () {\\n for (var _i = 0, _a = this.u; _i < _a.length; _i++) {\\n var f = _a[_i];\\n f.t();\\n }\\n this.d = 2;\\n };\\n return Zip;\\n}());\\nexport { Zip };\\nexport function zip(data, opts, cb) {\\n if (!cb)\\n cb = opts, opts = {};\\n if (typeof cb != 'function')\\n err(7);\\n var r = {};\\n fltn(data, '', r, opts);\\n var k = Object.keys(r);\\n var lft = k.length, o = 0, tot = 0;\\n var slft = lft, files = new Array(lft);\\n var term = [];\\n var tAll = function () {\\n for (var i = 0; i < term.length; ++i)\\n term[i]();\\n };\\n var cbd = function (a, b) {\\n mt(function () { cb(a, b); });\\n };\\n mt(function () { cbd = cb; });\\n var cbf = function () {\\n var out = new u8(tot + 22), oe = o, cdl = tot - o;\\n tot = 0;\\n for (var i = 0; i < slft; ++i) {\\n var f = files[i];\\n try {\\n var l = f.c.length;\\n wzh(out, tot, f, f.f, f.u, l);\\n var badd = 30 + f.f.length + exfl(f.extra);\\n var loc = tot + badd;\\n out.set(f.c, loc);\\n wzh(out, o, f, f.f, f.u, l, tot, f.m), o += 16 + badd + (f.m ? f.m.length : 0), tot = loc + l;\\n }\\n catch (e) {\\n return cbd(e, null);\\n }\\n }\\n wzf(out, o, files.length, cdl, oe);\\n cbd(null, out);\\n };\\n if (!lft)\\n cbf();\\n var _loop_1 = function (i) {\\n var fn = k[i];\\n var _a = r[fn], file = _a[0], p = _a[1];\\n var c = crc(), size = file.length;\\n c.p(file);\\n var f = strToU8(fn), s = f.length;\\n var com = p.comment, m = com && strToU8(com), ms = m && m.length;\\n var exl = exfl(p.extra);\\n var compression = p.level == 0 ? 0 : 8;\\n var cbl = function (e, d) {\\n if (e) {\\n tAll();\\n cbd(e, null);\\n }\\n else {\\n var l = d.length;\\n files[i] = mrg(p, {\\n size: size,\\n crc: c.d(),\\n c: d,\\n f: f,\\n m: m,\\n u: s != fn.length || (m && (com.length != ms)),\\n compression: compression\\n });\\n o += 30 + s + exl + l;\\n tot += 76 + 2 * (s + exl) + (ms || 0) + l;\\n if (!--lft)\\n cbf();\\n }\\n };\\n if (s > 65535)\\n cbl(err(11, 0, 1), null);\\n if (!compression)\\n cbl(null, file);\\n else if (size < 160000) {\\n try {\\n cbl(null, deflateSync(file, p));\\n }\\n catch (e) {\\n cbl(e, null);\\n }\\n }\\n else\\n term.push(deflate(file, p, cbl));\\n };\\n // Cannot use lft because it can decrease\\n for (var i = 0; i < slft; ++i) {\\n _loop_1(i);\\n }\\n return tAll;\\n}\\n/**\\n * Synchronously creates a ZIP file. Prefer using `zip` for better performance\\n * with more than one file.\\n * @param data The directory structure for the ZIP archive\\n * @param opts The main options, merged with per-file options\\n * @returns The generated ZIP archive\\n */\\nexport function zipSync(data, opts) {\\n if (!opts)\\n opts = {};\\n var r = {};\\n var files = [];\\n fltn(data, '', r, opts);\\n var o = 0;\\n var tot = 0;\\n for (var fn in r) {\\n var _a = r[fn], file = _a[0], p = _a[1];\\n var compression = p.level == 0 ? 0 : 8;\\n var f = strToU8(fn), s = f.length;\\n var com = p.comment, m = com && strToU8(com), ms = m && m.length;\\n var exl = exfl(p.extra);\\n if (s > 65535)\\n err(11);\\n var d = compression ? deflateSync(file, p) : file, l = d.length;\\n var c = crc();\\n c.p(file);\\n files.push(mrg(p, {\\n size: file.length,\\n crc: c.d(),\\n c: d,\\n f: f,\\n m: m,\\n u: s != fn.length || (m && (com.length != ms)),\\n o: o,\\n compression: compression\\n }));\\n o += 30 + s + exl + l;\\n tot += 76 + 2 * (s + exl) + (ms || 0) + l;\\n }\\n var out = new u8(tot + 22), oe = o, cdl = tot - o;\\n for (var i = 0; i < files.length; ++i) {\\n var f = files[i];\\n wzh(out, f.o, f, f.f, f.u, f.c.length);\\n var badd = 30 + f.f.length + exfl(f.extra);\\n out.set(f.c, f.o + badd);\\n wzh(out, o, f, f.f, f.u, f.c.length, f.o, f.m), o += 16 + badd + (f.m ? f.m.length : 0);\\n }\\n wzf(out, o, files.length, cdl, oe);\\n return out;\\n}\\n/**\\n * Streaming pass-through decompression for ZIP archives\\n */\\nvar UnzipPassThrough = /*#__PURE__*/ (function () {\\n function UnzipPassThrough() {\\n }\\n UnzipPassThrough.prototype.push = function (data, final) {\\n this.ondata(null, data, final);\\n };\\n UnzipPassThrough.compression = 0;\\n return UnzipPassThrough;\\n}());\\nexport { UnzipPassThrough };\\n/**\\n * Streaming DEFLATE decompression for ZIP archives. Prefer AsyncZipInflate for\\n * better performance.\\n */\\nvar UnzipInflate = /*#__PURE__*/ (function () {\\n /**\\n * Creates a DEFLATE decompression that can be used in ZIP archives\\n */\\n function UnzipInflate() {\\n var _this = this;\\n this.i = new Inflate(function (dat, final) {\\n _this.ondata(null, dat, final);\\n });\\n }\\n UnzipInflate.prototype.push = function (data, final) {\\n try {\\n this.i.push(data, final);\\n }\\n catch (e) {\\n this.ondata(e, null, final);\\n }\\n };\\n UnzipInflate.compression = 8;\\n return UnzipInflate;\\n}());\\nexport { UnzipInflate };\\n/**\\n * Asynchronous streaming DEFLATE decompression for ZIP archives\\n */\\nvar AsyncUnzipInflate = /*#__PURE__*/ (function () {\\n /**\\n * Creates a DEFLATE decompression that can be used in ZIP archives\\n */\\n function AsyncUnzipInflate(_, sz) {\\n var _this = this;\\n if (sz < 320000) {\\n this.i = new Inflate(function (dat, final) {\\n _this.ondata(null, dat, final);\\n });\\n }\\n else {\\n this.i = new AsyncInflate(function (err, dat, final) {\\n _this.ondata(err, dat, final);\\n });\\n this.terminate = this.i.terminate;\\n }\\n }\\n AsyncUnzipInflate.prototype.push = function (data, final) {\\n if (this.i.terminate)\\n data = slc(data, 0);\\n this.i.push(data, final);\\n };\\n AsyncUnzipInflate.compression = 8;\\n return AsyncUnzipInflate;\\n}());\\nexport { AsyncUnzipInflate };\\n/**\\n * A ZIP archive decompression stream that emits files as they are discovered\\n */\\nvar Unzip = /*#__PURE__*/ (function () {\\n /**\\n * Creates a ZIP decompression stream\\n * @param cb The callback to call whenever a file in the ZIP archive is found\\n */\\n function Unzip(cb) {\\n this.onfile = cb;\\n this.k = [];\\n this.o = {\\n 0: UnzipPassThrough\\n };\\n this.p = et;\\n }\\n /**\\n * Pushes a chunk to be unzipped\\n * @param chunk The chunk to push\\n * @param final Whether this is the last chunk\\n */\\n Unzip.prototype.push = function (chunk, final) {\\n var _this = this;\\n if (!this.onfile)\\n err(5);\\n if (!this.p)\\n err(4);\\n if (this.c > 0) {\\n var len = Math.min(this.c, chunk.length);\\n var toAdd = chunk.subarray(0, len);\\n this.c -= len;\\n if (this.d)\\n this.d.push(toAdd, !this.c);\\n else\\n this.k[0].push(toAdd);\\n chunk = chunk.subarray(len);\\n if (chunk.length)\\n return this.push(chunk, final);\\n }\\n else {\\n var f = 0, i = 0, is = void 0, buf = void 0;\\n if (!this.p.length)\\n buf = chunk;\\n else if (!chunk.length)\\n buf = this.p;\\n else {\\n buf = new u8(this.p.length + chunk.length);\\n buf.set(this.p), buf.set(chunk, this.p.length);\\n }\\n var l = buf.length, oc = this.c, add = oc && this.d;\\n var _loop_2 = function () {\\n var _a;\\n var sig = b4(buf, i);\\n if (sig == 0x4034B50) {\\n f = 1, is = i;\\n this_1.d = null;\\n this_1.c = 0;\\n var bf = b2(buf, i + 6), cmp_1 = b2(buf, i + 8), u = bf & 2048, dd = bf & 8, fnl = b2(buf, i + 26), es = b2(buf, i + 28);\\n if (l > i + 30 + fnl + es) {\\n var chks_3 = [];\\n this_1.k.unshift(chks_3);\\n f = 2;\\n var sc_1 = b4(buf, i + 18), su_1 = b4(buf, i + 22);\\n var fn_1 = strFromU8(buf.subarray(i + 30, i += 30 + fnl), !u);\\n if (sc_1 == 4294967295) {\\n _a = dd ? [-2] : z64e(buf, i), sc_1 = _a[0], su_1 = _a[1];\\n }\\n else if (dd)\\n sc_1 = -1;\\n i += es;\\n this_1.c = sc_1;\\n var d_1;\\n var file_1 = {\\n name: fn_1,\\n compression: cmp_1,\\n start: function () {\\n if (!file_1.ondata)\\n err(5);\\n if (!sc_1)\\n file_1.ondata(null, et, true);\\n else {\\n var ctr = _this.o[cmp_1];\\n if (!ctr)\\n file_1.ondata(err(14, 'unknown compression type ' + cmp_1, 1), null, false);\\n d_1 = sc_1 < 0 ? new ctr(fn_1) : new ctr(fn_1, sc_1, su_1);\\n d_1.ondata = function (err, dat, final) { file_1.ondata(err, dat, final); };\\n for (var _i = 0, chks_4 = chks_3; _i < chks_4.length; _i++) {\\n var dat = chks_4[_i];\\n d_1.push(dat, false);\\n }\\n if (_this.k[0] == chks_3 && _this.c)\\n _this.d = d_1;\\n else\\n d_1.push(et, true);\\n }\\n },\\n terminate: function () {\\n if (d_1 && d_1.terminate)\\n d_1.terminate();\\n }\\n };\\n if (sc_1 >= 0)\\n file_1.size = sc_1, file_1.originalSize = su_1;\\n this_1.onfile(file_1);\\n }\\n return \\\"break\\\";\\n }\\n else if (oc) {\\n if (sig == 0x8074B50) {\\n is = i += 12 + (oc == -2 && 8), f = 3, this_1.c = 0;\\n return \\\"break\\\";\\n }\\n else if (sig == 0x2014B50) {\\n is = i -= 4, f = 3, this_1.c = 0;\\n return \\\"break\\\";\\n }\\n }\\n };\\n var this_1 = this;\\n for (; i < l - 4; ++i) {\\n var state_1 = _loop_2();\\n if (state_1 === \\\"break\\\")\\n break;\\n }\\n this.p = et;\\n if (oc < 0) {\\n var dat = f ? buf.subarray(0, is - 12 - (oc == -2 && 8) - (b4(buf, is - 16) == 0x8074B50 && 4)) : buf.subarray(0, i);\\n if (add)\\n add.push(dat, !!f);\\n else\\n this.k[+(f == 2)].push(dat);\\n }\\n if (f & 2)\\n return this.push(buf.subarray(i), final);\\n this.p = buf.subarray(i);\\n }\\n if (final) {\\n if (this.c)\\n err(13);\\n this.p = null;\\n }\\n };\\n /**\\n * Registers a decoder with the stream, allowing for files compressed with\\n * the compression type provided to be expanded correctly\\n * @param decoder The decoder constructor\\n */\\n Unzip.prototype.register = function (decoder) {\\n this.o[decoder.compression] = decoder;\\n };\\n return Unzip;\\n}());\\nexport { Unzip };\\nvar mt = typeof queueMicrotask == 'function' ? queueMicrotask : typeof setTimeout == 'function' ? setTimeout : function (fn) { fn(); };\\nexport function unzip(data, opts, cb) {\\n if (!cb)\\n cb = opts, opts = {};\\n if (typeof cb != 'function')\\n err(7);\\n var term = [];\\n var tAll = function () {\\n for (var i = 0; i < term.length; ++i)\\n term[i]();\\n };\\n var files = {};\\n var cbd = function (a, b) {\\n mt(function () { cb(a, b); });\\n };\\n mt(function () { cbd = cb; });\\n var e = data.length - 22;\\n for (; b4(data, e) != 0x6054B50; --e) {\\n if (!e || data.length - e > 65558) {\\n cbd(err(13, 0, 1), null);\\n return tAll;\\n }\\n }\\n ;\\n var lft = b2(data, e + 8);\\n if (lft) {\\n var c = lft;\\n var o = b4(data, e + 16);\\n var z = o == 4294967295 || c == 65535;\\n if (z) {\\n var ze = b4(data, e - 12);\\n z = b4(data, ze) == 0x6064B50;\\n if (z) {\\n c = lft = b4(data, ze + 32);\\n o = b4(data, ze + 48);\\n }\\n }\\n var fltr = opts && opts.filter;\\n var _loop_3 = function (i) {\\n var _a = zh(data, o, z), c_1 = _a[0], sc = _a[1], su = _a[2], fn = _a[3], no = _a[4], off = _a[5], b = slzh(data, off);\\n o = no;\\n var cbl = function (e, d) {\\n if (e) {\\n tAll();\\n cbd(e, null);\\n }\\n else {\\n if (d)\\n files[fn] = d;\\n if (!--lft)\\n cbd(null, files);\\n }\\n };\\n if (!fltr || fltr({\\n name: fn,\\n size: sc,\\n originalSize: su,\\n compression: c_1\\n })) {\\n if (!c_1)\\n cbl(null, slc(data, b, b + sc));\\n else if (c_1 == 8) {\\n var infl = data.subarray(b, b + sc);\\n // Synchronously decompress under 512KB, or barely-compressed data\\n if (su < 524288 || sc > 0.8 * su) {\\n try {\\n cbl(null, inflateSync(infl, { out: new u8(su) }));\\n }\\n catch (e) {\\n cbl(e, null);\\n }\\n }\\n else\\n term.push(inflate(infl, { size: su }, cbl));\\n }\\n else\\n cbl(err(14, 'unknown compression type ' + c_1, 1), null);\\n }\\n else\\n cbl(null, null);\\n };\\n for (var i = 0; i < c; ++i) {\\n _loop_3(i);\\n }\\n }\\n else\\n cbd(null, {});\\n return tAll;\\n}\\n/**\\n * Synchronously decompresses a ZIP archive. Prefer using `unzip` for better\\n * performance with more than one file.\\n * @param data The raw compressed ZIP file\\n * @param opts The ZIP extraction options\\n * @returns The decompressed files\\n */\\nexport function unzipSync(data, opts) {\\n var files = {};\\n var e = data.length - 22;\\n for (; b4(data, e) != 0x6054B50; --e) {\\n if (!e || data.length - e > 65558)\\n err(13);\\n }\\n ;\\n var c = b2(data, e + 8);\\n if (!c)\\n return {};\\n var o = b4(data, e + 16);\\n var z = o == 4294967295 || c == 65535;\\n if (z) {\\n var ze = b4(data, e - 12);\\n z = b4(data, ze) == 0x6064B50;\\n if (z) {\\n c = b4(data, ze + 32);\\n o = b4(data, ze + 48);\\n }\\n }\\n var fltr = opts && opts.filter;\\n for (var i = 0; i < c; ++i) {\\n var _a = zh(data, o, z), c_2 = _a[0], sc = _a[1], su = _a[2], fn = _a[3], no = _a[4], off = _a[5], b = slzh(data, off);\\n o = no;\\n if (!fltr || fltr({\\n name: fn,\\n size: sc,\\n originalSize: su,\\n compression: c_2\\n })) {\\n if (!c_2)\\n files[fn] = slc(data, b, b + sc);\\n else if (c_2 == 8)\\n files[fn] = inflateSync(data.subarray(b, b + sc), { out: new u8(su) });\\n else\\n err(14, 'unknown compression type ' + c_2);\\n }\\n }\\n return files;\\n}\\n\",\"import Any from './properties/Any/regex.mjs';\\nimport Cc from './categories/Cc/regex.mjs';\\nimport Cf from './categories/Cf/regex.mjs';\\nimport P from './categories/P/regex.mjs';\\nimport S from './categories/S/regex.mjs';\\nimport Z from './categories/Z/regex.mjs';\\n\\nexport { Any, Cc, Cf, P, S, Z };\\n\",\"export default /[\\\\0-\\\\uD7FF\\\\uE000-\\\\uFFFF]|[\\\\uD800-\\\\uDBFF][\\\\uDC00-\\\\uDFFF]|[\\\\uD800-\\\\uDBFF](?![\\\\uDC00-\\\\uDFFF])|(?:[^\\\\uD800-\\\\uDBFF]|^)[\\\\uDC00-\\\\uDFFF]/\",\"export default /[\\\\0-\\\\x1F\\\\x7F-\\\\x9F]/\",\"export default /[\\\\xAD\\\\u0600-\\\\u0605\\\\u061C\\\\u06DD\\\\u070F\\\\u0890\\\\u0891\\\\u08E2\\\\u180E\\\\u200B-\\\\u200F\\\\u202A-\\\\u202E\\\\u2060-\\\\u2064\\\\u2066-\\\\u206F\\\\uFEFF\\\\uFFF9-\\\\uFFFB]|\\\\uD804[\\\\uDCBD\\\\uDCCD]|\\\\uD80D[\\\\uDC30-\\\\uDC3F]|\\\\uD82F[\\\\uDCA0-\\\\uDCA3]|\\\\uD834[\\\\uDD73-\\\\uDD7A]|\\\\uDB40[\\\\uDC01\\\\uDC20-\\\\uDC7F]/\",\"export default /[!-#%-\\\\*,-\\\\/:;\\\\?@\\\\[-\\\\]_\\\\{\\\\}\\\\xA1\\\\xA7\\\\xAB\\\\xB6\\\\xB7\\\\xBB\\\\xBF\\\\u037E\\\\u0387\\\\u055A-\\\\u055F\\\\u0589\\\\u058A\\\\u05BE\\\\u05C0\\\\u05C3\\\\u05C6\\\\u05F3\\\\u05F4\\\\u0609\\\\u060A\\\\u060C\\\\u060D\\\\u061B\\\\u061D-\\\\u061F\\\\u066A-\\\\u066D\\\\u06D4\\\\u0700-\\\\u070D\\\\u07F7-\\\\u07F9\\\\u0830-\\\\u083E\\\\u085E\\\\u0964\\\\u0965\\\\u0970\\\\u09FD\\\\u0A76\\\\u0AF0\\\\u0C77\\\\u0C84\\\\u0DF4\\\\u0E4F\\\\u0E5A\\\\u0E5B\\\\u0F04-\\\\u0F12\\\\u0F14\\\\u0F3A-\\\\u0F3D\\\\u0F85\\\\u0FD0-\\\\u0FD4\\\\u0FD9\\\\u0FDA\\\\u104A-\\\\u104F\\\\u10FB\\\\u1360-\\\\u1368\\\\u1400\\\\u166E\\\\u169B\\\\u169C\\\\u16EB-\\\\u16ED\\\\u1735\\\\u1736\\\\u17D4-\\\\u17D6\\\\u17D8-\\\\u17DA\\\\u1800-\\\\u180A\\\\u1944\\\\u1945\\\\u1A1E\\\\u1A1F\\\\u1AA0-\\\\u1AA6\\\\u1AA8-\\\\u1AAD\\\\u1B5A-\\\\u1B60\\\\u1B7D\\\\u1B7E\\\\u1BFC-\\\\u1BFF\\\\u1C3B-\\\\u1C3F\\\\u1C7E\\\\u1C7F\\\\u1CC0-\\\\u1CC7\\\\u1CD3\\\\u2010-\\\\u2027\\\\u2030-\\\\u2043\\\\u2045-\\\\u2051\\\\u2053-\\\\u205E\\\\u207D\\\\u207E\\\\u208D\\\\u208E\\\\u2308-\\\\u230B\\\\u2329\\\\u232A\\\\u2768-\\\\u2775\\\\u27C5\\\\u27C6\\\\u27E6-\\\\u27EF\\\\u2983-\\\\u2998\\\\u29D8-\\\\u29DB\\\\u29FC\\\\u29FD\\\\u2CF9-\\\\u2CFC\\\\u2CFE\\\\u2CFF\\\\u2D70\\\\u2E00-\\\\u2E2E\\\\u2E30-\\\\u2E4F\\\\u2E52-\\\\u2E5D\\\\u3001-\\\\u3003\\\\u3008-\\\\u3011\\\\u3014-\\\\u301F\\\\u3030\\\\u303D\\\\u30A0\\\\u30FB\\\\uA4FE\\\\uA4FF\\\\uA60D-\\\\uA60F\\\\uA673\\\\uA67E\\\\uA6F2-\\\\uA6F7\\\\uA874-\\\\uA877\\\\uA8CE\\\\uA8CF\\\\uA8F8-\\\\uA8FA\\\\uA8FC\\\\uA92E\\\\uA92F\\\\uA95F\\\\uA9C1-\\\\uA9CD\\\\uA9DE\\\\uA9DF\\\\uAA5C-\\\\uAA5F\\\\uAADE\\\\uAADF\\\\uAAF0\\\\uAAF1\\\\uABEB\\\\uFD3E\\\\uFD3F\\\\uFE10-\\\\uFE19\\\\uFE30-\\\\uFE52\\\\uFE54-\\\\uFE61\\\\uFE63\\\\uFE68\\\\uFE6A\\\\uFE6B\\\\uFF01-\\\\uFF03\\\\uFF05-\\\\uFF0A\\\\uFF0C-\\\\uFF0F\\\\uFF1A\\\\uFF1B\\\\uFF1F\\\\uFF20\\\\uFF3B-\\\\uFF3D\\\\uFF3F\\\\uFF5B\\\\uFF5D\\\\uFF5F-\\\\uFF65]|\\\\uD800[\\\\uDD00-\\\\uDD02\\\\uDF9F\\\\uDFD0]|\\\\uD801\\\\uDD6F|\\\\uD802[\\\\uDC57\\\\uDD1F\\\\uDD3F\\\\uDE50-\\\\uDE58\\\\uDE7F\\\\uDEF0-\\\\uDEF6\\\\uDF39-\\\\uDF3F\\\\uDF99-\\\\uDF9C]|\\\\uD803[\\\\uDEAD\\\\uDF55-\\\\uDF59\\\\uDF86-\\\\uDF89]|\\\\uD804[\\\\uDC47-\\\\uDC4D\\\\uDCBB\\\\uDCBC\\\\uDCBE-\\\\uDCC1\\\\uDD40-\\\\uDD43\\\\uDD74\\\\uDD75\\\\uDDC5-\\\\uDDC8\\\\uDDCD\\\\uDDDB\\\\uDDDD-\\\\uDDDF\\\\uDE38-\\\\uDE3D\\\\uDEA9]|\\\\uD805[\\\\uDC4B-\\\\uDC4F\\\\uDC5A\\\\uDC5B\\\\uDC5D\\\\uDCC6\\\\uDDC1-\\\\uDDD7\\\\uDE41-\\\\uDE43\\\\uDE60-\\\\uDE6C\\\\uDEB9\\\\uDF3C-\\\\uDF3E]|\\\\uD806[\\\\uDC3B\\\\uDD44-\\\\uDD46\\\\uDDE2\\\\uDE3F-\\\\uDE46\\\\uDE9A-\\\\uDE9C\\\\uDE9E-\\\\uDEA2\\\\uDF00-\\\\uDF09]|\\\\uD807[\\\\uDC41-\\\\uDC45\\\\uDC70\\\\uDC71\\\\uDEF7\\\\uDEF8\\\\uDF43-\\\\uDF4F\\\\uDFFF]|\\\\uD809[\\\\uDC70-\\\\uDC74]|\\\\uD80B[\\\\uDFF1\\\\uDFF2]|\\\\uD81A[\\\\uDE6E\\\\uDE6F\\\\uDEF5\\\\uDF37-\\\\uDF3B\\\\uDF44]|\\\\uD81B[\\\\uDE97-\\\\uDE9A\\\\uDFE2]|\\\\uD82F\\\\uDC9F|\\\\uD836[\\\\uDE87-\\\\uDE8B]|\\\\uD83A[\\\\uDD5E\\\\uDD5F]/\",\"export default /[\\\\$\\\\+<->\\\\^`\\\\|~\\\\xA2-\\\\xA6\\\\xA8\\\\xA9\\\\xAC\\\\xAE-\\\\xB1\\\\xB4\\\\xB8\\\\xD7\\\\xF7\\\\u02C2-\\\\u02C5\\\\u02D2-\\\\u02DF\\\\u02E5-\\\\u02EB\\\\u02ED\\\\u02EF-\\\\u02FF\\\\u0375\\\\u0384\\\\u0385\\\\u03F6\\\\u0482\\\\u058D-\\\\u058F\\\\u0606-\\\\u0608\\\\u060B\\\\u060E\\\\u060F\\\\u06DE\\\\u06E9\\\\u06FD\\\\u06FE\\\\u07F6\\\\u07FE\\\\u07FF\\\\u0888\\\\u09F2\\\\u09F3\\\\u09FA\\\\u09FB\\\\u0AF1\\\\u0B70\\\\u0BF3-\\\\u0BFA\\\\u0C7F\\\\u0D4F\\\\u0D79\\\\u0E3F\\\\u0F01-\\\\u0F03\\\\u0F13\\\\u0F15-\\\\u0F17\\\\u0F1A-\\\\u0F1F\\\\u0F34\\\\u0F36\\\\u0F38\\\\u0FBE-\\\\u0FC5\\\\u0FC7-\\\\u0FCC\\\\u0FCE\\\\u0FCF\\\\u0FD5-\\\\u0FD8\\\\u109E\\\\u109F\\\\u1390-\\\\u1399\\\\u166D\\\\u17DB\\\\u1940\\\\u19DE-\\\\u19FF\\\\u1B61-\\\\u1B6A\\\\u1B74-\\\\u1B7C\\\\u1FBD\\\\u1FBF-\\\\u1FC1\\\\u1FCD-\\\\u1FCF\\\\u1FDD-\\\\u1FDF\\\\u1FED-\\\\u1FEF\\\\u1FFD\\\\u1FFE\\\\u2044\\\\u2052\\\\u207A-\\\\u207C\\\\u208A-\\\\u208C\\\\u20A0-\\\\u20C0\\\\u2100\\\\u2101\\\\u2103-\\\\u2106\\\\u2108\\\\u2109\\\\u2114\\\\u2116-\\\\u2118\\\\u211E-\\\\u2123\\\\u2125\\\\u2127\\\\u2129\\\\u212E\\\\u213A\\\\u213B\\\\u2140-\\\\u2144\\\\u214A-\\\\u214D\\\\u214F\\\\u218A\\\\u218B\\\\u2190-\\\\u2307\\\\u230C-\\\\u2328\\\\u232B-\\\\u2426\\\\u2440-\\\\u244A\\\\u249C-\\\\u24E9\\\\u2500-\\\\u2767\\\\u2794-\\\\u27C4\\\\u27C7-\\\\u27E5\\\\u27F0-\\\\u2982\\\\u2999-\\\\u29D7\\\\u29DC-\\\\u29FB\\\\u29FE-\\\\u2B73\\\\u2B76-\\\\u2B95\\\\u2B97-\\\\u2BFF\\\\u2CE5-\\\\u2CEA\\\\u2E50\\\\u2E51\\\\u2E80-\\\\u2E99\\\\u2E9B-\\\\u2EF3\\\\u2F00-\\\\u2FD5\\\\u2FF0-\\\\u2FFF\\\\u3004\\\\u3012\\\\u3013\\\\u3020\\\\u3036\\\\u3037\\\\u303E\\\\u303F\\\\u309B\\\\u309C\\\\u3190\\\\u3191\\\\u3196-\\\\u319F\\\\u31C0-\\\\u31E3\\\\u31EF\\\\u3200-\\\\u321E\\\\u322A-\\\\u3247\\\\u3250\\\\u3260-\\\\u327F\\\\u328A-\\\\u32B0\\\\u32C0-\\\\u33FF\\\\u4DC0-\\\\u4DFF\\\\uA490-\\\\uA4C6\\\\uA700-\\\\uA716\\\\uA720\\\\uA721\\\\uA789\\\\uA78A\\\\uA828-\\\\uA82B\\\\uA836-\\\\uA839\\\\uAA77-\\\\uAA79\\\\uAB5B\\\\uAB6A\\\\uAB6B\\\\uFB29\\\\uFBB2-\\\\uFBC2\\\\uFD40-\\\\uFD4F\\\\uFDCF\\\\uFDFC-\\\\uFDFF\\\\uFE62\\\\uFE64-\\\\uFE66\\\\uFE69\\\\uFF04\\\\uFF0B\\\\uFF1C-\\\\uFF1E\\\\uFF3E\\\\uFF40\\\\uFF5C\\\\uFF5E\\\\uFFE0-\\\\uFFE6\\\\uFFE8-\\\\uFFEE\\\\uFFFC\\\\uFFFD]|\\\\uD800[\\\\uDD37-\\\\uDD3F\\\\uDD79-\\\\uDD89\\\\uDD8C-\\\\uDD8E\\\\uDD90-\\\\uDD9C\\\\uDDA0\\\\uDDD0-\\\\uDDFC]|\\\\uD802[\\\\uDC77\\\\uDC78\\\\uDEC8]|\\\\uD805\\\\uDF3F|\\\\uD807[\\\\uDFD5-\\\\uDFF1]|\\\\uD81A[\\\\uDF3C-\\\\uDF3F\\\\uDF45]|\\\\uD82F\\\\uDC9C|\\\\uD833[\\\\uDF50-\\\\uDFC3]|\\\\uD834[\\\\uDC00-\\\\uDCF5\\\\uDD00-\\\\uDD26\\\\uDD29-\\\\uDD64\\\\uDD6A-\\\\uDD6C\\\\uDD83\\\\uDD84\\\\uDD8C-\\\\uDDA9\\\\uDDAE-\\\\uDDEA\\\\uDE00-\\\\uDE41\\\\uDE45\\\\uDF00-\\\\uDF56]|\\\\uD835[\\\\uDEC1\\\\uDEDB\\\\uDEFB\\\\uDF15\\\\uDF35\\\\uDF4F\\\\uDF6F\\\\uDF89\\\\uDFA9\\\\uDFC3]|\\\\uD836[\\\\uDC00-\\\\uDDFF\\\\uDE37-\\\\uDE3A\\\\uDE6D-\\\\uDE74\\\\uDE76-\\\\uDE83\\\\uDE85\\\\uDE86]|\\\\uD838[\\\\uDD4F\\\\uDEFF]|\\\\uD83B[\\\\uDCAC\\\\uDCB0\\\\uDD2E\\\\uDEF0\\\\uDEF1]|\\\\uD83C[\\\\uDC00-\\\\uDC2B\\\\uDC30-\\\\uDC93\\\\uDCA0-\\\\uDCAE\\\\uDCB1-\\\\uDCBF\\\\uDCC1-\\\\uDCCF\\\\uDCD1-\\\\uDCF5\\\\uDD0D-\\\\uDDAD\\\\uDDE6-\\\\uDE02\\\\uDE10-\\\\uDE3B\\\\uDE40-\\\\uDE48\\\\uDE50\\\\uDE51\\\\uDE60-\\\\uDE65\\\\uDF00-\\\\uDFFF]|\\\\uD83D[\\\\uDC00-\\\\uDED7\\\\uDEDC-\\\\uDEEC\\\\uDEF0-\\\\uDEFC\\\\uDF00-\\\\uDF76\\\\uDF7B-\\\\uDFD9\\\\uDFE0-\\\\uDFEB\\\\uDFF0]|\\\\uD83E[\\\\uDC00-\\\\uDC0B\\\\uDC10-\\\\uDC47\\\\uDC50-\\\\uDC59\\\\uDC60-\\\\uDC87\\\\uDC90-\\\\uDCAD\\\\uDCB0\\\\uDCB1\\\\uDD00-\\\\uDE53\\\\uDE60-\\\\uDE6D\\\\uDE70-\\\\uDE7C\\\\uDE80-\\\\uDE88\\\\uDE90-\\\\uDEBD\\\\uDEBF-\\\\uDEC5\\\\uDECE-\\\\uDEDB\\\\uDEE0-\\\\uDEE8\\\\uDEF0-\\\\uDEF8\\\\uDF00-\\\\uDF92\\\\uDF94-\\\\uDFCA]/\",\"export default /[ \\\\xA0\\\\u1680\\\\u2000-\\\\u200A\\\\u2028\\\\u2029\\\\u202F\\\\u205F\\\\u3000]/\",\"import { Any, Cc, Z, P } from 'uc.micro'\\n\\nexport default function (opts) {\\n const re = {}\\n opts = opts || {}\\n\\n re.src_Any = Any.source\\n re.src_Cc = Cc.source\\n re.src_Z = Z.source\\n re.src_P = P.source\\n\\n // \\\\p{\\\\Z\\\\P\\\\Cc\\\\CF} (white spaces + control + format + punctuation)\\n re.src_ZPCc = [re.src_Z, re.src_P, re.src_Cc].join('|')\\n\\n // \\\\p{\\\\Z\\\\Cc} (white spaces + control)\\n re.src_ZCc = [re.src_Z, re.src_Cc].join('|')\\n\\n // Experimental. List of chars, completely prohibited in links\\n // because can separate it from other part of text\\n const text_separators = '[><\\\\uff5c]'\\n\\n // All possible word characters (everything without punctuation, spaces & controls)\\n // Defined via punctuation & spaces to save space\\n // Should be something like \\\\p{\\\\L\\\\N\\\\S\\\\M} (\\\\w but without `_`)\\n re.src_pseudo_letter = '(?:(?!' + text_separators + '|' + re.src_ZPCc + ')' + re.src_Any + ')'\\n // The same as abothe but without [0-9]\\n // var src_pseudo_letter_non_d = '(?:(?![0-9]|' + src_ZPCc + ')' + src_Any + ')';\\n\\n re.src_ip4 =\\n\\n '(?:(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\\\\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'\\n\\n // Prohibit any of \\\"@/[]()\\\" in user/pass to avoid wrong domain fetch.\\n re.src_auth = '(?:(?:(?!' + re.src_ZCc + '|[@/\\\\\\\\[\\\\\\\\]()]).)+@)?'\\n\\n re.src_port =\\n\\n '(?::(?:6(?:[0-4]\\\\\\\\d{3}|5(?:[0-4]\\\\\\\\d{2}|5(?:[0-2]\\\\\\\\d|3[0-5])))|[1-5]?\\\\\\\\d{1,4}))?'\\n\\n re.src_host_terminator =\\n\\n '(?=$|' + text_separators + '|' + re.src_ZPCc + ')' +\\n '(?!' + (opts['---'] ? '-(?!--)|' : '-|') + '_|:\\\\\\\\d|\\\\\\\\.-|\\\\\\\\.(?!$|' + re.src_ZPCc + '))'\\n\\n re.src_path =\\n\\n '(?:' +\\n '[/?#]' +\\n '(?:' +\\n '(?!' + re.src_ZCc + '|' + text_separators + '|[()[\\\\\\\\]{}.,\\\"\\\\'?!\\\\\\\\-;]).|' +\\n '\\\\\\\\[(?:(?!' + re.src_ZCc + '|\\\\\\\\]).)*\\\\\\\\]|' +\\n '\\\\\\\\((?:(?!' + re.src_ZCc + '|[)]).)*\\\\\\\\)|' +\\n '\\\\\\\\{(?:(?!' + re.src_ZCc + '|[}]).)*\\\\\\\\}|' +\\n '\\\\\\\\\\\"(?:(?!' + re.src_ZCc + '|[\\\"]).)+\\\\\\\\\\\"|' +\\n \\\"\\\\\\\\'(?:(?!\\\" + re.src_ZCc + \\\"|[']).)+\\\\\\\\'|\\\" +\\n\\n // allow `I'm_king` if no pair found\\n \\\"\\\\\\\\'(?=\\\" + re.src_pseudo_letter + '|[-])|' +\\n\\n // google has many dots in \\\"google search\\\" links (#66, #81).\\n // github has ... in commit range links,\\n // Restrict to\\n // - english\\n // - percent-encoded\\n // - parts of file path\\n // - params separator\\n // until more examples found.\\n '\\\\\\\\.{2,}[a-zA-Z0-9%/&]|' +\\n\\n '\\\\\\\\.(?!' + re.src_ZCc + '|[.]|$)|' +\\n (opts['---']\\n ? '\\\\\\\\-(?!--(?:[^-]|$))(?:-*)|' // `---` => long dash, terminate\\n : '\\\\\\\\-+|'\\n ) +\\n // allow `,,,` in paths\\n ',(?!' + re.src_ZCc + '|$)|' +\\n\\n // allow `;` if not followed by space-like char\\n ';(?!' + re.src_ZCc + '|$)|' +\\n\\n // allow `!!!` in paths, but not at the end\\n '\\\\\\\\!+(?!' + re.src_ZCc + '|[!]|$)|' +\\n\\n '\\\\\\\\?(?!' + re.src_ZCc + '|[?]|$)' +\\n ')+' +\\n '|\\\\\\\\/' +\\n ')?'\\n\\n // Allow anything in markdown spec, forbid quote (\\\") at the first position\\n // because emails enclosed in quotes are far more common\\n re.src_email_name =\\n\\n '[\\\\\\\\-;:&=\\\\\\\\+\\\\\\\\$,\\\\\\\\.a-zA-Z0-9_][\\\\\\\\-;:&=\\\\\\\\+\\\\\\\\$,\\\\\\\\\\\"\\\\\\\\.a-zA-Z0-9_]*'\\n\\n re.src_xn =\\n\\n 'xn--[a-z0-9\\\\\\\\-]{1,59}'\\n\\n // More to read about domain names\\n // http://serverfault.com/questions/638260/\\n\\n re.src_domain_root =\\n\\n // Allow letters & digits (http://test1)\\n '(?:' +\\n re.src_xn +\\n '|' +\\n re.src_pseudo_letter + '{1,63}' +\\n ')'\\n\\n re.src_domain =\\n\\n '(?:' +\\n re.src_xn +\\n '|' +\\n '(?:' + re.src_pseudo_letter + ')' +\\n '|' +\\n '(?:' + re.src_pseudo_letter + '(?:-|' + re.src_pseudo_letter + '){0,61}' + re.src_pseudo_letter + ')' +\\n ')'\\n\\n re.src_host =\\n\\n '(?:' +\\n // Don't need IP check, because digits are already allowed in normal domain names\\n // src_ip4 +\\n // '|' +\\n '(?:(?:(?:' + re.src_domain + ')\\\\\\\\.)*' + re.src_domain/* _root */ + ')' +\\n ')'\\n\\n re.tpl_host_fuzzy =\\n\\n '(?:' +\\n re.src_ip4 +\\n '|' +\\n '(?:(?:(?:' + re.src_domain + ')\\\\\\\\.)+(?:%TLDS%))' +\\n ')'\\n\\n re.tpl_host_no_ip_fuzzy =\\n\\n '(?:(?:(?:' + re.src_domain + ')\\\\\\\\.)+(?:%TLDS%))'\\n\\n re.src_host_strict =\\n\\n re.src_host + re.src_host_terminator\\n\\n re.tpl_host_fuzzy_strict =\\n\\n re.tpl_host_fuzzy + re.src_host_terminator\\n\\n re.src_host_port_strict =\\n\\n re.src_host + re.src_port + re.src_host_terminator\\n\\n re.tpl_host_port_fuzzy_strict =\\n\\n re.tpl_host_fuzzy + re.src_port + re.src_host_terminator\\n\\n re.tpl_host_port_no_ip_fuzzy_strict =\\n\\n re.tpl_host_no_ip_fuzzy + re.src_port + re.src_host_terminator\\n\\n //\\n // Main rules\\n //\\n\\n // Rude test fuzzy links by host, for quick deny\\n re.tpl_host_fuzzy_test =\\n\\n 'localhost|www\\\\\\\\.|\\\\\\\\.\\\\\\\\d{1,3}\\\\\\\\.|(?:\\\\\\\\.(?:%TLDS%)(?:' + re.src_ZPCc + '|>|$))'\\n\\n re.tpl_email_fuzzy =\\n\\n '(^|' + text_separators + '|\\\"|\\\\\\\\(|' + re.src_ZCc + ')' +\\n '(' + re.src_email_name + '@' + re.tpl_host_fuzzy_strict + ')'\\n\\n re.tpl_link_fuzzy =\\n // Fuzzy link can't be prepended with .:/\\\\- and non punctuation.\\n // but can start with > (markdown blockquote)\\n '(^|(?![.:/\\\\\\\\-_@])(?:[$+<=>^`|\\\\uff5c]|' + re.src_ZPCc + '))' +\\n '((?![$+<=>^`|\\\\uff5c])' + re.tpl_host_port_fuzzy_strict + re.src_path + ')'\\n\\n re.tpl_link_no_ip_fuzzy =\\n // Fuzzy link can't be prepended with .:/\\\\- and non punctuation.\\n // but can start with > (markdown blockquote)\\n '(^|(?![.:/\\\\\\\\-_@])(?:[$+<=>^`|\\\\uff5c]|' + re.src_ZPCc + '))' +\\n '((?![$+<=>^`|\\\\uff5c])' + re.tpl_host_port_no_ip_fuzzy_strict + re.src_path + ')'\\n\\n return re\\n}\\n\",\"import reFactory from './lib/re.mjs'\\n\\n//\\n// Helpers\\n//\\n\\n// Merge objects\\n//\\nfunction assign (obj /* from1, from2, from3, ... */) {\\n const sources = Array.prototype.slice.call(arguments, 1)\\n\\n sources.forEach(function (source) {\\n if (!source) { return }\\n\\n Object.keys(source).forEach(function (key) {\\n obj[key] = source[key]\\n })\\n })\\n\\n return obj\\n}\\n\\nfunction _class (obj) { return Object.prototype.toString.call(obj) }\\nfunction isString (obj) { return _class(obj) === '[object String]' }\\nfunction isObject (obj) { return _class(obj) === '[object Object]' }\\nfunction isRegExp (obj) { return _class(obj) === '[object RegExp]' }\\nfunction isFunction (obj) { return _class(obj) === '[object Function]' }\\n\\nfunction escapeRE (str) { return str.replace(/[.?*+^$[\\\\]\\\\\\\\(){}|-]/g, '\\\\\\\\$&') }\\n\\n//\\n\\nconst defaultOptions = {\\n fuzzyLink: true,\\n fuzzyEmail: true,\\n fuzzyIP: false\\n}\\n\\nfunction isOptionsObj (obj) {\\n return Object.keys(obj || {}).reduce(function (acc, k) {\\n /* eslint-disable-next-line no-prototype-builtins */\\n return acc || defaultOptions.hasOwnProperty(k)\\n }, false)\\n}\\n\\nconst defaultSchemas = {\\n 'http:': {\\n validate: function (text, pos, self) {\\n const tail = text.slice(pos)\\n\\n if (!self.re.http) {\\n // compile lazily, because \\\"host\\\"-containing variables can change on tlds update.\\n self.re.http = new RegExp(\\n '^\\\\\\\\/\\\\\\\\/' + self.re.src_auth + self.re.src_host_port_strict + self.re.src_path, 'i'\\n )\\n }\\n if (self.re.http.test(tail)) {\\n return tail.match(self.re.http)[0].length\\n }\\n return 0\\n }\\n },\\n 'https:': 'http:',\\n 'ftp:': 'http:',\\n '//': {\\n validate: function (text, pos, self) {\\n const tail = text.slice(pos)\\n\\n if (!self.re.no_http) {\\n // compile lazily, because \\\"host\\\"-containing variables can change on tlds update.\\n self.re.no_http = new RegExp(\\n '^' +\\n self.re.src_auth +\\n // Don't allow single-level domains, because of false positives like '//test'\\n // with code comments\\n '(?:localhost|(?:(?:' + self.re.src_domain + ')\\\\\\\\.)+' + self.re.src_domain_root + ')' +\\n self.re.src_port +\\n self.re.src_host_terminator +\\n self.re.src_path,\\n\\n 'i'\\n )\\n }\\n\\n if (self.re.no_http.test(tail)) {\\n // should not be `://` & `///`, that protects from errors in protocol name\\n if (pos >= 3 && text[pos - 3] === ':') { return 0 }\\n if (pos >= 3 && text[pos - 3] === '/') { return 0 }\\n return tail.match(self.re.no_http)[0].length\\n }\\n return 0\\n }\\n },\\n 'mailto:': {\\n validate: function (text, pos, self) {\\n const tail = text.slice(pos)\\n\\n if (!self.re.mailto) {\\n self.re.mailto = new RegExp(\\n '^' + self.re.src_email_name + '@' + self.re.src_host_strict, 'i'\\n )\\n }\\n if (self.re.mailto.test(tail)) {\\n return tail.match(self.re.mailto)[0].length\\n }\\n return 0\\n }\\n }\\n}\\n\\n// RE pattern for 2-character tlds (autogenerated by ./support/tlds_2char_gen.js)\\n/* eslint-disable-next-line max-len */\\nconst tlds_2ch_src_re = 'a[cdefgilmnoqrstuwxz]|b[abdefghijmnorstvwyz]|c[acdfghiklmnoruvwxyz]|d[ejkmoz]|e[cegrstu]|f[ijkmor]|g[abdefghilmnpqrstuwy]|h[kmnrtu]|i[delmnoqrst]|j[emop]|k[eghimnprwyz]|l[abcikrstuvy]|m[acdeghklmnopqrstuvwxyz]|n[acefgilopruz]|om|p[aefghklmnrstwy]|qa|r[eosuw]|s[abcdeghijklmnortuvxyz]|t[cdfghjklmnortvwz]|u[agksyz]|v[aceginu]|w[fs]|y[et]|z[amw]'\\n\\n// DON'T try to make PRs with changes. Extend TLDs with LinkifyIt.tlds() instead\\nconst tlds_default = 'biz|com|edu|gov|net|org|pro|web|xxx|aero|asia|coop|info|museum|name|shop|рф'.split('|')\\n\\nfunction resetScanCache (self) {\\n self.__index__ = -1\\n self.__text_cache__ = ''\\n}\\n\\nfunction createValidator (re) {\\n return function (text, pos) {\\n const tail = text.slice(pos)\\n\\n if (re.test(tail)) {\\n return tail.match(re)[0].length\\n }\\n return 0\\n }\\n}\\n\\nfunction createNormalizer () {\\n return function (match, self) {\\n self.normalize(match)\\n }\\n}\\n\\n// Schemas compiler. Build regexps.\\n//\\nfunction compile (self) {\\n // Load & clone RE patterns.\\n const re = self.re = reFactory(self.__opts__)\\n\\n // Define dynamic patterns\\n const tlds = self.__tlds__.slice()\\n\\n self.onCompile()\\n\\n if (!self.__tlds_replaced__) {\\n tlds.push(tlds_2ch_src_re)\\n }\\n tlds.push(re.src_xn)\\n\\n re.src_tlds = tlds.join('|')\\n\\n function untpl (tpl) { return tpl.replace('%TLDS%', re.src_tlds) }\\n\\n re.email_fuzzy = RegExp(untpl(re.tpl_email_fuzzy), 'i')\\n re.link_fuzzy = RegExp(untpl(re.tpl_link_fuzzy), 'i')\\n re.link_no_ip_fuzzy = RegExp(untpl(re.tpl_link_no_ip_fuzzy), 'i')\\n re.host_fuzzy_test = RegExp(untpl(re.tpl_host_fuzzy_test), 'i')\\n\\n //\\n // Compile each schema\\n //\\n\\n const aliases = []\\n\\n self.__compiled__ = {} // Reset compiled data\\n\\n function schemaError (name, val) {\\n throw new Error('(LinkifyIt) Invalid schema \\\"' + name + '\\\": ' + val)\\n }\\n\\n Object.keys(self.__schemas__).forEach(function (name) {\\n const val = self.__schemas__[name]\\n\\n // skip disabled methods\\n if (val === null) { return }\\n\\n const compiled = { validate: null, link: null }\\n\\n self.__compiled__[name] = compiled\\n\\n if (isObject(val)) {\\n if (isRegExp(val.validate)) {\\n compiled.validate = createValidator(val.validate)\\n } else if (isFunction(val.validate)) {\\n compiled.validate = val.validate\\n } else {\\n schemaError(name, val)\\n }\\n\\n if (isFunction(val.normalize)) {\\n compiled.normalize = val.normalize\\n } else if (!val.normalize) {\\n compiled.normalize = createNormalizer()\\n } else {\\n schemaError(name, val)\\n }\\n\\n return\\n }\\n\\n if (isString(val)) {\\n aliases.push(name)\\n return\\n }\\n\\n schemaError(name, val)\\n })\\n\\n //\\n // Compile postponed aliases\\n //\\n\\n aliases.forEach(function (alias) {\\n if (!self.__compiled__[self.__schemas__[alias]]) {\\n // Silently fail on missed schemas to avoid errons on disable.\\n // schemaError(alias, self.__schemas__[alias]);\\n return\\n }\\n\\n self.__compiled__[alias].validate =\\n self.__compiled__[self.__schemas__[alias]].validate\\n self.__compiled__[alias].normalize =\\n self.__compiled__[self.__schemas__[alias]].normalize\\n })\\n\\n //\\n // Fake record for guessed links\\n //\\n self.__compiled__[''] = { validate: null, normalize: createNormalizer() }\\n\\n //\\n // Build schema condition\\n //\\n const slist = Object.keys(self.__compiled__)\\n .filter(function (name) {\\n // Filter disabled & fake schemas\\n return name.length > 0 && self.__compiled__[name]\\n })\\n .map(escapeRE)\\n .join('|')\\n // (?!_) cause 1.5x slowdown\\n self.re.schema_test = RegExp('(^|(?!_)(?:[><\\\\uff5c]|' + re.src_ZPCc + '))(' + slist + ')', 'i')\\n self.re.schema_search = RegExp('(^|(?!_)(?:[><\\\\uff5c]|' + re.src_ZPCc + '))(' + slist + ')', 'ig')\\n self.re.schema_at_start = RegExp('^' + self.re.schema_search.source, 'i')\\n\\n self.re.pretest = RegExp(\\n '(' + self.re.schema_test.source + ')|(' + self.re.host_fuzzy_test.source + ')|@',\\n 'i'\\n )\\n\\n //\\n // Cleanup\\n //\\n\\n resetScanCache(self)\\n}\\n\\n/**\\n * class Match\\n *\\n * Match result. Single element of array, returned by [[LinkifyIt#match]]\\n **/\\nfunction Match (self, shift) {\\n const start = self.__index__\\n const end = self.__last_index__\\n const text = self.__text_cache__.slice(start, end)\\n\\n /**\\n * Match#schema -> String\\n *\\n * Prefix (protocol) for matched string.\\n **/\\n this.schema = self.__schema__.toLowerCase()\\n /**\\n * Match#index -> Number\\n *\\n * First position of matched string.\\n **/\\n this.index = start + shift\\n /**\\n * Match#lastIndex -> Number\\n *\\n * Next position after matched string.\\n **/\\n this.lastIndex = end + shift\\n /**\\n * Match#raw -> String\\n *\\n * Matched string.\\n **/\\n this.raw = text\\n /**\\n * Match#text -> String\\n *\\n * Notmalized text of matched string.\\n **/\\n this.text = text\\n /**\\n * Match#url -> String\\n *\\n * Normalized url of matched string.\\n **/\\n this.url = text\\n}\\n\\nfunction createMatch (self, shift) {\\n const match = new Match(self, shift)\\n\\n self.__compiled__[match.schema].normalize(match, self)\\n\\n return match\\n}\\n\\n/**\\n * class LinkifyIt\\n **/\\n\\n/**\\n * new LinkifyIt(schemas, options)\\n * - schemas (Object): Optional. Additional schemas to validate (prefix/validator)\\n * - options (Object): { fuzzyLink|fuzzyEmail|fuzzyIP: true|false }\\n *\\n * Creates new linkifier instance with optional additional schemas.\\n * Can be called without `new` keyword for convenience.\\n *\\n * By default understands:\\n *\\n * - `http(s)://...` , `ftp://...`, `mailto:...` & `//...` links\\n * - \\\"fuzzy\\\" links and emails (example.com, foo@bar.com).\\n *\\n * `schemas` is an object, where each key/value describes protocol/rule:\\n *\\n * - __key__ - link prefix (usually, protocol name with `:` at the end, `skype:`\\n * for example). `linkify-it` makes shure that prefix is not preceeded with\\n * alphanumeric char and symbols. Only whitespaces and punctuation allowed.\\n * - __value__ - rule to check tail after link prefix\\n * - _String_ - just alias to existing rule\\n * - _Object_\\n * - _validate_ - validator function (should return matched length on success),\\n * or `RegExp`.\\n * - _normalize_ - optional function to normalize text & url of matched result\\n * (for example, for @twitter mentions).\\n *\\n * `options`:\\n *\\n * - __fuzzyLink__ - recognige URL-s without `http(s):` prefix. Default `true`.\\n * - __fuzzyIP__ - allow IPs in fuzzy links above. Can conflict with some texts\\n * like version numbers. Default `false`.\\n * - __fuzzyEmail__ - recognize emails without `mailto:` prefix.\\n *\\n **/\\nfunction LinkifyIt (schemas, options) {\\n if (!(this instanceof LinkifyIt)) {\\n return new LinkifyIt(schemas, options)\\n }\\n\\n if (!options) {\\n if (isOptionsObj(schemas)) {\\n options = schemas\\n schemas = {}\\n }\\n }\\n\\n this.__opts__ = assign({}, defaultOptions, options)\\n\\n // Cache last tested result. Used to skip repeating steps on next `match` call.\\n this.__index__ = -1\\n this.__last_index__ = -1 // Next scan position\\n this.__schema__ = ''\\n this.__text_cache__ = ''\\n\\n this.__schemas__ = assign({}, defaultSchemas, schemas)\\n this.__compiled__ = {}\\n\\n this.__tlds__ = tlds_default\\n this.__tlds_replaced__ = false\\n\\n this.re = {}\\n\\n compile(this)\\n}\\n\\n/** chainable\\n * LinkifyIt#add(schema, definition)\\n * - schema (String): rule name (fixed pattern prefix)\\n * - definition (String|RegExp|Object): schema definition\\n *\\n * Add new rule definition. See constructor description for details.\\n **/\\nLinkifyIt.prototype.add = function add (schema, definition) {\\n this.__schemas__[schema] = definition\\n compile(this)\\n return this\\n}\\n\\n/** chainable\\n * LinkifyIt#set(options)\\n * - options (Object): { fuzzyLink|fuzzyEmail|fuzzyIP: true|false }\\n *\\n * Set recognition options for links without schema.\\n **/\\nLinkifyIt.prototype.set = function set (options) {\\n this.__opts__ = assign(this.__opts__, options)\\n return this\\n}\\n\\n/**\\n * LinkifyIt#test(text) -> Boolean\\n *\\n * Searches linkifiable pattern and returns `true` on success or `false` on fail.\\n **/\\nLinkifyIt.prototype.test = function test (text) {\\n // Reset scan cache\\n this.__text_cache__ = text\\n this.__index__ = -1\\n\\n if (!text.length) { return false }\\n\\n let m, ml, me, len, shift, next, re, tld_pos, at_pos\\n\\n // try to scan for link with schema - that's the most simple rule\\n if (this.re.schema_test.test(text)) {\\n re = this.re.schema_search\\n re.lastIndex = 0\\n while ((m = re.exec(text)) !== null) {\\n len = this.testSchemaAt(text, m[2], re.lastIndex)\\n if (len) {\\n this.__schema__ = m[2]\\n this.__index__ = m.index + m[1].length\\n this.__last_index__ = m.index + m[0].length + len\\n break\\n }\\n }\\n }\\n\\n if (this.__opts__.fuzzyLink && this.__compiled__['http:']) {\\n // guess schemaless links\\n tld_pos = text.search(this.re.host_fuzzy_test)\\n if (tld_pos >= 0) {\\n // if tld is located after found link - no need to check fuzzy pattern\\n if (this.__index__ < 0 || tld_pos < this.__index__) {\\n if ((ml = text.match(this.__opts__.fuzzyIP ? this.re.link_fuzzy : this.re.link_no_ip_fuzzy)) !== null) {\\n shift = ml.index + ml[1].length\\n\\n if (this.__index__ < 0 || shift < this.__index__) {\\n this.__schema__ = ''\\n this.__index__ = shift\\n this.__last_index__ = ml.index + ml[0].length\\n }\\n }\\n }\\n }\\n }\\n\\n if (this.__opts__.fuzzyEmail && this.__compiled__['mailto:']) {\\n // guess schemaless emails\\n at_pos = text.indexOf('@')\\n if (at_pos >= 0) {\\n // We can't skip this check, because this cases are possible:\\n // 192.168.1.1@gmail.com, my.in@example.com\\n if ((me = text.match(this.re.email_fuzzy)) !== null) {\\n shift = me.index + me[1].length\\n next = me.index + me[0].length\\n\\n if (this.__index__ < 0 || shift < this.__index__ ||\\n (shift === this.__index__ && next > this.__last_index__)) {\\n this.__schema__ = 'mailto:'\\n this.__index__ = shift\\n this.__last_index__ = next\\n }\\n }\\n }\\n }\\n\\n return this.__index__ >= 0\\n}\\n\\n/**\\n * LinkifyIt#pretest(text) -> Boolean\\n *\\n * Very quick check, that can give false positives. Returns true if link MAY BE\\n * can exists. Can be used for speed optimization, when you need to check that\\n * link NOT exists.\\n **/\\nLinkifyIt.prototype.pretest = function pretest (text) {\\n return this.re.pretest.test(text)\\n}\\n\\n/**\\n * LinkifyIt#testSchemaAt(text, name, position) -> Number\\n * - text (String): text to scan\\n * - name (String): rule (schema) name\\n * - position (Number): text offset to check from\\n *\\n * Similar to [[LinkifyIt#test]] but checks only specific protocol tail exactly\\n * at given position. Returns length of found pattern (0 on fail).\\n **/\\nLinkifyIt.prototype.testSchemaAt = function testSchemaAt (text, schema, pos) {\\n // If not supported schema check requested - terminate\\n if (!this.__compiled__[schema.toLowerCase()]) {\\n return 0\\n }\\n return this.__compiled__[schema.toLowerCase()].validate(text, pos, this)\\n}\\n\\n/**\\n * LinkifyIt#match(text) -> Array|null\\n *\\n * Returns array of found link descriptions or `null` on fail. We strongly\\n * recommend to use [[LinkifyIt#test]] first, for best speed.\\n *\\n * ##### Result match description\\n *\\n * - __schema__ - link schema, can be empty for fuzzy links, or `//` for\\n * protocol-neutral links.\\n * - __index__ - offset of matched text\\n * - __lastIndex__ - index of next char after mathch end\\n * - __raw__ - matched text\\n * - __text__ - normalized text\\n * - __url__ - link, generated from matched text\\n **/\\nLinkifyIt.prototype.match = function match (text) {\\n const result = []\\n let shift = 0\\n\\n // Try to take previous element from cache, if .test() called before\\n if (this.__index__ >= 0 && this.__text_cache__ === text) {\\n result.push(createMatch(this, shift))\\n shift = this.__last_index__\\n }\\n\\n // Cut head if cache was used\\n let tail = shift ? text.slice(shift) : text\\n\\n // Scan string until end reached\\n while (this.test(tail)) {\\n result.push(createMatch(this, shift))\\n\\n tail = tail.slice(this.__last_index__)\\n shift += this.__last_index__\\n }\\n\\n if (result.length) {\\n return result\\n }\\n\\n return null\\n}\\n\\n/**\\n * LinkifyIt#matchAtStart(text) -> Match|null\\n *\\n * Returns fully-formed (not fuzzy) link if it starts at the beginning\\n * of the string, and null otherwise.\\n **/\\nLinkifyIt.prototype.matchAtStart = function matchAtStart (text) {\\n // Reset scan cache\\n this.__text_cache__ = text\\n this.__index__ = -1\\n\\n if (!text.length) return null\\n\\n const m = this.re.schema_at_start.exec(text)\\n if (!m) return null\\n\\n const len = this.testSchemaAt(text, m[2], m[0].length)\\n if (!len) return null\\n\\n this.__schema__ = m[2]\\n this.__index__ = m.index + m[1].length\\n this.__last_index__ = m.index + m[0].length + len\\n\\n return createMatch(this, 0)\\n}\\n\\n/** chainable\\n * LinkifyIt#tlds(list [, keepOld]) -> this\\n * - list (Array): list of tlds\\n * - keepOld (Boolean): merge with current list if `true` (`false` by default)\\n *\\n * Load (or merge) new tlds list. Those are user for fuzzy links (without prefix)\\n * to avoid false positives. By default this algorythm used:\\n *\\n * - hostname with any 2-letter root zones are ok.\\n * - biz|com|edu|gov|net|org|pro|web|xxx|aero|asia|coop|info|museum|name|shop|рф\\n * are ok.\\n * - encoded (`xn--...`) root zones are ok.\\n *\\n * If list is replaced, then exact match for 2-chars root zones will be checked.\\n **/\\nLinkifyIt.prototype.tlds = function tlds (list, keepOld) {\\n list = Array.isArray(list) ? list : [list]\\n\\n if (!keepOld) {\\n this.__tlds__ = list.slice()\\n this.__tlds_replaced__ = true\\n compile(this)\\n return this\\n }\\n\\n this.__tlds__ = this.__tlds__.concat(list)\\n .sort()\\n .filter(function (el, idx, arr) {\\n return el !== arr[idx - 1]\\n })\\n .reverse()\\n\\n compile(this)\\n return this\\n}\\n\\n/**\\n * LinkifyIt#normalize(match)\\n *\\n * Default normalizer (if schema does not define it's own).\\n **/\\nLinkifyIt.prototype.normalize = function normalize (match) {\\n // Do minimal possible changes by default. Need to collect feedback prior\\n // to move forward https://github.com/markdown-it/linkify-it/issues/1\\n\\n if (!match.schema) { match.url = 'http://' + match.url }\\n\\n if (match.schema === 'mailto:' && !/^mailto:/i.test(match.url)) {\\n match.url = 'mailto:' + match.url\\n }\\n}\\n\\n/**\\n * LinkifyIt#onCompile()\\n *\\n * Override to modify basic RegExp-s.\\n **/\\nLinkifyIt.prototype.onCompile = function onCompile () {\\n}\\n\\nexport default LinkifyIt\\n\",\"// Utilities\\n//\\n\\nimport * as mdurl from 'mdurl'\\nimport * as ucmicro from 'uc.micro'\\nimport { decodeHTML } from 'entities'\\n\\nfunction _class (obj) { return Object.prototype.toString.call(obj) }\\n\\nfunction isString (obj) { return _class(obj) === '[object String]' }\\n\\nconst _hasOwnProperty = Object.prototype.hasOwnProperty\\n\\nfunction has (object, key) {\\n return _hasOwnProperty.call(object, key)\\n}\\n\\n// Merge objects\\n//\\nfunction assign (obj /* from1, from2, from3, ... */) {\\n const sources = Array.prototype.slice.call(arguments, 1)\\n\\n sources.forEach(function (source) {\\n if (!source) { return }\\n\\n if (typeof source !== 'object') {\\n throw new TypeError(source + 'must be object')\\n }\\n\\n Object.keys(source).forEach(function (key) {\\n obj[key] = source[key]\\n })\\n })\\n\\n return obj\\n}\\n\\n// Remove element from array and put another array at those position.\\n// Useful for some operations with tokens\\nfunction arrayReplaceAt (src, pos, newElements) {\\n return [].concat(src.slice(0, pos), newElements, src.slice(pos + 1))\\n}\\n\\nfunction isValidEntityCode (c) {\\n /* eslint no-bitwise:0 */\\n // broken sequence\\n if (c >= 0xD800 && c <= 0xDFFF) { return false }\\n // never used\\n if (c >= 0xFDD0 && c <= 0xFDEF) { return false }\\n if ((c & 0xFFFF) === 0xFFFF || (c & 0xFFFF) === 0xFFFE) { return false }\\n // control codes\\n if (c >= 0x00 && c <= 0x08) { return false }\\n if (c === 0x0B) { return false }\\n if (c >= 0x0E && c <= 0x1F) { return false }\\n if (c >= 0x7F && c <= 0x9F) { return false }\\n // out of range\\n if (c > 0x10FFFF) { return false }\\n return true\\n}\\n\\nfunction fromCodePoint (c) {\\n /* eslint no-bitwise:0 */\\n if (c > 0xffff) {\\n c -= 0x10000\\n const surrogate1 = 0xd800 + (c >> 10)\\n const surrogate2 = 0xdc00 + (c & 0x3ff)\\n\\n return String.fromCharCode(surrogate1, surrogate2)\\n }\\n return String.fromCharCode(c)\\n}\\n\\nconst UNESCAPE_MD_RE = /\\\\\\\\([!\\\"#$%&'()*+,\\\\-./:;<=>?@[\\\\\\\\\\\\]^_`{|}~])/g\\nconst ENTITY_RE = /&([a-z#][a-z0-9]{1,31});/gi\\nconst UNESCAPE_ALL_RE = new RegExp(UNESCAPE_MD_RE.source + '|' + ENTITY_RE.source, 'gi')\\n\\nconst DIGITAL_ENTITY_TEST_RE = /^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))$/i\\n\\nfunction replaceEntityPattern (match, name) {\\n if (name.charCodeAt(0) === 0x23/* # */ && DIGITAL_ENTITY_TEST_RE.test(name)) {\\n const code = name[1].toLowerCase() === 'x'\\n ? parseInt(name.slice(2), 16)\\n : parseInt(name.slice(1), 10)\\n\\n if (isValidEntityCode(code)) {\\n return fromCodePoint(code)\\n }\\n\\n return match\\n }\\n\\n const decoded = decodeHTML(match)\\n if (decoded !== match) {\\n return decoded\\n }\\n\\n return match\\n}\\n\\n/* function replaceEntities(str) {\\n if (str.indexOf('&') < 0) { return str; }\\n\\n return str.replace(ENTITY_RE, replaceEntityPattern);\\n} */\\n\\nfunction unescapeMd (str) {\\n if (str.indexOf('\\\\\\\\') < 0) { return str }\\n return str.replace(UNESCAPE_MD_RE, '$1')\\n}\\n\\nfunction unescapeAll (str) {\\n if (str.indexOf('\\\\\\\\') < 0 && str.indexOf('&') < 0) { return str }\\n\\n return str.replace(UNESCAPE_ALL_RE, function (match, escaped, entity) {\\n if (escaped) { return escaped }\\n return replaceEntityPattern(match, entity)\\n })\\n}\\n\\nconst HTML_ESCAPE_TEST_RE = /[&<>\\\"]/\\nconst HTML_ESCAPE_REPLACE_RE = /[&<>\\\"]/g\\nconst HTML_REPLACEMENTS = {\\n '&': '&',\\n '<': '<',\\n '>': '>',\\n '\\\"': '"'\\n}\\n\\nfunction replaceUnsafeChar (ch) {\\n return HTML_REPLACEMENTS[ch]\\n}\\n\\nfunction escapeHtml (str) {\\n if (HTML_ESCAPE_TEST_RE.test(str)) {\\n return str.replace(HTML_ESCAPE_REPLACE_RE, replaceUnsafeChar)\\n }\\n return str\\n}\\n\\nconst REGEXP_ESCAPE_RE = /[.?*+^$[\\\\]\\\\\\\\(){}|-]/g\\n\\nfunction escapeRE (str) {\\n return str.replace(REGEXP_ESCAPE_RE, '\\\\\\\\$&')\\n}\\n\\nfunction isSpace (code) {\\n switch (code) {\\n case 0x09:\\n case 0x20:\\n return true\\n }\\n return false\\n}\\n\\n// Zs (unicode class) || [\\\\t\\\\f\\\\v\\\\r\\\\n]\\nfunction isWhiteSpace (code) {\\n if (code >= 0x2000 && code <= 0x200A) { return true }\\n switch (code) {\\n case 0x09: // \\\\t\\n case 0x0A: // \\\\n\\n case 0x0B: // \\\\v\\n case 0x0C: // \\\\f\\n case 0x0D: // \\\\r\\n case 0x20:\\n case 0xA0:\\n case 0x1680:\\n case 0x202F:\\n case 0x205F:\\n case 0x3000:\\n return true\\n }\\n return false\\n}\\n\\n/* eslint-disable max-len */\\n\\n// Currently without astral characters support.\\nfunction isPunctChar (ch) {\\n return ucmicro.P.test(ch) || ucmicro.S.test(ch)\\n}\\n\\n// Markdown ASCII punctuation characters.\\n//\\n// !, \\\", #, $, %, &, ', (, ), *, +, ,, -, ., /, :, ;, <, =, >, ?, @, [, \\\\, ], ^, _, `, {, |, }, or ~\\n// http://spec.commonmark.org/0.15/#ascii-punctuation-character\\n//\\n// Don't confuse with unicode punctuation !!! It lacks some chars in ascii range.\\n//\\nfunction isMdAsciiPunct (ch) {\\n switch (ch) {\\n case 0x21/* ! */:\\n case 0x22/* \\\" */:\\n case 0x23/* # */:\\n case 0x24/* $ */:\\n case 0x25/* % */:\\n case 0x26/* & */:\\n case 0x27/* ' */:\\n case 0x28/* ( */:\\n case 0x29/* ) */:\\n case 0x2A/* * */:\\n case 0x2B/* + */:\\n case 0x2C/* , */:\\n case 0x2D/* - */:\\n case 0x2E/* . */:\\n case 0x2F/* / */:\\n case 0x3A/* : */:\\n case 0x3B/* ; */:\\n case 0x3C/* < */:\\n case 0x3D/* = */:\\n case 0x3E/* > */:\\n case 0x3F/* ? */:\\n case 0x40/* @ */:\\n case 0x5B/* [ */:\\n case 0x5C/* \\\\ */:\\n case 0x5D/* ] */:\\n case 0x5E/* ^ */:\\n case 0x5F/* _ */:\\n case 0x60/* ` */:\\n case 0x7B/* { */:\\n case 0x7C/* | */:\\n case 0x7D/* } */:\\n case 0x7E/* ~ */:\\n return true\\n default:\\n return false\\n }\\n}\\n\\n// Hepler to unify [reference labels].\\n//\\nfunction normalizeReference (str) {\\n // Trim and collapse whitespace\\n //\\n str = str.trim().replace(/\\\\s+/g, ' ')\\n\\n // In node v10 'ẞ'.toLowerCase() === 'Ṿ', which is presumed to be a bug\\n // fixed in v12 (couldn't find any details).\\n //\\n // So treat this one as a special case\\n // (remove this when node v10 is no longer supported).\\n //\\n if ('ẞ'.toLowerCase() === 'Ṿ') {\\n str = str.replace(/ẞ/g, 'ß')\\n }\\n\\n // .toLowerCase().toUpperCase() should get rid of all differences\\n // between letter variants.\\n //\\n // Simple .toLowerCase() doesn't normalize 125 code points correctly,\\n // and .toUpperCase doesn't normalize 6 of them (list of exceptions:\\n // İ, ϴ, ẞ, Ω, K, Å - those are already uppercased, but have differently\\n // uppercased versions).\\n //\\n // Here's an example showing how it happens. Lets take greek letter omega:\\n // uppercase U+0398 (Θ), U+03f4 (ϴ) and lowercase U+03b8 (θ), U+03d1 (ϑ)\\n //\\n // Unicode entries:\\n // 0398;GREEK CAPITAL LETTER THETA;Lu;0;L;;;;;N;;;;03B8;\\n // 03B8;GREEK SMALL LETTER THETA;Ll;0;L;;;;;N;;;0398;;0398\\n // 03D1;GREEK THETA SYMBOL;Ll;0;L; 03B8;;;;N;GREEK SMALL LETTER SCRIPT THETA;;0398;;0398\\n // 03F4;GREEK CAPITAL THETA SYMBOL;Lu;0;L; 0398;;;;N;;;;03B8;\\n //\\n // Case-insensitive comparison should treat all of them as equivalent.\\n //\\n // But .toLowerCase() doesn't change ϑ (it's already lowercase),\\n // and .toUpperCase() doesn't change ϴ (already uppercase).\\n //\\n // Applying first lower then upper case normalizes any character:\\n // '\\\\u0398\\\\u03f4\\\\u03b8\\\\u03d1'.toLowerCase().toUpperCase() === '\\\\u0398\\\\u0398\\\\u0398\\\\u0398'\\n //\\n // Note: this is equivalent to unicode case folding; unicode normalization\\n // is a different step that is not required here.\\n //\\n // Final result should be uppercased, because it's later stored in an object\\n // (this avoid a conflict with Object.prototype members,\\n // most notably, `__proto__`)\\n //\\n return str.toLowerCase().toUpperCase()\\n}\\n\\n// Re-export libraries commonly used in both markdown-it and its plugins,\\n// so plugins won't have to depend on them explicitly, which reduces their\\n// bundled size (e.g. a browser build).\\n//\\nconst lib = { mdurl, ucmicro }\\n\\nexport {\\n lib,\\n assign,\\n isString,\\n has,\\n unescapeMd,\\n unescapeAll,\\n isValidEntityCode,\\n fromCodePoint,\\n escapeHtml,\\n arrayReplaceAt,\\n isSpace,\\n isWhiteSpace,\\n isMdAsciiPunct,\\n isPunctChar,\\n escapeRE,\\n normalizeReference\\n}\\n\",\"import decode from './lib/decode.mjs'\\nimport encode from './lib/encode.mjs'\\nimport format from './lib/format.mjs'\\nimport parse from './lib/parse.mjs'\\n\\nexport {\\n decode,\\n encode,\\n format,\\n parse\\n}\\n\",\"/* eslint-disable no-bitwise */\\n\\nconst decodeCache = {}\\n\\nfunction getDecodeCache (exclude) {\\n let cache = decodeCache[exclude]\\n if (cache) { return cache }\\n\\n cache = decodeCache[exclude] = []\\n\\n for (let i = 0; i < 128; i++) {\\n const ch = String.fromCharCode(i)\\n cache.push(ch)\\n }\\n\\n for (let i = 0; i < exclude.length; i++) {\\n const ch = exclude.charCodeAt(i)\\n cache[ch] = '%' + ('0' + ch.toString(16).toUpperCase()).slice(-2)\\n }\\n\\n return cache\\n}\\n\\n// Decode percent-encoded string.\\n//\\nfunction decode (string, exclude) {\\n if (typeof exclude !== 'string') {\\n exclude = decode.defaultChars\\n }\\n\\n const cache = getDecodeCache(exclude)\\n\\n return string.replace(/(%[a-f0-9]{2})+/gi, function (seq) {\\n let result = ''\\n\\n for (let i = 0, l = seq.length; i < l; i += 3) {\\n const b1 = parseInt(seq.slice(i + 1, i + 3), 16)\\n\\n if (b1 < 0x80) {\\n result += cache[b1]\\n continue\\n }\\n\\n if ((b1 & 0xE0) === 0xC0 && (i + 3 < l)) {\\n // 110xxxxx 10xxxxxx\\n const b2 = parseInt(seq.slice(i + 4, i + 6), 16)\\n\\n if ((b2 & 0xC0) === 0x80) {\\n const chr = ((b1 << 6) & 0x7C0) | (b2 & 0x3F)\\n\\n if (chr < 0x80) {\\n result += '\\\\ufffd\\\\ufffd'\\n } else {\\n result += String.fromCharCode(chr)\\n }\\n\\n i += 3\\n continue\\n }\\n }\\n\\n if ((b1 & 0xF0) === 0xE0 && (i + 6 < l)) {\\n // 1110xxxx 10xxxxxx 10xxxxxx\\n const b2 = parseInt(seq.slice(i + 4, i + 6), 16)\\n const b3 = parseInt(seq.slice(i + 7, i + 9), 16)\\n\\n if ((b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80) {\\n const chr = ((b1 << 12) & 0xF000) | ((b2 << 6) & 0xFC0) | (b3 & 0x3F)\\n\\n if (chr < 0x800 || (chr >= 0xD800 && chr <= 0xDFFF)) {\\n result += '\\\\ufffd\\\\ufffd\\\\ufffd'\\n } else {\\n result += String.fromCharCode(chr)\\n }\\n\\n i += 6\\n continue\\n }\\n }\\n\\n if ((b1 & 0xF8) === 0xF0 && (i + 9 < l)) {\\n // 111110xx 10xxxxxx 10xxxxxx 10xxxxxx\\n const b2 = parseInt(seq.slice(i + 4, i + 6), 16)\\n const b3 = parseInt(seq.slice(i + 7, i + 9), 16)\\n const b4 = parseInt(seq.slice(i + 10, i + 12), 16)\\n\\n if ((b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80 && (b4 & 0xC0) === 0x80) {\\n let chr = ((b1 << 18) & 0x1C0000) | ((b2 << 12) & 0x3F000) | ((b3 << 6) & 0xFC0) | (b4 & 0x3F)\\n\\n if (chr < 0x10000 || chr > 0x10FFFF) {\\n result += '\\\\ufffd\\\\ufffd\\\\ufffd\\\\ufffd'\\n } else {\\n chr -= 0x10000\\n result += String.fromCharCode(0xD800 + (chr >> 10), 0xDC00 + (chr & 0x3FF))\\n }\\n\\n i += 9\\n continue\\n }\\n }\\n\\n result += '\\\\ufffd'\\n }\\n\\n return result\\n })\\n}\\n\\ndecode.defaultChars = ';/?:@&=+$,#'\\ndecode.componentChars = ''\\n\\nexport default decode\\n\",\"const encodeCache = {}\\n\\n// Create a lookup array where anything but characters in `chars` string\\n// and alphanumeric chars is percent-encoded.\\n//\\nfunction getEncodeCache (exclude) {\\n let cache = encodeCache[exclude]\\n if (cache) { return cache }\\n\\n cache = encodeCache[exclude] = []\\n\\n for (let i = 0; i < 128; i++) {\\n const ch = String.fromCharCode(i)\\n\\n if (/^[0-9a-z]$/i.test(ch)) {\\n // always allow unencoded alphanumeric characters\\n cache.push(ch)\\n } else {\\n cache.push('%' + ('0' + i.toString(16).toUpperCase()).slice(-2))\\n }\\n }\\n\\n for (let i = 0; i < exclude.length; i++) {\\n cache[exclude.charCodeAt(i)] = exclude[i]\\n }\\n\\n return cache\\n}\\n\\n// Encode unsafe characters with percent-encoding, skipping already\\n// encoded sequences.\\n//\\n// - string - string to encode\\n// - exclude - list of characters to ignore (in addition to a-zA-Z0-9)\\n// - keepEscaped - don't encode '%' in a correct escape sequence (default: true)\\n//\\nfunction encode (string, exclude, keepEscaped) {\\n if (typeof exclude !== 'string') {\\n // encode(string, keepEscaped)\\n keepEscaped = exclude\\n exclude = encode.defaultChars\\n }\\n\\n if (typeof keepEscaped === 'undefined') {\\n keepEscaped = true\\n }\\n\\n const cache = getEncodeCache(exclude)\\n let result = ''\\n\\n for (let i = 0, l = string.length; i < l; i++) {\\n const code = string.charCodeAt(i)\\n\\n if (keepEscaped && code === 0x25 /* % */ && i + 2 < l) {\\n if (/^[0-9a-f]{2}$/i.test(string.slice(i + 1, i + 3))) {\\n result += string.slice(i, i + 3)\\n i += 2\\n continue\\n }\\n }\\n\\n if (code < 128) {\\n result += cache[code]\\n continue\\n }\\n\\n if (code >= 0xD800 && code <= 0xDFFF) {\\n if (code >= 0xD800 && code <= 0xDBFF && i + 1 < l) {\\n const nextCode = string.charCodeAt(i + 1)\\n if (nextCode >= 0xDC00 && nextCode <= 0xDFFF) {\\n result += encodeURIComponent(string[i] + string[i + 1])\\n i++\\n continue\\n }\\n }\\n result += '%EF%BF%BD'\\n continue\\n }\\n\\n result += encodeURIComponent(string[i])\\n }\\n\\n return result\\n}\\n\\nencode.defaultChars = \\\";/?:@&=+$,-_.!~*'()#\\\"\\nencode.componentChars = \\\"-_.!~*'()\\\"\\n\\nexport default encode\\n\",\"export default function format (url) {\\n let result = ''\\n\\n result += url.protocol || ''\\n result += url.slashes ? '//' : ''\\n result += url.auth ? url.auth + '@' : ''\\n\\n if (url.hostname && url.hostname.indexOf(':') !== -1) {\\n // ipv6 address\\n result += '[' + url.hostname + ']'\\n } else {\\n result += url.hostname || ''\\n }\\n\\n result += url.port ? ':' + url.port : ''\\n result += url.pathname || ''\\n result += url.search || ''\\n result += url.hash || ''\\n\\n return result\\n};\\n\",\"// Copyright Joyent, Inc. and other Node contributors.\\n//\\n// Permission is hereby granted, free of charge, to any person obtaining a\\n// copy of this software and associated documentation files (the\\n// \\\"Software\\\"), to deal in the Software without restriction, including\\n// without limitation the rights to use, copy, modify, merge, publish,\\n// distribute, sublicense, and/or sell copies of the Software, and to permit\\n// persons to whom the Software is furnished to do so, subject to the\\n// following conditions:\\n//\\n// The above copyright notice and this permission notice shall be included\\n// in all copies or substantial portions of the Software.\\n//\\n// THE SOFTWARE IS PROVIDED \\\"AS IS\\\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\\n\\n//\\n// Changes from joyent/node:\\n//\\n// 1. No leading slash in paths,\\n// e.g. in `url.parse('http://foo?bar')` pathname is ``, not `/`\\n//\\n// 2. Backslashes are not replaced with slashes,\\n// so `http:\\\\\\\\example.org\\\\` is treated like a relative path\\n//\\n// 3. Trailing colon is treated like a part of the path,\\n// i.e. in `http://example.org:foo` pathname is `:foo`\\n//\\n// 4. Nothing is URL-encoded in the resulting object,\\n// (in joyent/node some chars in auth and paths are encoded)\\n//\\n// 5. `url.parse()` does not have `parseQueryString` argument\\n//\\n// 6. Removed extraneous result properties: `host`, `path`, `query`, etc.,\\n// which can be constructed using other parts of the url.\\n//\\n\\nfunction Url () {\\n this.protocol = null\\n this.slashes = null\\n this.auth = null\\n this.port = null\\n this.hostname = null\\n this.hash = null\\n this.search = null\\n this.pathname = null\\n}\\n\\n// Reference: RFC 3986, RFC 1808, RFC 2396\\n\\n// define these here so at least they only have to be\\n// compiled once on the first module load.\\nconst protocolPattern = /^([a-z0-9.+-]+:)/i\\nconst portPattern = /:[0-9]*$/\\n\\n// Special case for a simple path URL\\n/* eslint-disable-next-line no-useless-escape */\\nconst simplePathPattern = /^(\\\\/\\\\/?(?!\\\\/)[^\\\\?\\\\s]*)(\\\\?[^\\\\s]*)?$/\\n\\n// RFC 2396: characters reserved for delimiting URLs.\\n// We actually just auto-escape these.\\nconst delims = ['<', '>', '\\\"', '`', ' ', '\\\\r', '\\\\n', '\\\\t']\\n\\n// RFC 2396: characters not allowed for various reasons.\\nconst unwise = ['{', '}', '|', '\\\\\\\\', '^', '`'].concat(delims)\\n\\n// Allowed by RFCs, but cause of XSS attacks. Always escape these.\\nconst autoEscape = ['\\\\''].concat(unwise)\\n// Characters that are never ever allowed in a hostname.\\n// Note that any invalid chars are also handled, but these\\n// are the ones that are *expected* to be seen, so we fast-path\\n// them.\\nconst nonHostChars = ['%', '/', '?', ';', '#'].concat(autoEscape)\\nconst hostEndingChars = ['/', '?', '#']\\nconst hostnameMaxLen = 255\\nconst hostnamePartPattern = /^[+a-z0-9A-Z_-]{0,63}$/\\nconst hostnamePartStart = /^([+a-z0-9A-Z_-]{0,63})(.*)$/\\n// protocols that can allow \\\"unsafe\\\" and \\\"unwise\\\" chars.\\n// protocols that never have a hostname.\\nconst hostlessProtocol = {\\n javascript: true,\\n 'javascript:': true\\n}\\n// protocols that always contain a // bit.\\nconst slashedProtocol = {\\n http: true,\\n https: true,\\n ftp: true,\\n gopher: true,\\n file: true,\\n 'http:': true,\\n 'https:': true,\\n 'ftp:': true,\\n 'gopher:': true,\\n 'file:': true\\n}\\n\\nfunction urlParse (url, slashesDenoteHost) {\\n if (url && url instanceof Url) return url\\n\\n const u = new Url()\\n u.parse(url, slashesDenoteHost)\\n return u\\n}\\n\\nUrl.prototype.parse = function (url, slashesDenoteHost) {\\n let lowerProto, hec, slashes\\n let rest = url\\n\\n // trim before proceeding.\\n // This is to support parse stuff like \\\" http://foo.com \\\\n\\\"\\n rest = rest.trim()\\n\\n if (!slashesDenoteHost && url.split('#').length === 1) {\\n // Try fast path regexp\\n const simplePath = simplePathPattern.exec(rest)\\n if (simplePath) {\\n this.pathname = simplePath[1]\\n if (simplePath[2]) {\\n this.search = simplePath[2]\\n }\\n return this\\n }\\n }\\n\\n let proto = protocolPattern.exec(rest)\\n if (proto) {\\n proto = proto[0]\\n lowerProto = proto.toLowerCase()\\n this.protocol = proto\\n rest = rest.substr(proto.length)\\n }\\n\\n // figure out if it's got a host\\n // user@server is *always* interpreted as a hostname, and url\\n // resolution will treat //foo/bar as host=foo,path=bar because that's\\n // how the browser resolves relative URLs.\\n /* eslint-disable-next-line no-useless-escape */\\n if (slashesDenoteHost || proto || rest.match(/^\\\\/\\\\/[^@\\\\/]+@[^@\\\\/]+/)) {\\n slashes = rest.substr(0, 2) === '//'\\n if (slashes && !(proto && hostlessProtocol[proto])) {\\n rest = rest.substr(2)\\n this.slashes = true\\n }\\n }\\n\\n if (!hostlessProtocol[proto] &&\\n (slashes || (proto && !slashedProtocol[proto]))) {\\n // there's a hostname.\\n // the first instance of /, ?, ;, or # ends the host.\\n //\\n // If there is an @ in the hostname, then non-host chars *are* allowed\\n // to the left of the last @ sign, unless some host-ending character\\n // comes *before* the @-sign.\\n // URLs are obnoxious.\\n //\\n // ex:\\n // http://a@b@c/ => user:a@b host:c\\n // http://a@b?@c => user:a host:c path:/?@c\\n\\n // v0.12 TODO(isaacs): This is not quite how Chrome does things.\\n // Review our test case against browsers more comprehensively.\\n\\n // find the first instance of any hostEndingChars\\n let hostEnd = -1\\n for (let i = 0; i < hostEndingChars.length; i++) {\\n hec = rest.indexOf(hostEndingChars[i])\\n if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) {\\n hostEnd = hec\\n }\\n }\\n\\n // at this point, either we have an explicit point where the\\n // auth portion cannot go past, or the last @ char is the decider.\\n let auth, atSign\\n if (hostEnd === -1) {\\n // atSign can be anywhere.\\n atSign = rest.lastIndexOf('@')\\n } else {\\n // atSign must be in auth portion.\\n // http://a@b/c@d => host:b auth:a path:/c@d\\n atSign = rest.lastIndexOf('@', hostEnd)\\n }\\n\\n // Now we have a portion which is definitely the auth.\\n // Pull that off.\\n if (atSign !== -1) {\\n auth = rest.slice(0, atSign)\\n rest = rest.slice(atSign + 1)\\n this.auth = auth\\n }\\n\\n // the host is the remaining to the left of the first non-host char\\n hostEnd = -1\\n for (let i = 0; i < nonHostChars.length; i++) {\\n hec = rest.indexOf(nonHostChars[i])\\n if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) {\\n hostEnd = hec\\n }\\n }\\n // if we still have not hit it, then the entire thing is a host.\\n if (hostEnd === -1) {\\n hostEnd = rest.length\\n }\\n\\n if (rest[hostEnd - 1] === ':') { hostEnd-- }\\n const host = rest.slice(0, hostEnd)\\n rest = rest.slice(hostEnd)\\n\\n // pull out port.\\n this.parseHost(host)\\n\\n // we've indicated that there is a hostname,\\n // so even if it's empty, it has to be present.\\n this.hostname = this.hostname || ''\\n\\n // if hostname begins with [ and ends with ]\\n // assume that it's an IPv6 address.\\n const ipv6Hostname = this.hostname[0] === '[' &&\\n this.hostname[this.hostname.length - 1] === ']'\\n\\n // validate a little.\\n if (!ipv6Hostname) {\\n const hostparts = this.hostname.split(/\\\\./)\\n for (let i = 0, l = hostparts.length; i < l; i++) {\\n const part = hostparts[i]\\n if (!part) { continue }\\n if (!part.match(hostnamePartPattern)) {\\n let newpart = ''\\n for (let j = 0, k = part.length; j < k; j++) {\\n if (part.charCodeAt(j) > 127) {\\n // we replace non-ASCII char with a temporary placeholder\\n // we need this to make sure size of hostname is not\\n // broken by replacing non-ASCII by nothing\\n newpart += 'x'\\n } else {\\n newpart += part[j]\\n }\\n }\\n // we test again with ASCII char only\\n if (!newpart.match(hostnamePartPattern)) {\\n const validParts = hostparts.slice(0, i)\\n const notHost = hostparts.slice(i + 1)\\n const bit = part.match(hostnamePartStart)\\n if (bit) {\\n validParts.push(bit[1])\\n notHost.unshift(bit[2])\\n }\\n if (notHost.length) {\\n rest = notHost.join('.') + rest\\n }\\n this.hostname = validParts.join('.')\\n break\\n }\\n }\\n }\\n }\\n\\n if (this.hostname.length > hostnameMaxLen) {\\n this.hostname = ''\\n }\\n\\n // strip [ and ] from the hostname\\n // the host field still retains them, though\\n if (ipv6Hostname) {\\n this.hostname = this.hostname.substr(1, this.hostname.length - 2)\\n }\\n }\\n\\n // chop off from the tail first.\\n const hash = rest.indexOf('#')\\n if (hash !== -1) {\\n // got a fragment string.\\n this.hash = rest.substr(hash)\\n rest = rest.slice(0, hash)\\n }\\n const qm = rest.indexOf('?')\\n if (qm !== -1) {\\n this.search = rest.substr(qm)\\n rest = rest.slice(0, qm)\\n }\\n if (rest) { this.pathname = rest }\\n if (slashedProtocol[lowerProto] &&\\n this.hostname && !this.pathname) {\\n this.pathname = ''\\n }\\n\\n return this\\n}\\n\\nUrl.prototype.parseHost = function (host) {\\n let port = portPattern.exec(host)\\n if (port) {\\n port = port[0]\\n if (port !== ':') {\\n this.port = port.substr(1)\\n }\\n host = host.substr(0, host.length - port.length)\\n }\\n if (host) { this.hostname = host }\\n}\\n\\nexport default urlParse\\n\",null,null,null,null,null,null,null,\"// Just a shortcut for bulk export\\n\\nimport parseLinkLabel from './parse_link_label.mjs'\\nimport parseLinkDestination from './parse_link_destination.mjs'\\nimport parseLinkTitle from './parse_link_title.mjs'\\n\\nexport {\\n parseLinkLabel,\\n parseLinkDestination,\\n parseLinkTitle\\n}\\n\",\"// Parse link label\\n//\\n// this function assumes that first character (\\\"[\\\") already matches;\\n// returns the end of the label\\n//\\n\\nexport default function parseLinkLabel (state, start, disableNested) {\\n let level, found, marker, prevPos\\n\\n const max = state.posMax\\n const oldPos = state.pos\\n\\n state.pos = start + 1\\n level = 1\\n\\n while (state.pos < max) {\\n marker = state.src.charCodeAt(state.pos)\\n if (marker === 0x5D /* ] */) {\\n level--\\n if (level === 0) {\\n found = true\\n break\\n }\\n }\\n\\n prevPos = state.pos\\n state.md.inline.skipToken(state)\\n if (marker === 0x5B /* [ */) {\\n if (prevPos === state.pos - 1) {\\n // increase level if we find text `[`, which is not a part of any token\\n level++\\n } else if (disableNested) {\\n state.pos = oldPos\\n return -1\\n }\\n }\\n }\\n\\n let labelEnd = -1\\n\\n if (found) {\\n labelEnd = state.pos\\n }\\n\\n // restore old state\\n state.pos = oldPos\\n\\n return labelEnd\\n}\\n\",\"// Parse link destination\\n//\\n\\nimport { unescapeAll } from '../common/utils.mjs'\\n\\nexport default function parseLinkDestination (str, start, max) {\\n let code\\n let pos = start\\n\\n const result = {\\n ok: false,\\n pos: 0,\\n str: ''\\n }\\n\\n if (str.charCodeAt(pos) === 0x3C /* < */) {\\n pos++\\n while (pos < max) {\\n code = str.charCodeAt(pos)\\n if (code === 0x0A /* \\\\n */) { return result }\\n if (code === 0x3C /* < */) { return result }\\n if (code === 0x3E /* > */) {\\n result.pos = pos + 1\\n result.str = unescapeAll(str.slice(start + 1, pos))\\n result.ok = true\\n return result\\n }\\n if (code === 0x5C /* \\\\ */ && pos + 1 < max) {\\n pos += 2\\n continue\\n }\\n\\n pos++\\n }\\n\\n // no closing '>'\\n return result\\n }\\n\\n // this should be ... } else { ... branch\\n\\n let level = 0\\n while (pos < max) {\\n code = str.charCodeAt(pos)\\n\\n if (code === 0x20) { break }\\n\\n // ascii control characters\\n if (code < 0x20 || code === 0x7F) { break }\\n\\n if (code === 0x5C /* \\\\ */ && pos + 1 < max) {\\n if (str.charCodeAt(pos + 1) === 0x20) { break }\\n pos += 2\\n continue\\n }\\n\\n if (code === 0x28 /* ( */) {\\n level++\\n if (level > 32) { return result }\\n }\\n\\n if (code === 0x29 /* ) */) {\\n if (level === 0) { break }\\n level--\\n }\\n\\n pos++\\n }\\n\\n if (start === pos) { return result }\\n if (level !== 0) { return result }\\n\\n result.str = unescapeAll(str.slice(start, pos))\\n result.pos = pos\\n result.ok = true\\n return result\\n}\\n\",\"// Parse link title\\n//\\n\\nimport { unescapeAll } from '../common/utils.mjs'\\n\\n// Parse link title within `str` in [start, max] range,\\n// or continue previous parsing if `prev_state` is defined (equal to result of last execution).\\n//\\nexport default function parseLinkTitle (str, start, max, prev_state) {\\n let code\\n let pos = start\\n\\n const state = {\\n // if `true`, this is a valid link title\\n ok: false,\\n // if `true`, this link can be continued on the next line\\n can_continue: false,\\n // if `ok`, it's the position of the first character after the closing marker\\n pos: 0,\\n // if `ok`, it's the unescaped title\\n str: '',\\n // expected closing marker character code\\n marker: 0\\n }\\n\\n if (prev_state) {\\n // this is a continuation of a previous parseLinkTitle call on the next line,\\n // used in reference links only\\n state.str = prev_state.str\\n state.marker = prev_state.marker\\n } else {\\n if (pos >= max) { return state }\\n\\n let marker = str.charCodeAt(pos)\\n if (marker !== 0x22 /* \\\" */ && marker !== 0x27 /* ' */ && marker !== 0x28 /* ( */) { return state }\\n\\n start++\\n pos++\\n\\n // if opening marker is \\\"(\\\", switch it to closing marker \\\")\\\"\\n if (marker === 0x28) { marker = 0x29 }\\n\\n state.marker = marker\\n }\\n\\n while (pos < max) {\\n code = str.charCodeAt(pos)\\n if (code === state.marker) {\\n state.pos = pos + 1\\n state.str += unescapeAll(str.slice(start, pos))\\n state.ok = true\\n return state\\n } else if (code === 0x28 /* ( */ && state.marker === 0x29 /* ) */) {\\n return state\\n } else if (code === 0x5C /* \\\\ */ && pos + 1 < max) {\\n pos++\\n }\\n\\n pos++\\n }\\n\\n // no closing marker found, but this link title may continue on the next line (for references)\\n state.can_continue = true\\n state.str += unescapeAll(str.slice(start, pos))\\n return state\\n}\\n\",\"/**\\n * class Renderer\\n *\\n * Generates HTML from parsed token stream. Each instance has independent\\n * copy of rules. Those can be rewritten with ease. Also, you can add new\\n * rules if you create plugin and adds new token types.\\n **/\\n\\nimport { assign, unescapeAll, escapeHtml } from './common/utils.mjs'\\n\\nconst default_rules = {}\\n\\ndefault_rules.code_inline = function (tokens, idx, options, env, slf) {\\n const token = tokens[idx]\\n\\n return '' +\\n escapeHtml(token.content) +\\n ''\\n}\\n\\ndefault_rules.code_block = function (tokens, idx, options, env, slf) {\\n const token = tokens[idx]\\n\\n return '' +\\n escapeHtml(tokens[idx].content) +\\n '\\\\n'\\n}\\n\\ndefault_rules.fence = function (tokens, idx, options, env, slf) {\\n const token = tokens[idx]\\n const info = token.info ? unescapeAll(token.info).trim() : ''\\n let langName = ''\\n let langAttrs = ''\\n\\n if (info) {\\n const arr = info.split(/(\\\\s+)/g)\\n langName = arr[0]\\n langAttrs = arr.slice(2).join('')\\n }\\n\\n let highlighted\\n if (options.highlight) {\\n highlighted = options.highlight(token.content, langName, langAttrs) || escapeHtml(token.content)\\n } else {\\n highlighted = escapeHtml(token.content)\\n }\\n\\n if (highlighted.indexOf('${highlighted}\\\\n`\\n }\\n\\n return `

${highlighted}
\\\\n`\\n}\\n\\ndefault_rules.image = function (tokens, idx, options, env, slf) {\\n const token = tokens[idx]\\n\\n // \\\"alt\\\" attr MUST be set, even if empty. Because it's mandatory and\\n // should be placed on proper position for tests.\\n //\\n // Replace content with actual value\\n\\n token.attrs[token.attrIndex('alt')][1] =\\n slf.renderInlineAsText(token.children, options, env)\\n\\n return slf.renderToken(tokens, idx, options)\\n}\\n\\ndefault_rules.hardbreak = function (tokens, idx, options /*, env */) {\\n return options.xhtmlOut ? '
\\\\n' : '
\\\\n'\\n}\\ndefault_rules.softbreak = function (tokens, idx, options /*, env */) {\\n return options.breaks ? (options.xhtmlOut ? '
\\\\n' : '
\\\\n') : '\\\\n'\\n}\\n\\ndefault_rules.text = function (tokens, idx /*, options, env */) {\\n return escapeHtml(tokens[idx].content)\\n}\\n\\ndefault_rules.html_block = function (tokens, idx /*, options, env */) {\\n return tokens[idx].content\\n}\\ndefault_rules.html_inline = function (tokens, idx /*, options, env */) {\\n return tokens[idx].content\\n}\\n\\n/**\\n * new Renderer()\\n *\\n * Creates new [[Renderer]] instance and fill [[Renderer#rules]] with defaults.\\n **/\\nfunction Renderer () {\\n /**\\n * Renderer#rules -> Object\\n *\\n * Contains render rules for tokens. Can be updated and extended.\\n *\\n * ##### Example\\n *\\n * ```javascript\\n * var md = require('markdown-it')();\\n *\\n * md.renderer.rules.strong_open = function () { return ''; };\\n * md.renderer.rules.strong_close = function () { return ''; };\\n *\\n * var result = md.renderInline(...);\\n * ```\\n *\\n * Each rule is called as independent static function with fixed signature:\\n *\\n * ```javascript\\n * function my_token_render(tokens, idx, options, env, renderer) {\\n * // ...\\n * return renderedHTML;\\n * }\\n * ```\\n *\\n * See [source code](https://github.com/markdown-it/markdown-it/blob/master/lib/renderer.mjs)\\n * for more details and examples.\\n **/\\n this.rules = assign({}, default_rules)\\n}\\n\\n/**\\n * Renderer.renderAttrs(token) -> String\\n *\\n * Render token attributes to string.\\n **/\\nRenderer.prototype.renderAttrs = function renderAttrs (token) {\\n let i, l, result\\n\\n if (!token.attrs) { return '' }\\n\\n result = ''\\n\\n for (i = 0, l = token.attrs.length; i < l; i++) {\\n result += ' ' + escapeHtml(token.attrs[i][0]) + '=\\\"' + escapeHtml(token.attrs[i][1]) + '\\\"'\\n }\\n\\n return result\\n}\\n\\n/**\\n * Renderer.renderToken(tokens, idx, options) -> String\\n * - tokens (Array): list of tokens\\n * - idx (Numbed): token index to render\\n * - options (Object): params of parser instance\\n *\\n * Default token renderer. Can be overriden by custom function\\n * in [[Renderer#rules]].\\n **/\\nRenderer.prototype.renderToken = function renderToken (tokens, idx, options) {\\n const token = tokens[idx]\\n let result = ''\\n\\n // Tight list paragraphs\\n if (token.hidden) {\\n return ''\\n }\\n\\n // Insert a newline between hidden paragraph and subsequent opening\\n // block-level tag.\\n //\\n // For example, here we should insert a newline before blockquote:\\n // - a\\n // >\\n //\\n if (token.block && token.nesting !== -1 && idx && tokens[idx - 1].hidden) {\\n result += '\\\\n'\\n }\\n\\n // Add token name, e.g. ``.\\n //\\n needLf = false\\n }\\n }\\n }\\n }\\n\\n result += needLf ? '>\\\\n' : '>'\\n\\n return result\\n}\\n\\n/**\\n * Renderer.renderInline(tokens, options, env) -> String\\n * - tokens (Array): list on block tokens to render\\n * - options (Object): params of parser instance\\n * - env (Object): additional data from parsed input (references, for example)\\n *\\n * The same as [[Renderer.render]], but for single token of `inline` type.\\n **/\\nRenderer.prototype.renderInline = function (tokens, options, env) {\\n let result = ''\\n const rules = this.rules\\n\\n for (let i = 0, len = tokens.length; i < len; i++) {\\n const type = tokens[i].type\\n\\n if (typeof rules[type] !== 'undefined') {\\n result += rules[type](tokens, i, options, env, this)\\n } else {\\n result += this.renderToken(tokens, i, options)\\n }\\n }\\n\\n return result\\n}\\n\\n/** internal\\n * Renderer.renderInlineAsText(tokens, options, env) -> String\\n * - tokens (Array): list on block tokens to render\\n * - options (Object): params of parser instance\\n * - env (Object): additional data from parsed input (references, for example)\\n *\\n * Special kludge for image `alt` attributes to conform CommonMark spec.\\n * Don't try to use it! Spec requires to show `alt` content with stripped markup,\\n * instead of simple escaping.\\n **/\\nRenderer.prototype.renderInlineAsText = function (tokens, options, env) {\\n let result = ''\\n\\n for (let i = 0, len = tokens.length; i < len; i++) {\\n switch (tokens[i].type) {\\n case 'text':\\n result += tokens[i].content\\n break\\n case 'image':\\n result += this.renderInlineAsText(tokens[i].children, options, env)\\n break\\n case 'html_inline':\\n case 'html_block':\\n result += tokens[i].content\\n break\\n case 'softbreak':\\n case 'hardbreak':\\n result += '\\\\n'\\n break\\n default:\\n // all other tokens are skipped\\n }\\n }\\n\\n return result\\n}\\n\\n/**\\n * Renderer.render(tokens, options, env) -> String\\n * - tokens (Array): list on block tokens to render\\n * - options (Object): params of parser instance\\n * - env (Object): additional data from parsed input (references, for example)\\n *\\n * Takes token stream and generates HTML. Probably, you will never need to call\\n * this method directly.\\n **/\\nRenderer.prototype.render = function (tokens, options, env) {\\n let result = ''\\n const rules = this.rules\\n\\n for (let i = 0, len = tokens.length; i < len; i++) {\\n const type = tokens[i].type\\n\\n if (type === 'inline') {\\n result += this.renderInline(tokens[i].children, options, env)\\n } else if (typeof rules[type] !== 'undefined') {\\n result += rules[type](tokens, i, options, env, this)\\n } else {\\n result += this.renderToken(tokens, i, options, env)\\n }\\n }\\n\\n return result\\n}\\n\\nexport default Renderer\\n\",\"/**\\n * class Ruler\\n *\\n * Helper class, used by [[MarkdownIt#core]], [[MarkdownIt#block]] and\\n * [[MarkdownIt#inline]] to manage sequences of functions (rules):\\n *\\n * - keep rules in defined order\\n * - assign the name to each rule\\n * - enable/disable rules\\n * - add/replace rules\\n * - allow assign rules to additional named chains (in the same)\\n * - cacheing lists of active rules\\n *\\n * You will not need use this class directly until write plugins. For simple\\n * rules control use [[MarkdownIt.disable]], [[MarkdownIt.enable]] and\\n * [[MarkdownIt.use]].\\n **/\\n\\n/**\\n * new Ruler()\\n **/\\nfunction Ruler () {\\n // List of added rules. Each element is:\\n //\\n // {\\n // name: XXX,\\n // enabled: Boolean,\\n // fn: Function(),\\n // alt: [ name2, name3 ]\\n // }\\n //\\n this.__rules__ = []\\n\\n // Cached rule chains.\\n //\\n // First level - chain name, '' for default.\\n // Second level - diginal anchor for fast filtering by charcodes.\\n //\\n this.__cache__ = null\\n}\\n\\n// Helper methods, should not be used directly\\n\\n// Find rule index by name\\n//\\nRuler.prototype.__find__ = function (name) {\\n for (let i = 0; i < this.__rules__.length; i++) {\\n if (this.__rules__[i].name === name) {\\n return i\\n }\\n }\\n return -1\\n}\\n\\n// Build rules lookup cache\\n//\\nRuler.prototype.__compile__ = function () {\\n const self = this\\n const chains = ['']\\n\\n // collect unique names\\n self.__rules__.forEach(function (rule) {\\n if (!rule.enabled) { return }\\n\\n rule.alt.forEach(function (altName) {\\n if (chains.indexOf(altName) < 0) {\\n chains.push(altName)\\n }\\n })\\n })\\n\\n self.__cache__ = {}\\n\\n chains.forEach(function (chain) {\\n self.__cache__[chain] = []\\n self.__rules__.forEach(function (rule) {\\n if (!rule.enabled) { return }\\n\\n if (chain && rule.alt.indexOf(chain) < 0) { return }\\n\\n self.__cache__[chain].push(rule.fn)\\n })\\n })\\n}\\n\\n/**\\n * Ruler.at(name, fn [, options])\\n * - name (String): rule name to replace.\\n * - fn (Function): new rule function.\\n * - options (Object): new rule options (not mandatory).\\n *\\n * Replace rule by name with new function & options. Throws error if name not\\n * found.\\n *\\n * ##### Options:\\n *\\n * - __alt__ - array with names of \\\"alternate\\\" chains.\\n *\\n * ##### Example\\n *\\n * Replace existing typographer replacement rule with new one:\\n *\\n * ```javascript\\n * var md = require('markdown-it')();\\n *\\n * md.core.ruler.at('replacements', function replace(state) {\\n * //...\\n * });\\n * ```\\n **/\\nRuler.prototype.at = function (name, fn, options) {\\n const index = this.__find__(name)\\n const opt = options || {}\\n\\n if (index === -1) { throw new Error('Parser rule not found: ' + name) }\\n\\n this.__rules__[index].fn = fn\\n this.__rules__[index].alt = opt.alt || []\\n this.__cache__ = null\\n}\\n\\n/**\\n * Ruler.before(beforeName, ruleName, fn [, options])\\n * - beforeName (String): new rule will be added before this one.\\n * - ruleName (String): name of added rule.\\n * - fn (Function): rule function.\\n * - options (Object): rule options (not mandatory).\\n *\\n * Add new rule to chain before one with given name. See also\\n * [[Ruler.after]], [[Ruler.push]].\\n *\\n * ##### Options:\\n *\\n * - __alt__ - array with names of \\\"alternate\\\" chains.\\n *\\n * ##### Example\\n *\\n * ```javascript\\n * var md = require('markdown-it')();\\n *\\n * md.block.ruler.before('paragraph', 'my_rule', function replace(state) {\\n * //...\\n * });\\n * ```\\n **/\\nRuler.prototype.before = function (beforeName, ruleName, fn, options) {\\n const index = this.__find__(beforeName)\\n const opt = options || {}\\n\\n if (index === -1) { throw new Error('Parser rule not found: ' + beforeName) }\\n\\n this.__rules__.splice(index, 0, {\\n name: ruleName,\\n enabled: true,\\n fn,\\n alt: opt.alt || []\\n })\\n\\n this.__cache__ = null\\n}\\n\\n/**\\n * Ruler.after(afterName, ruleName, fn [, options])\\n * - afterName (String): new rule will be added after this one.\\n * - ruleName (String): name of added rule.\\n * - fn (Function): rule function.\\n * - options (Object): rule options (not mandatory).\\n *\\n * Add new rule to chain after one with given name. See also\\n * [[Ruler.before]], [[Ruler.push]].\\n *\\n * ##### Options:\\n *\\n * - __alt__ - array with names of \\\"alternate\\\" chains.\\n *\\n * ##### Example\\n *\\n * ```javascript\\n * var md = require('markdown-it')();\\n *\\n * md.inline.ruler.after('text', 'my_rule', function replace(state) {\\n * //...\\n * });\\n * ```\\n **/\\nRuler.prototype.after = function (afterName, ruleName, fn, options) {\\n const index = this.__find__(afterName)\\n const opt = options || {}\\n\\n if (index === -1) { throw new Error('Parser rule not found: ' + afterName) }\\n\\n this.__rules__.splice(index + 1, 0, {\\n name: ruleName,\\n enabled: true,\\n fn,\\n alt: opt.alt || []\\n })\\n\\n this.__cache__ = null\\n}\\n\\n/**\\n * Ruler.push(ruleName, fn [, options])\\n * - ruleName (String): name of added rule.\\n * - fn (Function): rule function.\\n * - options (Object): rule options (not mandatory).\\n *\\n * Push new rule to the end of chain. See also\\n * [[Ruler.before]], [[Ruler.after]].\\n *\\n * ##### Options:\\n *\\n * - __alt__ - array with names of \\\"alternate\\\" chains.\\n *\\n * ##### Example\\n *\\n * ```javascript\\n * var md = require('markdown-it')();\\n *\\n * md.core.ruler.push('my_rule', function replace(state) {\\n * //...\\n * });\\n * ```\\n **/\\nRuler.prototype.push = function (ruleName, fn, options) {\\n const opt = options || {}\\n\\n this.__rules__.push({\\n name: ruleName,\\n enabled: true,\\n fn,\\n alt: opt.alt || []\\n })\\n\\n this.__cache__ = null\\n}\\n\\n/**\\n * Ruler.enable(list [, ignoreInvalid]) -> Array\\n * - list (String|Array): list of rule names to enable.\\n * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.\\n *\\n * Enable rules with given names. If any rule name not found - throw Error.\\n * Errors can be disabled by second param.\\n *\\n * Returns list of found rule names (if no exception happened).\\n *\\n * See also [[Ruler.disable]], [[Ruler.enableOnly]].\\n **/\\nRuler.prototype.enable = function (list, ignoreInvalid) {\\n if (!Array.isArray(list)) { list = [list] }\\n\\n const result = []\\n\\n // Search by name and enable\\n list.forEach(function (name) {\\n const idx = this.__find__(name)\\n\\n if (idx < 0) {\\n if (ignoreInvalid) { return }\\n throw new Error('Rules manager: invalid rule name ' + name)\\n }\\n this.__rules__[idx].enabled = true\\n result.push(name)\\n }, this)\\n\\n this.__cache__ = null\\n return result\\n}\\n\\n/**\\n * Ruler.enableOnly(list [, ignoreInvalid])\\n * - list (String|Array): list of rule names to enable (whitelist).\\n * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.\\n *\\n * Enable rules with given names, and disable everything else. If any rule name\\n * not found - throw Error. Errors can be disabled by second param.\\n *\\n * See also [[Ruler.disable]], [[Ruler.enable]].\\n **/\\nRuler.prototype.enableOnly = function (list, ignoreInvalid) {\\n if (!Array.isArray(list)) { list = [list] }\\n\\n this.__rules__.forEach(function (rule) { rule.enabled = false })\\n\\n this.enable(list, ignoreInvalid)\\n}\\n\\n/**\\n * Ruler.disable(list [, ignoreInvalid]) -> Array\\n * - list (String|Array): list of rule names to disable.\\n * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.\\n *\\n * Disable rules with given names. If any rule name not found - throw Error.\\n * Errors can be disabled by second param.\\n *\\n * Returns list of found rule names (if no exception happened).\\n *\\n * See also [[Ruler.enable]], [[Ruler.enableOnly]].\\n **/\\nRuler.prototype.disable = function (list, ignoreInvalid) {\\n if (!Array.isArray(list)) { list = [list] }\\n\\n const result = []\\n\\n // Search by name and disable\\n list.forEach(function (name) {\\n const idx = this.__find__(name)\\n\\n if (idx < 0) {\\n if (ignoreInvalid) { return }\\n throw new Error('Rules manager: invalid rule name ' + name)\\n }\\n this.__rules__[idx].enabled = false\\n result.push(name)\\n }, this)\\n\\n this.__cache__ = null\\n return result\\n}\\n\\n/**\\n * Ruler.getRules(chainName) -> Array\\n *\\n * Return array of active functions (rules) for given chain name. It analyzes\\n * rules configuration, compiles caches if not exists and returns result.\\n *\\n * Default chain name is `''` (empty string). It can't be skipped. That's\\n * done intentionally, to keep signature monomorphic for high speed.\\n **/\\nRuler.prototype.getRules = function (chainName) {\\n if (this.__cache__ === null) {\\n this.__compile__()\\n }\\n\\n // Chain can be empty, if rules disabled. But we still have to return Array.\\n return this.__cache__[chainName] || []\\n}\\n\\nexport default Ruler\\n\",\"// Token class\\n\\n/**\\n * class Token\\n **/\\n\\n/**\\n * new Token(type, tag, nesting)\\n *\\n * Create new token and fill passed properties.\\n **/\\nfunction Token (type, tag, nesting) {\\n /**\\n * Token#type -> String\\n *\\n * Type of the token (string, e.g. \\\"paragraph_open\\\")\\n **/\\n this.type = type\\n\\n /**\\n * Token#tag -> String\\n *\\n * html tag name, e.g. \\\"p\\\"\\n **/\\n this.tag = tag\\n\\n /**\\n * Token#attrs -> Array\\n *\\n * Html attributes. Format: `[ [ name1, value1 ], [ name2, value2 ] ]`\\n **/\\n this.attrs = null\\n\\n /**\\n * Token#map -> Array\\n *\\n * Source map info. Format: `[ line_begin, line_end ]`\\n **/\\n this.map = null\\n\\n /**\\n * Token#nesting -> Number\\n *\\n * Level change (number in {-1, 0, 1} set), where:\\n *\\n * - `1` means the tag is opening\\n * - `0` means the tag is self-closing\\n * - `-1` means the tag is closing\\n **/\\n this.nesting = nesting\\n\\n /**\\n * Token#level -> Number\\n *\\n * nesting level, the same as `state.level`\\n **/\\n this.level = 0\\n\\n /**\\n * Token#children -> Array\\n *\\n * An array of child nodes (inline and img tokens)\\n **/\\n this.children = null\\n\\n /**\\n * Token#content -> String\\n *\\n * In a case of self-closing tag (code, html, fence, etc.),\\n * it has contents of this tag.\\n **/\\n this.content = ''\\n\\n /**\\n * Token#markup -> String\\n *\\n * '*' or '_' for emphasis, fence string for fence, etc.\\n **/\\n this.markup = ''\\n\\n /**\\n * Token#info -> String\\n *\\n * Additional information:\\n *\\n * - Info string for \\\"fence\\\" tokens\\n * - The value \\\"auto\\\" for autolink \\\"link_open\\\" and \\\"link_close\\\" tokens\\n * - The string value of the item marker for ordered-list \\\"list_item_open\\\" tokens\\n **/\\n this.info = ''\\n\\n /**\\n * Token#meta -> Object\\n *\\n * A place for plugins to store an arbitrary data\\n **/\\n this.meta = null\\n\\n /**\\n * Token#block -> Boolean\\n *\\n * True for block-level tokens, false for inline tokens.\\n * Used in renderer to calculate line breaks\\n **/\\n this.block = false\\n\\n /**\\n * Token#hidden -> Boolean\\n *\\n * If it's true, ignore this element when rendering. Used for tight lists\\n * to hide paragraphs.\\n **/\\n this.hidden = false\\n}\\n\\n/**\\n * Token.attrIndex(name) -> Number\\n *\\n * Search attribute index by name.\\n **/\\nToken.prototype.attrIndex = function attrIndex (name) {\\n if (!this.attrs) { return -1 }\\n\\n const attrs = this.attrs\\n\\n for (let i = 0, len = attrs.length; i < len; i++) {\\n if (attrs[i][0] === name) { return i }\\n }\\n return -1\\n}\\n\\n/**\\n * Token.attrPush(attrData)\\n *\\n * Add `[ name, value ]` attribute to list. Init attrs if necessary\\n **/\\nToken.prototype.attrPush = function attrPush (attrData) {\\n if (this.attrs) {\\n this.attrs.push(attrData)\\n } else {\\n this.attrs = [attrData]\\n }\\n}\\n\\n/**\\n * Token.attrSet(name, value)\\n *\\n * Set `name` attribute to `value`. Override old value if exists.\\n **/\\nToken.prototype.attrSet = function attrSet (name, value) {\\n const idx = this.attrIndex(name)\\n const attrData = [name, value]\\n\\n if (idx < 0) {\\n this.attrPush(attrData)\\n } else {\\n this.attrs[idx] = attrData\\n }\\n}\\n\\n/**\\n * Token.attrGet(name)\\n *\\n * Get the value of attribute `name`, or null if it does not exist.\\n **/\\nToken.prototype.attrGet = function attrGet (name) {\\n const idx = this.attrIndex(name)\\n let value = null\\n if (idx >= 0) {\\n value = this.attrs[idx][1]\\n }\\n return value\\n}\\n\\n/**\\n * Token.attrJoin(name, value)\\n *\\n * Join value to existing attribute via space. Or create new attribute if not\\n * exists. Useful to operate with token classes.\\n **/\\nToken.prototype.attrJoin = function attrJoin (name, value) {\\n const idx = this.attrIndex(name)\\n\\n if (idx < 0) {\\n this.attrPush([name, value])\\n } else {\\n this.attrs[idx][1] = this.attrs[idx][1] + ' ' + value\\n }\\n}\\n\\nexport default Token\\n\",\"// Core state object\\n//\\n\\nimport Token from '../token.mjs'\\n\\nfunction StateCore (src, md, env) {\\n this.src = src\\n this.env = env\\n this.tokens = []\\n this.inlineMode = false\\n this.md = md // link to parser instance\\n}\\n\\n// re-export Token class to use in core rules\\nStateCore.prototype.Token = Token\\n\\nexport default StateCore\\n\",\"// Normalize input string\\n\\n// https://spec.commonmark.org/0.29/#line-ending\\nconst NEWLINES_RE = /\\\\r\\\\n?|\\\\n/g\\nconst NULL_RE = /\\\\0/g\\n\\nexport default function normalize (state) {\\n let str\\n\\n // Normalize newlines\\n str = state.src.replace(NEWLINES_RE, '\\\\n')\\n\\n // Replace NULL characters\\n str = str.replace(NULL_RE, '\\\\uFFFD')\\n\\n state.src = str\\n}\\n\",\"export default function block (state) {\\n let token\\n\\n if (state.inlineMode) {\\n token = new state.Token('inline', '', 0)\\n token.content = state.src\\n token.map = [0, 1]\\n token.children = []\\n state.tokens.push(token)\\n } else {\\n state.md.block.parse(state.src, state.md, state.env, state.tokens)\\n }\\n}\\n\",\"export default function inline (state) {\\n const tokens = state.tokens\\n\\n // Parse inlines\\n for (let i = 0, l = tokens.length; i < l; i++) {\\n const tok = tokens[i]\\n if (tok.type === 'inline') {\\n state.md.inline.parse(tok.content, state.md, state.env, tok.children)\\n }\\n }\\n}\\n\",\"// Replace link-like texts with link nodes.\\n//\\n// Currently restricted by `md.validateLink()` to http/https/ftp\\n//\\n\\nimport { arrayReplaceAt } from '../common/utils.mjs'\\n\\nfunction isLinkOpen (str) {\\n return /^\\\\s]/i.test(str)\\n}\\nfunction isLinkClose (str) {\\n return /^<\\\\/a\\\\s*>/i.test(str)\\n}\\n\\nexport default function linkify (state) {\\n const blockTokens = state.tokens\\n\\n if (!state.md.options.linkify) { return }\\n\\n for (let j = 0, l = blockTokens.length; j < l; j++) {\\n if (blockTokens[j].type !== 'inline' ||\\n !state.md.linkify.pretest(blockTokens[j].content)) {\\n continue\\n }\\n\\n let tokens = blockTokens[j].children\\n\\n let htmlLinkLevel = 0\\n\\n // We scan from the end, to keep position when new tags added.\\n // Use reversed logic in links start/end match\\n for (let i = tokens.length - 1; i >= 0; i--) {\\n const currentToken = tokens[i]\\n\\n // Skip content of markdown links\\n if (currentToken.type === 'link_close') {\\n i--\\n while (tokens[i].level !== currentToken.level && tokens[i].type !== 'link_open') {\\n i--\\n }\\n continue\\n }\\n\\n // Skip content of html tag links\\n if (currentToken.type === 'html_inline') {\\n if (isLinkOpen(currentToken.content) && htmlLinkLevel > 0) {\\n htmlLinkLevel--\\n }\\n if (isLinkClose(currentToken.content)) {\\n htmlLinkLevel++\\n }\\n }\\n if (htmlLinkLevel > 0) { continue }\\n\\n if (currentToken.type === 'text' && state.md.linkify.test(currentToken.content)) {\\n const text = currentToken.content\\n let links = state.md.linkify.match(text)\\n\\n // Now split string to nodes\\n const nodes = []\\n let level = currentToken.level\\n let lastPos = 0\\n\\n // forbid escape sequence at the start of the string,\\n // this avoids http\\\\://example.com/ from being linkified as\\n // http:
//example.com/\\n if (links.length > 0 &&\\n links[0].index === 0 &&\\n i > 0 &&\\n tokens[i - 1].type === 'text_special') {\\n links = links.slice(1)\\n }\\n\\n for (let ln = 0; ln < links.length; ln++) {\\n const url = links[ln].url\\n const fullUrl = state.md.normalizeLink(url)\\n if (!state.md.validateLink(fullUrl)) { continue }\\n\\n let urlText = links[ln].text\\n\\n // Linkifier might send raw hostnames like \\\"example.com\\\", where url\\n // starts with domain name. So we prepend http:// in those cases,\\n // and remove it afterwards.\\n //\\n if (!links[ln].schema) {\\n urlText = state.md.normalizeLinkText('http://' + urlText).replace(/^http:\\\\/\\\\//, '')\\n } else if (links[ln].schema === 'mailto:' && !/^mailto:/i.test(urlText)) {\\n urlText = state.md.normalizeLinkText('mailto:' + urlText).replace(/^mailto:/, '')\\n } else {\\n urlText = state.md.normalizeLinkText(urlText)\\n }\\n\\n const pos = links[ln].index\\n\\n if (pos > lastPos) {\\n const token = new state.Token('text', '', 0)\\n token.content = text.slice(lastPos, pos)\\n token.level = level\\n nodes.push(token)\\n }\\n\\n const token_o = new state.Token('link_open', 'a', 1)\\n token_o.attrs = [['href', fullUrl]]\\n token_o.level = level++\\n token_o.markup = 'linkify'\\n token_o.info = 'auto'\\n nodes.push(token_o)\\n\\n const token_t = new state.Token('text', '', 0)\\n token_t.content = urlText\\n token_t.level = level\\n nodes.push(token_t)\\n\\n const token_c = new state.Token('link_close', 'a', -1)\\n token_c.level = --level\\n token_c.markup = 'linkify'\\n token_c.info = 'auto'\\n nodes.push(token_c)\\n\\n lastPos = links[ln].lastIndex\\n }\\n if (lastPos < text.length) {\\n const token = new state.Token('text', '', 0)\\n token.content = text.slice(lastPos)\\n token.level = level\\n nodes.push(token)\\n }\\n\\n // replace current node\\n blockTokens[j].children = tokens = arrayReplaceAt(tokens, i, nodes)\\n }\\n }\\n }\\n}\\n\",\"// Simple typographic replacements\\n//\\n// (c) (C) → ©\\n// (tm) (TM) → ™\\n// (r) (R) → ®\\n// +- → ±\\n// ... → … (also ?.... → ?.., !.... → !..)\\n// ???????? → ???, !!!!! → !!!, `,,` → `,`\\n// -- → –, --- → —\\n//\\n\\n// TODO:\\n// - fractionals 1/2, 1/4, 3/4 -> ½, ¼, ¾\\n// - multiplications 2 x 4 -> 2 × 4\\n\\nconst RARE_RE = /\\\\+-|\\\\.\\\\.|\\\\?\\\\?\\\\?\\\\?|!!!!|,,|--/\\n\\n// Workaround for phantomjs - need regex without /g flag,\\n// or root check will fail every second time\\nconst SCOPED_ABBR_TEST_RE = /\\\\((c|tm|r)\\\\)/i\\n\\nconst SCOPED_ABBR_RE = /\\\\((c|tm|r)\\\\)/ig\\nconst SCOPED_ABBR = {\\n c: '©',\\n r: '®',\\n tm: '™'\\n}\\n\\nfunction replaceFn (match, name) {\\n return SCOPED_ABBR[name.toLowerCase()]\\n}\\n\\nfunction replace_scoped (inlineTokens) {\\n let inside_autolink = 0\\n\\n for (let i = inlineTokens.length - 1; i >= 0; i--) {\\n const token = inlineTokens[i]\\n\\n if (token.type === 'text' && !inside_autolink) {\\n token.content = token.content.replace(SCOPED_ABBR_RE, replaceFn)\\n }\\n\\n if (token.type === 'link_open' && token.info === 'auto') {\\n inside_autolink--\\n }\\n\\n if (token.type === 'link_close' && token.info === 'auto') {\\n inside_autolink++\\n }\\n }\\n}\\n\\nfunction replace_rare (inlineTokens) {\\n let inside_autolink = 0\\n\\n for (let i = inlineTokens.length - 1; i >= 0; i--) {\\n const token = inlineTokens[i]\\n\\n if (token.type === 'text' && !inside_autolink) {\\n if (RARE_RE.test(token.content)) {\\n token.content = token.content\\n .replace(/\\\\+-/g, '±')\\n // .., ..., ....... -> …\\n // but ?..... & !..... -> ?.. & !..\\n .replace(/\\\\.{2,}/g, '…').replace(/([?!])…/g, '$1..')\\n .replace(/([?!]){4,}/g, '$1$1$1').replace(/,{2,}/g, ',')\\n // em-dash\\n .replace(/(^|[^-])---(?=[^-]|$)/mg, '$1\\\\u2014')\\n // en-dash\\n .replace(/(^|\\\\s)--(?=\\\\s|$)/mg, '$1\\\\u2013')\\n .replace(/(^|[^-\\\\s])--(?=[^-\\\\s]|$)/mg, '$1\\\\u2013')\\n }\\n }\\n\\n if (token.type === 'link_open' && token.info === 'auto') {\\n inside_autolink--\\n }\\n\\n if (token.type === 'link_close' && token.info === 'auto') {\\n inside_autolink++\\n }\\n }\\n}\\n\\nexport default function replace (state) {\\n let blkIdx\\n\\n if (!state.md.options.typographer) { return }\\n\\n for (blkIdx = state.tokens.length - 1; blkIdx >= 0; blkIdx--) {\\n if (state.tokens[blkIdx].type !== 'inline') { continue }\\n\\n if (SCOPED_ABBR_TEST_RE.test(state.tokens[blkIdx].content)) {\\n replace_scoped(state.tokens[blkIdx].children)\\n }\\n\\n if (RARE_RE.test(state.tokens[blkIdx].content)) {\\n replace_rare(state.tokens[blkIdx].children)\\n }\\n }\\n}\\n\",\"// Convert straight quotation marks to typographic ones\\n//\\n\\nimport { isWhiteSpace, isPunctChar, isMdAsciiPunct } from '../common/utils.mjs'\\n\\nconst QUOTE_TEST_RE = /['\\\"]/\\nconst QUOTE_RE = /['\\\"]/g\\nconst APOSTROPHE = '\\\\u2019' /* ’ */\\n\\nfunction replaceAt (str, index, ch) {\\n return str.slice(0, index) + ch + str.slice(index + 1)\\n}\\n\\nfunction process_inlines (tokens, state) {\\n let j\\n\\n const stack = []\\n\\n for (let i = 0; i < tokens.length; i++) {\\n const token = tokens[i]\\n\\n const thisLevel = tokens[i].level\\n\\n for (j = stack.length - 1; j >= 0; j--) {\\n if (stack[j].level <= thisLevel) { break }\\n }\\n stack.length = j + 1\\n\\n if (token.type !== 'text') { continue }\\n\\n let text = token.content\\n let pos = 0\\n let max = text.length\\n\\n /* eslint no-labels:0,block-scoped-var:0 */\\n OUTER:\\n while (pos < max) {\\n QUOTE_RE.lastIndex = pos\\n const t = QUOTE_RE.exec(text)\\n if (!t) { break }\\n\\n let canOpen = true\\n let canClose = true\\n pos = t.index + 1\\n const isSingle = (t[0] === \\\"'\\\")\\n\\n // Find previous character,\\n // default to space if it's the beginning of the line\\n //\\n let lastChar = 0x20\\n\\n if (t.index - 1 >= 0) {\\n lastChar = text.charCodeAt(t.index - 1)\\n } else {\\n for (j = i - 1; j >= 0; j--) {\\n if (tokens[j].type === 'softbreak' || tokens[j].type === 'hardbreak') break // lastChar defaults to 0x20\\n if (!tokens[j].content) continue // should skip all tokens except 'text', 'html_inline' or 'code_inline'\\n\\n lastChar = tokens[j].content.charCodeAt(tokens[j].content.length - 1)\\n break\\n }\\n }\\n\\n // Find next character,\\n // default to space if it's the end of the line\\n //\\n let nextChar = 0x20\\n\\n if (pos < max) {\\n nextChar = text.charCodeAt(pos)\\n } else {\\n for (j = i + 1; j < tokens.length; j++) {\\n if (tokens[j].type === 'softbreak' || tokens[j].type === 'hardbreak') break // nextChar defaults to 0x20\\n if (!tokens[j].content) continue // should skip all tokens except 'text', 'html_inline' or 'code_inline'\\n\\n nextChar = tokens[j].content.charCodeAt(0)\\n break\\n }\\n }\\n\\n const isLastPunctChar = isMdAsciiPunct(lastChar) || isPunctChar(String.fromCharCode(lastChar))\\n const isNextPunctChar = isMdAsciiPunct(nextChar) || isPunctChar(String.fromCharCode(nextChar))\\n\\n const isLastWhiteSpace = isWhiteSpace(lastChar)\\n const isNextWhiteSpace = isWhiteSpace(nextChar)\\n\\n if (isNextWhiteSpace) {\\n canOpen = false\\n } else if (isNextPunctChar) {\\n if (!(isLastWhiteSpace || isLastPunctChar)) {\\n canOpen = false\\n }\\n }\\n\\n if (isLastWhiteSpace) {\\n canClose = false\\n } else if (isLastPunctChar) {\\n if (!(isNextWhiteSpace || isNextPunctChar)) {\\n canClose = false\\n }\\n }\\n\\n if (nextChar === 0x22 /* \\\" */ && t[0] === '\\\"') {\\n if (lastChar >= 0x30 /* 0 */ && lastChar <= 0x39 /* 9 */) {\\n // special case: 1\\\"\\\" - count first quote as an inch\\n canClose = canOpen = false\\n }\\n }\\n\\n if (canOpen && canClose) {\\n // Replace quotes in the middle of punctuation sequence, but not\\n // in the middle of the words, i.e.:\\n //\\n // 1. foo \\\" bar \\\" baz - not replaced\\n // 2. foo-\\\"-bar-\\\"-baz - replaced\\n // 3. foo\\\"bar\\\"baz - not replaced\\n //\\n canOpen = isLastPunctChar\\n canClose = isNextPunctChar\\n }\\n\\n if (!canOpen && !canClose) {\\n // middle of word\\n if (isSingle) {\\n token.content = replaceAt(token.content, t.index, APOSTROPHE)\\n }\\n continue\\n }\\n\\n if (canClose) {\\n // this could be a closing quote, rewind the stack to get a match\\n for (j = stack.length - 1; j >= 0; j--) {\\n let item = stack[j]\\n if (stack[j].level < thisLevel) { break }\\n if (item.single === isSingle && stack[j].level === thisLevel) {\\n item = stack[j]\\n\\n let openQuote\\n let closeQuote\\n if (isSingle) {\\n openQuote = state.md.options.quotes[2]\\n closeQuote = state.md.options.quotes[3]\\n } else {\\n openQuote = state.md.options.quotes[0]\\n closeQuote = state.md.options.quotes[1]\\n }\\n\\n // replace token.content *before* tokens[item.token].content,\\n // because, if they are pointing at the same token, replaceAt\\n // could mess up indices when quote length != 1\\n token.content = replaceAt(token.content, t.index, closeQuote)\\n tokens[item.token].content = replaceAt(\\n tokens[item.token].content, item.pos, openQuote)\\n\\n pos += closeQuote.length - 1\\n if (item.token === i) { pos += openQuote.length - 1 }\\n\\n text = token.content\\n max = text.length\\n\\n stack.length = j\\n continue OUTER\\n }\\n }\\n }\\n\\n if (canOpen) {\\n stack.push({\\n token: i,\\n pos: t.index,\\n single: isSingle,\\n level: thisLevel\\n })\\n } else if (canClose && isSingle) {\\n token.content = replaceAt(token.content, t.index, APOSTROPHE)\\n }\\n }\\n }\\n}\\n\\nexport default function smartquotes (state) {\\n /* eslint max-depth:0 */\\n if (!state.md.options.typographer) { return }\\n\\n for (let blkIdx = state.tokens.length - 1; blkIdx >= 0; blkIdx--) {\\n if (state.tokens[blkIdx].type !== 'inline' ||\\n !QUOTE_TEST_RE.test(state.tokens[blkIdx].content)) {\\n continue\\n }\\n\\n process_inlines(state.tokens[blkIdx].children, state)\\n }\\n}\\n\",\"// Join raw text tokens with the rest of the text\\n//\\n// This is set as a separate rule to provide an opportunity for plugins\\n// to run text replacements after text join, but before escape join.\\n//\\n// For example, `\\\\:)` shouldn't be replaced with an emoji.\\n//\\n\\nexport default function text_join (state) {\\n let curr, last\\n const blockTokens = state.tokens\\n const l = blockTokens.length\\n\\n for (let j = 0; j < l; j++) {\\n if (blockTokens[j].type !== 'inline') continue\\n\\n const tokens = blockTokens[j].children\\n const max = tokens.length\\n\\n for (curr = 0; curr < max; curr++) {\\n if (tokens[curr].type === 'text_special') {\\n tokens[curr].type = 'text'\\n }\\n }\\n\\n for (curr = last = 0; curr < max; curr++) {\\n if (tokens[curr].type === 'text' &&\\n curr + 1 < max &&\\n tokens[curr + 1].type === 'text') {\\n // collapse two adjacent text nodes\\n tokens[curr + 1].content = tokens[curr].content + tokens[curr + 1].content\\n } else {\\n if (curr !== last) { tokens[last] = tokens[curr] }\\n\\n last++\\n }\\n }\\n\\n if (curr !== last) {\\n tokens.length = last\\n }\\n }\\n}\\n\",\"/** internal\\n * class Core\\n *\\n * Top-level rules executor. Glues block/inline parsers and does intermediate\\n * transformations.\\n **/\\n\\nimport Ruler from './ruler.mjs'\\nimport StateCore from './rules_core/state_core.mjs'\\n\\nimport r_normalize from './rules_core/normalize.mjs'\\nimport r_block from './rules_core/block.mjs'\\nimport r_inline from './rules_core/inline.mjs'\\nimport r_linkify from './rules_core/linkify.mjs'\\nimport r_replacements from './rules_core/replacements.mjs'\\nimport r_smartquotes from './rules_core/smartquotes.mjs'\\nimport r_text_join from './rules_core/text_join.mjs'\\n\\nconst _rules = [\\n ['normalize', r_normalize],\\n ['block', r_block],\\n ['inline', r_inline],\\n ['linkify', r_linkify],\\n ['replacements', r_replacements],\\n ['smartquotes', r_smartquotes],\\n // `text_join` finds `text_special` tokens (for escape sequences)\\n // and joins them with the rest of the text\\n ['text_join', r_text_join]\\n]\\n\\n/**\\n * new Core()\\n **/\\nfunction Core () {\\n /**\\n * Core#ruler -> Ruler\\n *\\n * [[Ruler]] instance. Keep configuration of core rules.\\n **/\\n this.ruler = new Ruler()\\n\\n for (let i = 0; i < _rules.length; i++) {\\n this.ruler.push(_rules[i][0], _rules[i][1])\\n }\\n}\\n\\n/**\\n * Core.process(state)\\n *\\n * Executes core chain rules.\\n **/\\nCore.prototype.process = function (state) {\\n const rules = this.ruler.getRules('')\\n\\n for (let i = 0, l = rules.length; i < l; i++) {\\n rules[i](state)\\n }\\n}\\n\\nCore.prototype.State = StateCore\\n\\nexport default Core\\n\",\"// Parser state class\\n\\nimport Token from '../token.mjs'\\nimport { isSpace } from '../common/utils.mjs'\\n\\nfunction StateBlock (src, md, env, tokens) {\\n this.src = src\\n\\n // link to parser instance\\n this.md = md\\n\\n this.env = env\\n\\n //\\n // Internal state vartiables\\n //\\n\\n this.tokens = tokens\\n\\n this.bMarks = [] // line begin offsets for fast jumps\\n this.eMarks = [] // line end offsets for fast jumps\\n this.tShift = [] // offsets of the first non-space characters (tabs not expanded)\\n this.sCount = [] // indents for each line (tabs expanded)\\n\\n // An amount of virtual spaces (tabs expanded) between beginning\\n // of each line (bMarks) and real beginning of that line.\\n //\\n // It exists only as a hack because blockquotes override bMarks\\n // losing information in the process.\\n //\\n // It's used only when expanding tabs, you can think about it as\\n // an initial tab length, e.g. bsCount=21 applied to string `\\\\t123`\\n // means first tab should be expanded to 4-21%4 === 3 spaces.\\n //\\n this.bsCount = []\\n\\n // block parser variables\\n\\n // required block content indent (for example, if we are\\n // inside a list, it would be positioned after list marker)\\n this.blkIndent = 0\\n this.line = 0 // line index in src\\n this.lineMax = 0 // lines count\\n this.tight = false // loose/tight mode for lists\\n this.ddIndent = -1 // indent of the current dd block (-1 if there isn't any)\\n this.listIndent = -1 // indent of the current list block (-1 if there isn't any)\\n\\n // can be 'blockquote', 'list', 'root', 'paragraph' or 'reference'\\n // used in lists to determine if they interrupt a paragraph\\n this.parentType = 'root'\\n\\n this.level = 0\\n\\n // Create caches\\n // Generate markers.\\n const s = this.src\\n\\n for (let start = 0, pos = 0, indent = 0, offset = 0, len = s.length, indent_found = false; pos < len; pos++) {\\n const ch = s.charCodeAt(pos)\\n\\n if (!indent_found) {\\n if (isSpace(ch)) {\\n indent++\\n\\n if (ch === 0x09) {\\n offset += 4 - offset % 4\\n } else {\\n offset++\\n }\\n continue\\n } else {\\n indent_found = true\\n }\\n }\\n\\n if (ch === 0x0A || pos === len - 1) {\\n if (ch !== 0x0A) { pos++ }\\n this.bMarks.push(start)\\n this.eMarks.push(pos)\\n this.tShift.push(indent)\\n this.sCount.push(offset)\\n this.bsCount.push(0)\\n\\n indent_found = false\\n indent = 0\\n offset = 0\\n start = pos + 1\\n }\\n }\\n\\n // Push fake entry to simplify cache bounds checks\\n this.bMarks.push(s.length)\\n this.eMarks.push(s.length)\\n this.tShift.push(0)\\n this.sCount.push(0)\\n this.bsCount.push(0)\\n\\n this.lineMax = this.bMarks.length - 1 // don't count last fake line\\n}\\n\\n// Push new token to \\\"stream\\\".\\n//\\nStateBlock.prototype.push = function (type, tag, nesting) {\\n const token = new Token(type, tag, nesting)\\n token.block = true\\n\\n if (nesting < 0) this.level-- // closing tag\\n token.level = this.level\\n if (nesting > 0) this.level++ // opening tag\\n\\n this.tokens.push(token)\\n return token\\n}\\n\\nStateBlock.prototype.isEmpty = function isEmpty (line) {\\n return this.bMarks[line] + this.tShift[line] >= this.eMarks[line]\\n}\\n\\nStateBlock.prototype.skipEmptyLines = function skipEmptyLines (from) {\\n for (let max = this.lineMax; from < max; from++) {\\n if (this.bMarks[from] + this.tShift[from] < this.eMarks[from]) {\\n break\\n }\\n }\\n return from\\n}\\n\\n// Skip spaces from given position.\\nStateBlock.prototype.skipSpaces = function skipSpaces (pos) {\\n for (let max = this.src.length; pos < max; pos++) {\\n const ch = this.src.charCodeAt(pos)\\n if (!isSpace(ch)) { break }\\n }\\n return pos\\n}\\n\\n// Skip spaces from given position in reverse.\\nStateBlock.prototype.skipSpacesBack = function skipSpacesBack (pos, min) {\\n if (pos <= min) { return pos }\\n\\n while (pos > min) {\\n if (!isSpace(this.src.charCodeAt(--pos))) { return pos + 1 }\\n }\\n return pos\\n}\\n\\n// Skip char codes from given position\\nStateBlock.prototype.skipChars = function skipChars (pos, code) {\\n for (let max = this.src.length; pos < max; pos++) {\\n if (this.src.charCodeAt(pos) !== code) { break }\\n }\\n return pos\\n}\\n\\n// Skip char codes reverse from given position - 1\\nStateBlock.prototype.skipCharsBack = function skipCharsBack (pos, code, min) {\\n if (pos <= min) { return pos }\\n\\n while (pos > min) {\\n if (code !== this.src.charCodeAt(--pos)) { return pos + 1 }\\n }\\n return pos\\n}\\n\\n// cut lines range from source.\\nStateBlock.prototype.getLines = function getLines (begin, end, indent, keepLastLF) {\\n if (begin >= end) {\\n return ''\\n }\\n\\n const queue = new Array(end - begin)\\n\\n for (let i = 0, line = begin; line < end; line++, i++) {\\n let lineIndent = 0\\n const lineStart = this.bMarks[line]\\n let first = lineStart\\n let last\\n\\n if (line + 1 < end || keepLastLF) {\\n // No need for bounds check because we have fake entry on tail.\\n last = this.eMarks[line] + 1\\n } else {\\n last = this.eMarks[line]\\n }\\n\\n while (first < last && lineIndent < indent) {\\n const ch = this.src.charCodeAt(first)\\n\\n if (isSpace(ch)) {\\n if (ch === 0x09) {\\n lineIndent += 4 - (lineIndent + this.bsCount[line]) % 4\\n } else {\\n lineIndent++\\n }\\n } else if (first - lineStart < this.tShift[line]) {\\n // patched tShift masked characters to look like spaces (blockquotes, list markers)\\n lineIndent++\\n } else {\\n break\\n }\\n\\n first++\\n }\\n\\n if (lineIndent > indent) {\\n // partially expanding tabs in code blocks, e.g '\\\\t\\\\tfoobar'\\n // with indent=2 becomes ' \\\\tfoobar'\\n queue[i] = new Array(lineIndent - indent + 1).join(' ') + this.src.slice(first, last)\\n } else {\\n queue[i] = this.src.slice(first, last)\\n }\\n }\\n\\n return queue.join('')\\n}\\n\\n// re-export Token class to use in block rules\\nStateBlock.prototype.Token = Token\\n\\nexport default StateBlock\\n\",\"// GFM table, https://github.github.com/gfm/#tables-extension-\\n\\nimport { isSpace } from '../common/utils.mjs'\\n\\n// Limit the amount of empty autocompleted cells in a table,\\n// see https://github.com/markdown-it/markdown-it/issues/1000,\\n//\\n// Both pulldown-cmark and commonmark-hs limit the number of cells this way to ~200k.\\n// We set it to 65k, which can expand user input by a factor of x370\\n// (256x256 square is 1.8kB expanded into 650kB).\\nconst MAX_AUTOCOMPLETED_CELLS = 0x10000\\n\\nfunction getLine (state, line) {\\n const pos = state.bMarks[line] + state.tShift[line]\\n const max = state.eMarks[line]\\n\\n return state.src.slice(pos, max)\\n}\\n\\nfunction escapedSplit (str) {\\n const result = []\\n const max = str.length\\n\\n let pos = 0\\n let ch = str.charCodeAt(pos)\\n let isEscaped = false\\n let lastPos = 0\\n let current = ''\\n\\n while (pos < max) {\\n if (ch === 0x7c/* | */) {\\n if (!isEscaped) {\\n // pipe separating cells, '|'\\n result.push(current + str.substring(lastPos, pos))\\n current = ''\\n lastPos = pos + 1\\n } else {\\n // escaped pipe, '\\\\|'\\n current += str.substring(lastPos, pos - 1)\\n lastPos = pos\\n }\\n }\\n\\n isEscaped = (ch === 0x5c/* \\\\ */)\\n pos++\\n\\n ch = str.charCodeAt(pos)\\n }\\n\\n result.push(current + str.substring(lastPos))\\n\\n return result\\n}\\n\\nexport default function table (state, startLine, endLine, silent) {\\n // should have at least two lines\\n if (startLine + 2 > endLine) { return false }\\n\\n let nextLine = startLine + 1\\n\\n if (state.sCount[nextLine] < state.blkIndent) { return false }\\n\\n // if it's indented more than 3 spaces, it should be a code block\\n if (state.sCount[nextLine] - state.blkIndent >= 4) { return false }\\n\\n // first character of the second line should be '|', '-', ':',\\n // and no other characters are allowed but spaces;\\n // basically, this is the equivalent of /^[-:|][-:|\\\\s]*$/ regexp\\n\\n let pos = state.bMarks[nextLine] + state.tShift[nextLine]\\n if (pos >= state.eMarks[nextLine]) { return false }\\n\\n const firstCh = state.src.charCodeAt(pos++)\\n if (firstCh !== 0x7C/* | */ && firstCh !== 0x2D/* - */ && firstCh !== 0x3A/* : */) { return false }\\n\\n if (pos >= state.eMarks[nextLine]) { return false }\\n\\n const secondCh = state.src.charCodeAt(pos++)\\n if (secondCh !== 0x7C/* | */ && secondCh !== 0x2D/* - */ && secondCh !== 0x3A/* : */ && !isSpace(secondCh)) {\\n return false\\n }\\n\\n // if first character is '-', then second character must not be a space\\n // (due to parsing ambiguity with list)\\n if (firstCh === 0x2D/* - */ && isSpace(secondCh)) { return false }\\n\\n while (pos < state.eMarks[nextLine]) {\\n const ch = state.src.charCodeAt(pos)\\n\\n if (ch !== 0x7C/* | */ && ch !== 0x2D/* - */ && ch !== 0x3A/* : */ && !isSpace(ch)) { return false }\\n\\n pos++\\n }\\n\\n let lineText = getLine(state, startLine + 1)\\n let columns = lineText.split('|')\\n const aligns = []\\n for (let i = 0; i < columns.length; i++) {\\n const t = columns[i].trim()\\n if (!t) {\\n // allow empty columns before and after table, but not in between columns;\\n // e.g. allow ` |---| `, disallow ` ---||--- `\\n if (i === 0 || i === columns.length - 1) {\\n continue\\n } else {\\n return false\\n }\\n }\\n\\n if (!/^:?-+:?$/.test(t)) { return false }\\n if (t.charCodeAt(t.length - 1) === 0x3A/* : */) {\\n aligns.push(t.charCodeAt(0) === 0x3A/* : */ ? 'center' : 'right')\\n } else if (t.charCodeAt(0) === 0x3A/* : */) {\\n aligns.push('left')\\n } else {\\n aligns.push('')\\n }\\n }\\n\\n lineText = getLine(state, startLine).trim()\\n if (lineText.indexOf('|') === -1) { return false }\\n if (state.sCount[startLine] - state.blkIndent >= 4) { return false }\\n columns = escapedSplit(lineText)\\n if (columns.length && columns[0] === '') columns.shift()\\n if (columns.length && columns[columns.length - 1] === '') columns.pop()\\n\\n // header row will define an amount of columns in the entire table,\\n // and align row should be exactly the same (the rest of the rows can differ)\\n const columnCount = columns.length\\n if (columnCount === 0 || columnCount !== aligns.length) { return false }\\n\\n if (silent) { return true }\\n\\n const oldParentType = state.parentType\\n state.parentType = 'table'\\n\\n // use 'blockquote' lists for termination because it's\\n // the most similar to tables\\n const terminatorRules = state.md.block.ruler.getRules('blockquote')\\n\\n const token_to = state.push('table_open', 'table', 1)\\n const tableLines = [startLine, 0]\\n token_to.map = tableLines\\n\\n const token_tho = state.push('thead_open', 'thead', 1)\\n token_tho.map = [startLine, startLine + 1]\\n\\n const token_htro = state.push('tr_open', 'tr', 1)\\n token_htro.map = [startLine, startLine + 1]\\n\\n for (let i = 0; i < columns.length; i++) {\\n const token_ho = state.push('th_open', 'th', 1)\\n if (aligns[i]) {\\n token_ho.attrs = [['style', 'text-align:' + aligns[i]]]\\n }\\n\\n const token_il = state.push('inline', '', 0)\\n token_il.content = columns[i].trim()\\n token_il.children = []\\n\\n state.push('th_close', 'th', -1)\\n }\\n\\n state.push('tr_close', 'tr', -1)\\n state.push('thead_close', 'thead', -1)\\n\\n let tbodyLines\\n let autocompletedCells = 0\\n\\n for (nextLine = startLine + 2; nextLine < endLine; nextLine++) {\\n if (state.sCount[nextLine] < state.blkIndent) { break }\\n\\n let terminate = false\\n for (let i = 0, l = terminatorRules.length; i < l; i++) {\\n if (terminatorRules[i](state, nextLine, endLine, true)) {\\n terminate = true\\n break\\n }\\n }\\n\\n if (terminate) { break }\\n lineText = getLine(state, nextLine).trim()\\n if (!lineText) { break }\\n if (state.sCount[nextLine] - state.blkIndent >= 4) { break }\\n columns = escapedSplit(lineText)\\n if (columns.length && columns[0] === '') columns.shift()\\n if (columns.length && columns[columns.length - 1] === '') columns.pop()\\n\\n // note: autocomplete count can be negative if user specifies more columns than header,\\n // but that does not affect intended use (which is limiting expansion)\\n autocompletedCells += columnCount - columns.length\\n if (autocompletedCells > MAX_AUTOCOMPLETED_CELLS) { break }\\n\\n if (nextLine === startLine + 2) {\\n const token_tbo = state.push('tbody_open', 'tbody', 1)\\n token_tbo.map = tbodyLines = [startLine + 2, 0]\\n }\\n\\n const token_tro = state.push('tr_open', 'tr', 1)\\n token_tro.map = [nextLine, nextLine + 1]\\n\\n for (let i = 0; i < columnCount; i++) {\\n const token_tdo = state.push('td_open', 'td', 1)\\n if (aligns[i]) {\\n token_tdo.attrs = [['style', 'text-align:' + aligns[i]]]\\n }\\n\\n const token_il = state.push('inline', '', 0)\\n token_il.content = columns[i] ? columns[i].trim() : ''\\n token_il.children = []\\n\\n state.push('td_close', 'td', -1)\\n }\\n state.push('tr_close', 'tr', -1)\\n }\\n\\n if (tbodyLines) {\\n state.push('tbody_close', 'tbody', -1)\\n tbodyLines[1] = nextLine\\n }\\n\\n state.push('table_close', 'table', -1)\\n tableLines[1] = nextLine\\n\\n state.parentType = oldParentType\\n state.line = nextLine\\n return true\\n}\\n\",\"// Code block (4 spaces padded)\\n\\nexport default function code (state, startLine, endLine/*, silent */) {\\n if (state.sCount[startLine] - state.blkIndent < 4) { return false }\\n\\n let nextLine = startLine + 1\\n let last = nextLine\\n\\n while (nextLine < endLine) {\\n if (state.isEmpty(nextLine)) {\\n nextLine++\\n continue\\n }\\n\\n if (state.sCount[nextLine] - state.blkIndent >= 4) {\\n nextLine++\\n last = nextLine\\n continue\\n }\\n break\\n }\\n\\n state.line = last\\n\\n const token = state.push('code_block', 'code', 0)\\n token.content = state.getLines(startLine, last, 4 + state.blkIndent, false) + '\\\\n'\\n token.map = [startLine, state.line]\\n\\n return true\\n}\\n\",\"// fences (``` lang, ~~~ lang)\\n\\nexport default function fence (state, startLine, endLine, silent) {\\n let pos = state.bMarks[startLine] + state.tShift[startLine]\\n let max = state.eMarks[startLine]\\n\\n // if it's indented more than 3 spaces, it should be a code block\\n if (state.sCount[startLine] - state.blkIndent >= 4) { return false }\\n\\n if (pos + 3 > max) { return false }\\n\\n const marker = state.src.charCodeAt(pos)\\n\\n if (marker !== 0x7E/* ~ */ && marker !== 0x60 /* ` */) {\\n return false\\n }\\n\\n // scan marker length\\n let mem = pos\\n pos = state.skipChars(pos, marker)\\n\\n let len = pos - mem\\n\\n if (len < 3) { return false }\\n\\n const markup = state.src.slice(mem, pos)\\n const params = state.src.slice(pos, max)\\n\\n if (marker === 0x60 /* ` */) {\\n if (params.indexOf(String.fromCharCode(marker)) >= 0) {\\n return false\\n }\\n }\\n\\n // Since start is found, we can report success here in validation mode\\n if (silent) { return true }\\n\\n // search end of block\\n let nextLine = startLine\\n let haveEndMarker = false\\n\\n for (;;) {\\n nextLine++\\n if (nextLine >= endLine) {\\n // unclosed block should be autoclosed by end of document.\\n // also block seems to be autoclosed by end of parent\\n break\\n }\\n\\n pos = mem = state.bMarks[nextLine] + state.tShift[nextLine]\\n max = state.eMarks[nextLine]\\n\\n if (pos < max && state.sCount[nextLine] < state.blkIndent) {\\n // non-empty line with negative indent should stop the list:\\n // - ```\\n // test\\n break\\n }\\n\\n if (state.src.charCodeAt(pos) !== marker) { continue }\\n\\n if (state.sCount[nextLine] - state.blkIndent >= 4) {\\n // closing fence should be indented less than 4 spaces\\n continue\\n }\\n\\n pos = state.skipChars(pos, marker)\\n\\n // closing code fence must be at least as long as the opening one\\n if (pos - mem < len) { continue }\\n\\n // make sure tail has spaces only\\n pos = state.skipSpaces(pos)\\n\\n if (pos < max) { continue }\\n\\n haveEndMarker = true\\n // found!\\n break\\n }\\n\\n // If a fence has heading spaces, they should be removed from its inner block\\n len = state.sCount[startLine]\\n\\n state.line = nextLine + (haveEndMarker ? 1 : 0)\\n\\n const token = state.push('fence', 'code', 0)\\n token.info = params\\n token.content = state.getLines(startLine + 1, nextLine, len, true)\\n token.markup = markup\\n token.map = [startLine, state.line]\\n\\n return true\\n}\\n\",\"// Block quotes\\n\\nimport { isSpace } from '../common/utils.mjs'\\n\\nexport default function blockquote (state, startLine, endLine, silent) {\\n let pos = state.bMarks[startLine] + state.tShift[startLine]\\n let max = state.eMarks[startLine]\\n\\n const oldLineMax = state.lineMax\\n\\n // if it's indented more than 3 spaces, it should be a code block\\n if (state.sCount[startLine] - state.blkIndent >= 4) { return false }\\n\\n // check the block quote marker\\n if (state.src.charCodeAt(pos) !== 0x3E/* > */) { return false }\\n\\n // we know that it's going to be a valid blockquote,\\n // so no point trying to find the end of it in silent mode\\n if (silent) { return true }\\n\\n const oldBMarks = []\\n const oldBSCount = []\\n const oldSCount = []\\n const oldTShift = []\\n\\n const terminatorRules = state.md.block.ruler.getRules('blockquote')\\n\\n const oldParentType = state.parentType\\n state.parentType = 'blockquote'\\n let lastLineEmpty = false\\n let nextLine\\n\\n // Search the end of the block\\n //\\n // Block ends with either:\\n // 1. an empty line outside:\\n // ```\\n // > test\\n //\\n // ```\\n // 2. an empty line inside:\\n // ```\\n // >\\n // test\\n // ```\\n // 3. another tag:\\n // ```\\n // > test\\n // - - -\\n // ```\\n for (nextLine = startLine; nextLine < endLine; nextLine++) {\\n // check if it's outdented, i.e. it's inside list item and indented\\n // less than said list item:\\n //\\n // ```\\n // 1. anything\\n // > current blockquote\\n // 2. checking this line\\n // ```\\n const isOutdented = state.sCount[nextLine] < state.blkIndent\\n\\n pos = state.bMarks[nextLine] + state.tShift[nextLine]\\n max = state.eMarks[nextLine]\\n\\n if (pos >= max) {\\n // Case 1: line is not inside the blockquote, and this line is empty.\\n break\\n }\\n\\n if (state.src.charCodeAt(pos++) === 0x3E/* > */ && !isOutdented) {\\n // This line is inside the blockquote.\\n\\n // set offset past spaces and \\\">\\\"\\n let initial = state.sCount[nextLine] + 1\\n let spaceAfterMarker\\n let adjustTab\\n\\n // skip one optional space after '>'\\n if (state.src.charCodeAt(pos) === 0x20 /* space */) {\\n // ' > test '\\n // ^ -- position start of line here:\\n pos++\\n initial++\\n adjustTab = false\\n spaceAfterMarker = true\\n } else if (state.src.charCodeAt(pos) === 0x09 /* tab */) {\\n spaceAfterMarker = true\\n\\n if ((state.bsCount[nextLine] + initial) % 4 === 3) {\\n // ' >\\\\t test '\\n // ^ -- position start of line here (tab has width===1)\\n pos++\\n initial++\\n adjustTab = false\\n } else {\\n // ' >\\\\t test '\\n // ^ -- position start of line here + shift bsCount slightly\\n // to make extra space appear\\n adjustTab = true\\n }\\n } else {\\n spaceAfterMarker = false\\n }\\n\\n let offset = initial\\n oldBMarks.push(state.bMarks[nextLine])\\n state.bMarks[nextLine] = pos\\n\\n while (pos < max) {\\n const ch = state.src.charCodeAt(pos)\\n\\n if (isSpace(ch)) {\\n if (ch === 0x09) {\\n offset += 4 - (offset + state.bsCount[nextLine] + (adjustTab ? 1 : 0)) % 4\\n } else {\\n offset++\\n }\\n } else {\\n break\\n }\\n\\n pos++\\n }\\n\\n lastLineEmpty = pos >= max\\n\\n oldBSCount.push(state.bsCount[nextLine])\\n state.bsCount[nextLine] = state.sCount[nextLine] + 1 + (spaceAfterMarker ? 1 : 0)\\n\\n oldSCount.push(state.sCount[nextLine])\\n state.sCount[nextLine] = offset - initial\\n\\n oldTShift.push(state.tShift[nextLine])\\n state.tShift[nextLine] = pos - state.bMarks[nextLine]\\n continue\\n }\\n\\n // Case 2: line is not inside the blockquote, and the last line was empty.\\n if (lastLineEmpty) { break }\\n\\n // Case 3: another tag found.\\n let terminate = false\\n for (let i = 0, l = terminatorRules.length; i < l; i++) {\\n if (terminatorRules[i](state, nextLine, endLine, true)) {\\n terminate = true\\n break\\n }\\n }\\n\\n if (terminate) {\\n // Quirk to enforce \\\"hard termination mode\\\" for paragraphs;\\n // normally if you call `tokenize(state, startLine, nextLine)`,\\n // paragraphs will look below nextLine for paragraph continuation,\\n // but if blockquote is terminated by another tag, they shouldn't\\n state.lineMax = nextLine\\n\\n if (state.blkIndent !== 0) {\\n // state.blkIndent was non-zero, we now set it to zero,\\n // so we need to re-calculate all offsets to appear as\\n // if indent wasn't changed\\n oldBMarks.push(state.bMarks[nextLine])\\n oldBSCount.push(state.bsCount[nextLine])\\n oldTShift.push(state.tShift[nextLine])\\n oldSCount.push(state.sCount[nextLine])\\n state.sCount[nextLine] -= state.blkIndent\\n }\\n\\n break\\n }\\n\\n oldBMarks.push(state.bMarks[nextLine])\\n oldBSCount.push(state.bsCount[nextLine])\\n oldTShift.push(state.tShift[nextLine])\\n oldSCount.push(state.sCount[nextLine])\\n\\n // A negative indentation means that this is a paragraph continuation\\n //\\n state.sCount[nextLine] = -1\\n }\\n\\n const oldIndent = state.blkIndent\\n state.blkIndent = 0\\n\\n const token_o = state.push('blockquote_open', 'blockquote', 1)\\n token_o.markup = '>'\\n const lines = [startLine, 0]\\n token_o.map = lines\\n\\n state.md.block.tokenize(state, startLine, nextLine)\\n\\n const token_c = state.push('blockquote_close', 'blockquote', -1)\\n token_c.markup = '>'\\n\\n state.lineMax = oldLineMax\\n state.parentType = oldParentType\\n lines[1] = state.line\\n\\n // Restore original tShift; this might not be necessary since the parser\\n // has already been here, but just to make sure we can do that.\\n for (let i = 0; i < oldTShift.length; i++) {\\n state.bMarks[i + startLine] = oldBMarks[i]\\n state.tShift[i + startLine] = oldTShift[i]\\n state.sCount[i + startLine] = oldSCount[i]\\n state.bsCount[i + startLine] = oldBSCount[i]\\n }\\n state.blkIndent = oldIndent\\n\\n return true\\n}\\n\",\"// Horizontal rule\\n\\nimport { isSpace } from '../common/utils.mjs'\\n\\nexport default function hr (state, startLine, endLine, silent) {\\n const max = state.eMarks[startLine]\\n // if it's indented more than 3 spaces, it should be a code block\\n if (state.sCount[startLine] - state.blkIndent >= 4) { return false }\\n\\n let pos = state.bMarks[startLine] + state.tShift[startLine]\\n const marker = state.src.charCodeAt(pos++)\\n\\n // Check hr marker\\n if (marker !== 0x2A/* * */ &&\\n marker !== 0x2D/* - */ &&\\n marker !== 0x5F/* _ */) {\\n return false\\n }\\n\\n // markers can be mixed with spaces, but there should be at least 3 of them\\n\\n let cnt = 1\\n while (pos < max) {\\n const ch = state.src.charCodeAt(pos++)\\n if (ch !== marker && !isSpace(ch)) { return false }\\n if (ch === marker) { cnt++ }\\n }\\n\\n if (cnt < 3) { return false }\\n\\n if (silent) { return true }\\n\\n state.line = startLine + 1\\n\\n const token = state.push('hr', 'hr', 0)\\n token.map = [startLine, state.line]\\n token.markup = Array(cnt + 1).join(String.fromCharCode(marker))\\n\\n return true\\n}\\n\",\"// Lists\\n\\nimport { isSpace } from '../common/utils.mjs'\\n\\n// Search `[-+*][\\\\n ]`, returns next pos after marker on success\\n// or -1 on fail.\\nfunction skipBulletListMarker (state, startLine) {\\n const max = state.eMarks[startLine]\\n let pos = state.bMarks[startLine] + state.tShift[startLine]\\n\\n const marker = state.src.charCodeAt(pos++)\\n // Check bullet\\n if (marker !== 0x2A/* * */ &&\\n marker !== 0x2D/* - */ &&\\n marker !== 0x2B/* + */) {\\n return -1\\n }\\n\\n if (pos < max) {\\n const ch = state.src.charCodeAt(pos)\\n\\n if (!isSpace(ch)) {\\n // \\\" -test \\\" - is not a list item\\n return -1\\n }\\n }\\n\\n return pos\\n}\\n\\n// Search `\\\\d+[.)][\\\\n ]`, returns next pos after marker on success\\n// or -1 on fail.\\nfunction skipOrderedListMarker (state, startLine) {\\n const start = state.bMarks[startLine] + state.tShift[startLine]\\n const max = state.eMarks[startLine]\\n let pos = start\\n\\n // List marker should have at least 2 chars (digit + dot)\\n if (pos + 1 >= max) { return -1 }\\n\\n let ch = state.src.charCodeAt(pos++)\\n\\n if (ch < 0x30/* 0 */ || ch > 0x39/* 9 */) { return -1 }\\n\\n for (;;) {\\n // EOL -> fail\\n if (pos >= max) { return -1 }\\n\\n ch = state.src.charCodeAt(pos++)\\n\\n if (ch >= 0x30/* 0 */ && ch <= 0x39/* 9 */) {\\n // List marker should have no more than 9 digits\\n // (prevents integer overflow in browsers)\\n if (pos - start >= 10) { return -1 }\\n\\n continue\\n }\\n\\n // found valid marker\\n if (ch === 0x29/* ) */ || ch === 0x2e/* . */) {\\n break\\n }\\n\\n return -1\\n }\\n\\n if (pos < max) {\\n ch = state.src.charCodeAt(pos)\\n\\n if (!isSpace(ch)) {\\n // \\\" 1.test \\\" - is not a list item\\n return -1\\n }\\n }\\n return pos\\n}\\n\\nfunction markTightParagraphs (state, idx) {\\n const level = state.level + 2\\n\\n for (let i = idx + 2, l = state.tokens.length - 2; i < l; i++) {\\n if (state.tokens[i].level === level && state.tokens[i].type === 'paragraph_open') {\\n state.tokens[i + 2].hidden = true\\n state.tokens[i].hidden = true\\n i += 2\\n }\\n }\\n}\\n\\nexport default function list (state, startLine, endLine, silent) {\\n let max, pos, start, token\\n let nextLine = startLine\\n let tight = true\\n\\n // if it's indented more than 3 spaces, it should be a code block\\n if (state.sCount[nextLine] - state.blkIndent >= 4) { return false }\\n\\n // Special case:\\n // - item 1\\n // - item 2\\n // - item 3\\n // - item 4\\n // - this one is a paragraph continuation\\n if (state.listIndent >= 0 &&\\n state.sCount[nextLine] - state.listIndent >= 4 &&\\n state.sCount[nextLine] < state.blkIndent) {\\n return false\\n }\\n\\n let isTerminatingParagraph = false\\n\\n // limit conditions when list can interrupt\\n // a paragraph (validation mode only)\\n if (silent && state.parentType === 'paragraph') {\\n // Next list item should still terminate previous list item;\\n //\\n // This code can fail if plugins use blkIndent as well as lists,\\n // but I hope the spec gets fixed long before that happens.\\n //\\n if (state.sCount[nextLine] >= state.blkIndent) {\\n isTerminatingParagraph = true\\n }\\n }\\n\\n // Detect list type and position after marker\\n let isOrdered\\n let markerValue\\n let posAfterMarker\\n if ((posAfterMarker = skipOrderedListMarker(state, nextLine)) >= 0) {\\n isOrdered = true\\n start = state.bMarks[nextLine] + state.tShift[nextLine]\\n markerValue = Number(state.src.slice(start, posAfterMarker - 1))\\n\\n // If we're starting a new ordered list right after\\n // a paragraph, it should start with 1.\\n if (isTerminatingParagraph && markerValue !== 1) return false\\n } else if ((posAfterMarker = skipBulletListMarker(state, nextLine)) >= 0) {\\n isOrdered = false\\n } else {\\n return false\\n }\\n\\n // If we're starting a new unordered list right after\\n // a paragraph, first line should not be empty.\\n if (isTerminatingParagraph) {\\n if (state.skipSpaces(posAfterMarker) >= state.eMarks[nextLine]) return false\\n }\\n\\n // For validation mode we can terminate immediately\\n if (silent) { return true }\\n\\n // We should terminate list on style change. Remember first one to compare.\\n const markerCharCode = state.src.charCodeAt(posAfterMarker - 1)\\n\\n // Start list\\n const listTokIdx = state.tokens.length\\n\\n if (isOrdered) {\\n token = state.push('ordered_list_open', 'ol', 1)\\n if (markerValue !== 1) {\\n token.attrs = [['start', markerValue]]\\n }\\n } else {\\n token = state.push('bullet_list_open', 'ul', 1)\\n }\\n\\n const listLines = [nextLine, 0]\\n token.map = listLines\\n token.markup = String.fromCharCode(markerCharCode)\\n\\n //\\n // Iterate list items\\n //\\n\\n let prevEmptyEnd = false\\n const terminatorRules = state.md.block.ruler.getRules('list')\\n\\n const oldParentType = state.parentType\\n state.parentType = 'list'\\n\\n while (nextLine < endLine) {\\n pos = posAfterMarker\\n max = state.eMarks[nextLine]\\n\\n const initial = state.sCount[nextLine] + posAfterMarker - (state.bMarks[nextLine] + state.tShift[nextLine])\\n let offset = initial\\n\\n while (pos < max) {\\n const ch = state.src.charCodeAt(pos)\\n\\n if (ch === 0x09) {\\n offset += 4 - (offset + state.bsCount[nextLine]) % 4\\n } else if (ch === 0x20) {\\n offset++\\n } else {\\n break\\n }\\n\\n pos++\\n }\\n\\n const contentStart = pos\\n let indentAfterMarker\\n\\n if (contentStart >= max) {\\n // trimming space in \\\"- \\\\n 3\\\" case, indent is 1 here\\n indentAfterMarker = 1\\n } else {\\n indentAfterMarker = offset - initial\\n }\\n\\n // If we have more than 4 spaces, the indent is 1\\n // (the rest is just indented code block)\\n if (indentAfterMarker > 4) { indentAfterMarker = 1 }\\n\\n // \\\" - test\\\"\\n // ^^^^^ - calculating total length of this thing\\n const indent = initial + indentAfterMarker\\n\\n // Run subparser & write tokens\\n token = state.push('list_item_open', 'li', 1)\\n token.markup = String.fromCharCode(markerCharCode)\\n const itemLines = [nextLine, 0]\\n token.map = itemLines\\n if (isOrdered) {\\n token.info = state.src.slice(start, posAfterMarker - 1)\\n }\\n\\n // change current state, then restore it after parser subcall\\n const oldTight = state.tight\\n const oldTShift = state.tShift[nextLine]\\n const oldSCount = state.sCount[nextLine]\\n\\n // - example list\\n // ^ listIndent position will be here\\n // ^ blkIndent position will be here\\n //\\n const oldListIndent = state.listIndent\\n state.listIndent = state.blkIndent\\n state.blkIndent = indent\\n\\n state.tight = true\\n state.tShift[nextLine] = contentStart - state.bMarks[nextLine]\\n state.sCount[nextLine] = offset\\n\\n if (contentStart >= max && state.isEmpty(nextLine + 1)) {\\n // workaround for this case\\n // (list item is empty, list terminates before \\\"foo\\\"):\\n // ~~~~~~~~\\n // -\\n //\\n // foo\\n // ~~~~~~~~\\n state.line = Math.min(state.line + 2, endLine)\\n } else {\\n state.md.block.tokenize(state, nextLine, endLine, true)\\n }\\n\\n // If any of list item is tight, mark list as tight\\n if (!state.tight || prevEmptyEnd) {\\n tight = false\\n }\\n // Item become loose if finish with empty line,\\n // but we should filter last element, because it means list finish\\n prevEmptyEnd = (state.line - nextLine) > 1 && state.isEmpty(state.line - 1)\\n\\n state.blkIndent = state.listIndent\\n state.listIndent = oldListIndent\\n state.tShift[nextLine] = oldTShift\\n state.sCount[nextLine] = oldSCount\\n state.tight = oldTight\\n\\n token = state.push('list_item_close', 'li', -1)\\n token.markup = String.fromCharCode(markerCharCode)\\n\\n nextLine = state.line\\n itemLines[1] = nextLine\\n\\n if (nextLine >= endLine) { break }\\n\\n //\\n // Try to check if list is terminated or continued.\\n //\\n if (state.sCount[nextLine] < state.blkIndent) { break }\\n\\n // if it's indented more than 3 spaces, it should be a code block\\n if (state.sCount[nextLine] - state.blkIndent >= 4) { break }\\n\\n // fail if terminating block found\\n let terminate = false\\n for (let i = 0, l = terminatorRules.length; i < l; i++) {\\n if (terminatorRules[i](state, nextLine, endLine, true)) {\\n terminate = true\\n break\\n }\\n }\\n if (terminate) { break }\\n\\n // fail if list has another type\\n if (isOrdered) {\\n posAfterMarker = skipOrderedListMarker(state, nextLine)\\n if (posAfterMarker < 0) { break }\\n start = state.bMarks[nextLine] + state.tShift[nextLine]\\n } else {\\n posAfterMarker = skipBulletListMarker(state, nextLine)\\n if (posAfterMarker < 0) { break }\\n }\\n\\n if (markerCharCode !== state.src.charCodeAt(posAfterMarker - 1)) { break }\\n }\\n\\n // Finalize list\\n if (isOrdered) {\\n token = state.push('ordered_list_close', 'ol', -1)\\n } else {\\n token = state.push('bullet_list_close', 'ul', -1)\\n }\\n token.markup = String.fromCharCode(markerCharCode)\\n\\n listLines[1] = nextLine\\n state.line = nextLine\\n\\n state.parentType = oldParentType\\n\\n // mark paragraphs tight if needed\\n if (tight) {\\n markTightParagraphs(state, listTokIdx)\\n }\\n\\n return true\\n}\\n\",\"import { isSpace, normalizeReference } from '../common/utils.mjs'\\n\\nexport default function reference (state, startLine, _endLine, silent) {\\n let pos = state.bMarks[startLine] + state.tShift[startLine]\\n let max = state.eMarks[startLine]\\n let nextLine = startLine + 1\\n\\n // if it's indented more than 3 spaces, it should be a code block\\n if (state.sCount[startLine] - state.blkIndent >= 4) { return false }\\n\\n if (state.src.charCodeAt(pos) !== 0x5B/* [ */) { return false }\\n\\n function getNextLine (nextLine) {\\n const endLine = state.lineMax\\n\\n if (nextLine >= endLine || state.isEmpty(nextLine)) {\\n // empty line or end of input\\n return null\\n }\\n\\n let isContinuation = false\\n\\n // this would be a code block normally, but after paragraph\\n // it's considered a lazy continuation regardless of what's there\\n if (state.sCount[nextLine] - state.blkIndent > 3) { isContinuation = true }\\n\\n // quirk for blockquotes, this line should already be checked by that rule\\n if (state.sCount[nextLine] < 0) { isContinuation = true }\\n\\n if (!isContinuation) {\\n const terminatorRules = state.md.block.ruler.getRules('reference')\\n const oldParentType = state.parentType\\n state.parentType = 'reference'\\n\\n // Some tags can terminate paragraph without empty line.\\n let terminate = false\\n for (let i = 0, l = terminatorRules.length; i < l; i++) {\\n if (terminatorRules[i](state, nextLine, endLine, true)) {\\n terminate = true\\n break\\n }\\n }\\n\\n state.parentType = oldParentType\\n if (terminate) {\\n // terminated by another block\\n return null\\n }\\n }\\n\\n const pos = state.bMarks[nextLine] + state.tShift[nextLine]\\n const max = state.eMarks[nextLine]\\n\\n // max + 1 explicitly includes the newline\\n return state.src.slice(pos, max + 1)\\n }\\n\\n let str = state.src.slice(pos, max + 1)\\n\\n max = str.length\\n let labelEnd = -1\\n\\n for (pos = 1; pos < max; pos++) {\\n const ch = str.charCodeAt(pos)\\n if (ch === 0x5B /* [ */) {\\n return false\\n } else if (ch === 0x5D /* ] */) {\\n labelEnd = pos\\n break\\n } else if (ch === 0x0A /* \\\\n */) {\\n const lineContent = getNextLine(nextLine)\\n if (lineContent !== null) {\\n str += lineContent\\n max = str.length\\n nextLine++\\n }\\n } else if (ch === 0x5C /* \\\\ */) {\\n pos++\\n if (pos < max && str.charCodeAt(pos) === 0x0A) {\\n const lineContent = getNextLine(nextLine)\\n if (lineContent !== null) {\\n str += lineContent\\n max = str.length\\n nextLine++\\n }\\n }\\n }\\n }\\n\\n if (labelEnd < 0 || str.charCodeAt(labelEnd + 1) !== 0x3A/* : */) { return false }\\n\\n // [label]: destination 'title'\\n // ^^^ skip optional whitespace here\\n for (pos = labelEnd + 2; pos < max; pos++) {\\n const ch = str.charCodeAt(pos)\\n if (ch === 0x0A) {\\n const lineContent = getNextLine(nextLine)\\n if (lineContent !== null) {\\n str += lineContent\\n max = str.length\\n nextLine++\\n }\\n } else if (isSpace(ch)) {\\n /* eslint no-empty:0 */\\n } else {\\n break\\n }\\n }\\n\\n // [label]: destination 'title'\\n // ^^^^^^^^^^^ parse this\\n const destRes = state.md.helpers.parseLinkDestination(str, pos, max)\\n if (!destRes.ok) { return false }\\n\\n const href = state.md.normalizeLink(destRes.str)\\n if (!state.md.validateLink(href)) { return false }\\n\\n pos = destRes.pos\\n\\n // save cursor state, we could require to rollback later\\n const destEndPos = pos\\n const destEndLineNo = nextLine\\n\\n // [label]: destination 'title'\\n // ^^^ skipping those spaces\\n const start = pos\\n for (; pos < max; pos++) {\\n const ch = str.charCodeAt(pos)\\n if (ch === 0x0A) {\\n const lineContent = getNextLine(nextLine)\\n if (lineContent !== null) {\\n str += lineContent\\n max = str.length\\n nextLine++\\n }\\n } else if (isSpace(ch)) {\\n /* eslint no-empty:0 */\\n } else {\\n break\\n }\\n }\\n\\n // [label]: destination 'title'\\n // ^^^^^^^ parse this\\n let titleRes = state.md.helpers.parseLinkTitle(str, pos, max)\\n while (titleRes.can_continue) {\\n const lineContent = getNextLine(nextLine)\\n if (lineContent === null) break\\n str += lineContent\\n pos = max\\n max = str.length\\n nextLine++\\n titleRes = state.md.helpers.parseLinkTitle(str, pos, max, titleRes)\\n }\\n let title\\n\\n if (pos < max && start !== pos && titleRes.ok) {\\n title = titleRes.str\\n pos = titleRes.pos\\n } else {\\n title = ''\\n pos = destEndPos\\n nextLine = destEndLineNo\\n }\\n\\n // skip trailing spaces until the rest of the line\\n while (pos < max) {\\n const ch = str.charCodeAt(pos)\\n if (!isSpace(ch)) { break }\\n pos++\\n }\\n\\n if (pos < max && str.charCodeAt(pos) !== 0x0A) {\\n if (title) {\\n // garbage at the end of the line after title,\\n // but it could still be a valid reference if we roll back\\n title = ''\\n pos = destEndPos\\n nextLine = destEndLineNo\\n while (pos < max) {\\n const ch = str.charCodeAt(pos)\\n if (!isSpace(ch)) { break }\\n pos++\\n }\\n }\\n }\\n\\n if (pos < max && str.charCodeAt(pos) !== 0x0A) {\\n // garbage at the end of the line\\n return false\\n }\\n\\n const label = normalizeReference(str.slice(1, labelEnd))\\n if (!label) {\\n // CommonMark 0.20 disallows empty labels\\n return false\\n }\\n\\n // Reference can not terminate anything. This check is for safety only.\\n /* istanbul ignore if */\\n if (silent) { return true }\\n\\n if (typeof state.env.references === 'undefined') {\\n state.env.references = {}\\n }\\n if (typeof state.env.references[label] === 'undefined') {\\n state.env.references[label] = { title, href }\\n }\\n\\n state.line = nextLine\\n return true\\n}\\n\",\"// List of valid html blocks names, according to commonmark spec\\n// https://spec.commonmark.org/0.30/#html-blocks\\n\\nexport default [\\n 'address',\\n 'article',\\n 'aside',\\n 'base',\\n 'basefont',\\n 'blockquote',\\n 'body',\\n 'caption',\\n 'center',\\n 'col',\\n 'colgroup',\\n 'dd',\\n 'details',\\n 'dialog',\\n 'dir',\\n 'div',\\n 'dl',\\n 'dt',\\n 'fieldset',\\n 'figcaption',\\n 'figure',\\n 'footer',\\n 'form',\\n 'frame',\\n 'frameset',\\n 'h1',\\n 'h2',\\n 'h3',\\n 'h4',\\n 'h5',\\n 'h6',\\n 'head',\\n 'header',\\n 'hr',\\n 'html',\\n 'iframe',\\n 'legend',\\n 'li',\\n 'link',\\n 'main',\\n 'menu',\\n 'menuitem',\\n 'nav',\\n 'noframes',\\n 'ol',\\n 'optgroup',\\n 'option',\\n 'p',\\n 'param',\\n 'search',\\n 'section',\\n 'summary',\\n 'table',\\n 'tbody',\\n 'td',\\n 'tfoot',\\n 'th',\\n 'thead',\\n 'title',\\n 'tr',\\n 'track',\\n 'ul'\\n]\\n\",\"// Regexps to match html elements\\n\\nconst attr_name = '[a-zA-Z_:][a-zA-Z0-9:._-]*'\\n\\nconst unquoted = '[^\\\"\\\\'=<>`\\\\\\\\x00-\\\\\\\\x20]+'\\nconst single_quoted = \\\"'[^']*'\\\"\\nconst double_quoted = '\\\"[^\\\"]*\\\"'\\n\\nconst attr_value = '(?:' + unquoted + '|' + single_quoted + '|' + double_quoted + ')'\\n\\nconst attribute = '(?:\\\\\\\\s+' + attr_name + '(?:\\\\\\\\s*=\\\\\\\\s*' + attr_value + ')?)'\\n\\nconst open_tag = '<[A-Za-z][A-Za-z0-9\\\\\\\\-]*' + attribute + '*\\\\\\\\s*\\\\\\\\/?>'\\n\\nconst close_tag = '<\\\\\\\\/[A-Za-z][A-Za-z0-9\\\\\\\\-]*\\\\\\\\s*>'\\nconst comment = ''\\nconst processing = '<[?][\\\\\\\\s\\\\\\\\S]*?[?]>'\\nconst declaration = ']*>'\\nconst cdata = ''\\n\\nconst HTML_TAG_RE = new RegExp('^(?:' + open_tag + '|' + close_tag + '|' + comment +\\n '|' + processing + '|' + declaration + '|' + cdata + ')')\\nconst HTML_OPEN_CLOSE_TAG_RE = new RegExp('^(?:' + open_tag + '|' + close_tag + ')')\\n\\nexport { HTML_TAG_RE, HTML_OPEN_CLOSE_TAG_RE }\\n\",\"// HTML block\\n\\nimport block_names from '../common/html_blocks.mjs'\\nimport { HTML_OPEN_CLOSE_TAG_RE } from '../common/html_re.mjs'\\n\\n// An array of opening and corresponding closing sequences for html tags,\\n// last argument defines whether it can terminate a paragraph or not\\n//\\nconst HTML_SEQUENCES = [\\n [/^<(script|pre|style|textarea)(?=(\\\\s|>|$))/i, /<\\\\/(script|pre|style|textarea)>/i, true],\\n [/^/, true],\\n [/^<\\\\?/, /\\\\?>/, true],\\n [/^/, true],\\n [/^/, true],\\n [new RegExp('^|$))', 'i'), /^$/, true],\\n [new RegExp(HTML_OPEN_CLOSE_TAG_RE.source + '\\\\\\\\s*$'), /^$/, false]\\n]\\n\\nexport default function html_block (state, startLine, endLine, silent) {\\n let pos = state.bMarks[startLine] + state.tShift[startLine]\\n let max = state.eMarks[startLine]\\n\\n // if it's indented more than 3 spaces, it should be a code block\\n if (state.sCount[startLine] - state.blkIndent >= 4) { return false }\\n\\n if (!state.md.options.html) { return false }\\n\\n if (state.src.charCodeAt(pos) !== 0x3C/* < */) { return false }\\n\\n let lineText = state.src.slice(pos, max)\\n\\n let i = 0\\n for (; i < HTML_SEQUENCES.length; i++) {\\n if (HTML_SEQUENCES[i][0].test(lineText)) { break }\\n }\\n if (i === HTML_SEQUENCES.length) { return false }\\n\\n if (silent) {\\n // true if this sequence can be a terminator, false otherwise\\n return HTML_SEQUENCES[i][2]\\n }\\n\\n let nextLine = startLine + 1\\n\\n // If we are here - we detected HTML block.\\n // Let's roll down till block end.\\n if (!HTML_SEQUENCES[i][1].test(lineText)) {\\n for (; nextLine < endLine; nextLine++) {\\n if (state.sCount[nextLine] < state.blkIndent) { break }\\n\\n pos = state.bMarks[nextLine] + state.tShift[nextLine]\\n max = state.eMarks[nextLine]\\n lineText = state.src.slice(pos, max)\\n\\n if (HTML_SEQUENCES[i][1].test(lineText)) {\\n if (lineText.length !== 0) { nextLine++ }\\n break\\n }\\n }\\n }\\n\\n state.line = nextLine\\n\\n const token = state.push('html_block', '', 0)\\n token.map = [startLine, nextLine]\\n token.content = state.getLines(startLine, nextLine, state.blkIndent, true)\\n\\n return true\\n}\\n\",\"// heading (#, ##, ...)\\n\\nimport { isSpace } from '../common/utils.mjs'\\n\\nexport default function heading (state, startLine, endLine, silent) {\\n let pos = state.bMarks[startLine] + state.tShift[startLine]\\n let max = state.eMarks[startLine]\\n\\n // if it's indented more than 3 spaces, it should be a code block\\n if (state.sCount[startLine] - state.blkIndent >= 4) { return false }\\n\\n let ch = state.src.charCodeAt(pos)\\n\\n if (ch !== 0x23/* # */ || pos >= max) { return false }\\n\\n // count heading level\\n let level = 1\\n ch = state.src.charCodeAt(++pos)\\n while (ch === 0x23/* # */ && pos < max && level <= 6) {\\n level++\\n ch = state.src.charCodeAt(++pos)\\n }\\n\\n if (level > 6 || (pos < max && !isSpace(ch))) { return false }\\n\\n if (silent) { return true }\\n\\n // Let's cut tails like ' ### ' from the end of string\\n\\n max = state.skipSpacesBack(max, pos)\\n const tmp = state.skipCharsBack(max, 0x23, pos) // #\\n if (tmp > pos && isSpace(state.src.charCodeAt(tmp - 1))) {\\n max = tmp\\n }\\n\\n state.line = startLine + 1\\n\\n const token_o = state.push('heading_open', 'h' + String(level), 1)\\n token_o.markup = '########'.slice(0, level)\\n token_o.map = [startLine, state.line]\\n\\n const token_i = state.push('inline', '', 0)\\n token_i.content = state.src.slice(pos, max).trim()\\n token_i.map = [startLine, state.line]\\n token_i.children = []\\n\\n const token_c = state.push('heading_close', 'h' + String(level), -1)\\n token_c.markup = '########'.slice(0, level)\\n\\n return true\\n}\\n\",\"// lheading (---, ===)\\n\\nexport default function lheading (state, startLine, endLine/*, silent */) {\\n const terminatorRules = state.md.block.ruler.getRules('paragraph')\\n\\n // if it's indented more than 3 spaces, it should be a code block\\n if (state.sCount[startLine] - state.blkIndent >= 4) { return false }\\n\\n const oldParentType = state.parentType\\n state.parentType = 'paragraph' // use paragraph to match terminatorRules\\n\\n // jump line-by-line until empty one or EOF\\n let level = 0\\n let marker\\n let nextLine = startLine + 1\\n\\n for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) {\\n // this would be a code block normally, but after paragraph\\n // it's considered a lazy continuation regardless of what's there\\n if (state.sCount[nextLine] - state.blkIndent > 3) { continue }\\n\\n //\\n // Check for underline in setext header\\n //\\n if (state.sCount[nextLine] >= state.blkIndent) {\\n let pos = state.bMarks[nextLine] + state.tShift[nextLine]\\n const max = state.eMarks[nextLine]\\n\\n if (pos < max) {\\n marker = state.src.charCodeAt(pos)\\n\\n if (marker === 0x2D/* - */ || marker === 0x3D/* = */) {\\n pos = state.skipChars(pos, marker)\\n pos = state.skipSpaces(pos)\\n\\n if (pos >= max) {\\n level = (marker === 0x3D/* = */ ? 1 : 2)\\n break\\n }\\n }\\n }\\n }\\n\\n // quirk for blockquotes, this line should already be checked by that rule\\n if (state.sCount[nextLine] < 0) { continue }\\n\\n // Some tags can terminate paragraph without empty line.\\n let terminate = false\\n for (let i = 0, l = terminatorRules.length; i < l; i++) {\\n if (terminatorRules[i](state, nextLine, endLine, true)) {\\n terminate = true\\n break\\n }\\n }\\n if (terminate) { break }\\n }\\n\\n if (!level) {\\n // Didn't find valid underline\\n return false\\n }\\n\\n const content = state.getLines(startLine, nextLine, state.blkIndent, false).trim()\\n\\n state.line = nextLine + 1\\n\\n const token_o = state.push('heading_open', 'h' + String(level), 1)\\n token_o.markup = String.fromCharCode(marker)\\n token_o.map = [startLine, state.line]\\n\\n const token_i = state.push('inline', '', 0)\\n token_i.content = content\\n token_i.map = [startLine, state.line - 1]\\n token_i.children = []\\n\\n const token_c = state.push('heading_close', 'h' + String(level), -1)\\n token_c.markup = String.fromCharCode(marker)\\n\\n state.parentType = oldParentType\\n\\n return true\\n}\\n\",\"// Paragraph\\n\\nexport default function paragraph (state, startLine, endLine) {\\n const terminatorRules = state.md.block.ruler.getRules('paragraph')\\n const oldParentType = state.parentType\\n let nextLine = startLine + 1\\n state.parentType = 'paragraph'\\n\\n // jump line-by-line until empty one or EOF\\n for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) {\\n // this would be a code block normally, but after paragraph\\n // it's considered a lazy continuation regardless of what's there\\n if (state.sCount[nextLine] - state.blkIndent > 3) { continue }\\n\\n // quirk for blockquotes, this line should already be checked by that rule\\n if (state.sCount[nextLine] < 0) { continue }\\n\\n // Some tags can terminate paragraph without empty line.\\n let terminate = false\\n for (let i = 0, l = terminatorRules.length; i < l; i++) {\\n if (terminatorRules[i](state, nextLine, endLine, true)) {\\n terminate = true\\n break\\n }\\n }\\n if (terminate) { break }\\n }\\n\\n const content = state.getLines(startLine, nextLine, state.blkIndent, false).trim()\\n\\n state.line = nextLine\\n\\n const token_o = state.push('paragraph_open', 'p', 1)\\n token_o.map = [startLine, state.line]\\n\\n const token_i = state.push('inline', '', 0)\\n token_i.content = content\\n token_i.map = [startLine, state.line]\\n token_i.children = []\\n\\n state.push('paragraph_close', 'p', -1)\\n\\n state.parentType = oldParentType\\n\\n return true\\n}\\n\",\"/** internal\\n * class ParserBlock\\n *\\n * Block-level tokenizer.\\n **/\\n\\nimport Ruler from './ruler.mjs'\\nimport StateBlock from './rules_block/state_block.mjs'\\n\\nimport r_table from './rules_block/table.mjs'\\nimport r_code from './rules_block/code.mjs'\\nimport r_fence from './rules_block/fence.mjs'\\nimport r_blockquote from './rules_block/blockquote.mjs'\\nimport r_hr from './rules_block/hr.mjs'\\nimport r_list from './rules_block/list.mjs'\\nimport r_reference from './rules_block/reference.mjs'\\nimport r_html_block from './rules_block/html_block.mjs'\\nimport r_heading from './rules_block/heading.mjs'\\nimport r_lheading from './rules_block/lheading.mjs'\\nimport r_paragraph from './rules_block/paragraph.mjs'\\n\\nconst _rules = [\\n // First 2 params - rule name & source. Secondary array - list of rules,\\n // which can be terminated by this one.\\n ['table', r_table, ['paragraph', 'reference']],\\n ['code', r_code],\\n ['fence', r_fence, ['paragraph', 'reference', 'blockquote', 'list']],\\n ['blockquote', r_blockquote, ['paragraph', 'reference', 'blockquote', 'list']],\\n ['hr', r_hr, ['paragraph', 'reference', 'blockquote', 'list']],\\n ['list', r_list, ['paragraph', 'reference', 'blockquote']],\\n ['reference', r_reference],\\n ['html_block', r_html_block, ['paragraph', 'reference', 'blockquote']],\\n ['heading', r_heading, ['paragraph', 'reference', 'blockquote']],\\n ['lheading', r_lheading],\\n ['paragraph', r_paragraph]\\n]\\n\\n/**\\n * new ParserBlock()\\n **/\\nfunction ParserBlock () {\\n /**\\n * ParserBlock#ruler -> Ruler\\n *\\n * [[Ruler]] instance. Keep configuration of block rules.\\n **/\\n this.ruler = new Ruler()\\n\\n for (let i = 0; i < _rules.length; i++) {\\n this.ruler.push(_rules[i][0], _rules[i][1], { alt: (_rules[i][2] || []).slice() })\\n }\\n}\\n\\n// Generate tokens for input range\\n//\\nParserBlock.prototype.tokenize = function (state, startLine, endLine) {\\n const rules = this.ruler.getRules('')\\n const len = rules.length\\n const maxNesting = state.md.options.maxNesting\\n let line = startLine\\n let hasEmptyLines = false\\n\\n while (line < endLine) {\\n state.line = line = state.skipEmptyLines(line)\\n if (line >= endLine) { break }\\n\\n // Termination condition for nested calls.\\n // Nested calls currently used for blockquotes & lists\\n if (state.sCount[line] < state.blkIndent) { break }\\n\\n // If nesting level exceeded - skip tail to the end. That's not ordinary\\n // situation and we should not care about content.\\n if (state.level >= maxNesting) {\\n state.line = endLine\\n break\\n }\\n\\n // Try all possible rules.\\n // On success, rule should:\\n //\\n // - update `state.line`\\n // - update `state.tokens`\\n // - return true\\n const prevLine = state.line\\n let ok = false\\n\\n for (let i = 0; i < len; i++) {\\n ok = rules[i](state, line, endLine, false)\\n if (ok) {\\n if (prevLine >= state.line) {\\n throw new Error(\\\"block rule didn't increment state.line\\\")\\n }\\n break\\n }\\n }\\n\\n // this can only happen if user disables paragraph rule\\n if (!ok) throw new Error('none of the block rules matched')\\n\\n // set state.tight if we had an empty line before current tag\\n // i.e. latest empty line should not count\\n state.tight = !hasEmptyLines\\n\\n // paragraph might \\\"eat\\\" one newline after it in nested lists\\n if (state.isEmpty(state.line - 1)) {\\n hasEmptyLines = true\\n }\\n\\n line = state.line\\n\\n if (line < endLine && state.isEmpty(line)) {\\n hasEmptyLines = true\\n line++\\n state.line = line\\n }\\n }\\n}\\n\\n/**\\n * ParserBlock.parse(str, md, env, outTokens)\\n *\\n * Process input string and push block tokens into `outTokens`\\n **/\\nParserBlock.prototype.parse = function (src, md, env, outTokens) {\\n if (!src) { return }\\n\\n const state = new this.State(src, md, env, outTokens)\\n\\n this.tokenize(state, state.line, state.lineMax)\\n}\\n\\nParserBlock.prototype.State = StateBlock\\n\\nexport default ParserBlock\\n\",\"// Inline parser state\\n\\nimport Token from '../token.mjs'\\nimport { isWhiteSpace, isPunctChar, isMdAsciiPunct } from '../common/utils.mjs'\\n\\nfunction StateInline (src, md, env, outTokens) {\\n this.src = src\\n this.env = env\\n this.md = md\\n this.tokens = outTokens\\n this.tokens_meta = Array(outTokens.length)\\n\\n this.pos = 0\\n this.posMax = this.src.length\\n this.level = 0\\n this.pending = ''\\n this.pendingLevel = 0\\n\\n // Stores { start: end } pairs. Useful for backtrack\\n // optimization of pairs parse (emphasis, strikes).\\n this.cache = {}\\n\\n // List of emphasis-like delimiters for current tag\\n this.delimiters = []\\n\\n // Stack of delimiter lists for upper level tags\\n this._prev_delimiters = []\\n\\n // backtick length => last seen position\\n this.backticks = {}\\n this.backticksScanned = false\\n\\n // Counter used to disable inline linkify-it execution\\n // inside and markdown links\\n this.linkLevel = 0\\n}\\n\\n// Flush pending text\\n//\\nStateInline.prototype.pushPending = function () {\\n const token = new Token('text', '', 0)\\n token.content = this.pending\\n token.level = this.pendingLevel\\n this.tokens.push(token)\\n this.pending = ''\\n return token\\n}\\n\\n// Push new token to \\\"stream\\\".\\n// If pending text exists - flush it as text token\\n//\\nStateInline.prototype.push = function (type, tag, nesting) {\\n if (this.pending) {\\n this.pushPending()\\n }\\n\\n const token = new Token(type, tag, nesting)\\n let token_meta = null\\n\\n if (nesting < 0) {\\n // closing tag\\n this.level--\\n this.delimiters = this._prev_delimiters.pop()\\n }\\n\\n token.level = this.level\\n\\n if (nesting > 0) {\\n // opening tag\\n this.level++\\n this._prev_delimiters.push(this.delimiters)\\n this.delimiters = []\\n token_meta = { delimiters: this.delimiters }\\n }\\n\\n this.pendingLevel = this.level\\n this.tokens.push(token)\\n this.tokens_meta.push(token_meta)\\n return token\\n}\\n\\n// Scan a sequence of emphasis-like markers, and determine whether\\n// it can start an emphasis sequence or end an emphasis sequence.\\n//\\n// - start - position to scan from (it should point at a valid marker);\\n// - canSplitWord - determine if these markers can be found inside a word\\n//\\nStateInline.prototype.scanDelims = function (start, canSplitWord) {\\n const max = this.posMax\\n const marker = this.src.charCodeAt(start)\\n\\n // treat beginning of the line as a whitespace\\n const lastChar = start > 0 ? this.src.charCodeAt(start - 1) : 0x20\\n\\n let pos = start\\n while (pos < max && this.src.charCodeAt(pos) === marker) { pos++ }\\n\\n const count = pos - start\\n\\n // treat end of the line as a whitespace\\n const nextChar = pos < max ? this.src.charCodeAt(pos) : 0x20\\n\\n const isLastPunctChar = isMdAsciiPunct(lastChar) || isPunctChar(String.fromCharCode(lastChar))\\n const isNextPunctChar = isMdAsciiPunct(nextChar) || isPunctChar(String.fromCharCode(nextChar))\\n\\n const isLastWhiteSpace = isWhiteSpace(lastChar)\\n const isNextWhiteSpace = isWhiteSpace(nextChar)\\n\\n const left_flanking =\\n !isNextWhiteSpace && (!isNextPunctChar || isLastWhiteSpace || isLastPunctChar)\\n const right_flanking =\\n !isLastWhiteSpace && (!isLastPunctChar || isNextWhiteSpace || isNextPunctChar)\\n\\n const can_open = left_flanking && (canSplitWord || !right_flanking || isLastPunctChar)\\n const can_close = right_flanking && (canSplitWord || !left_flanking || isNextPunctChar)\\n\\n return { can_open, can_close, length: count }\\n}\\n\\n// re-export Token class to use in block rules\\nStateInline.prototype.Token = Token\\n\\nexport default StateInline\\n\",\"// Skip text characters for text token, place those to pending buffer\\n// and increment current pos\\n\\n// Rule to skip pure text\\n// '{}$%@~+=:' reserved for extentions\\n\\n// !, \\\", #, $, %, &, ', (, ), *, +, ,, -, ., /, :, ;, <, =, >, ?, @, [, \\\\, ], ^, _, `, {, |, }, or ~\\n\\n// !!!! Don't confuse with \\\"Markdown ASCII Punctuation\\\" chars\\n// http://spec.commonmark.org/0.15/#ascii-punctuation-character\\nfunction isTerminatorChar (ch) {\\n switch (ch) {\\n case 0x0A/* \\\\n */:\\n case 0x21/* ! */:\\n case 0x23/* # */:\\n case 0x24/* $ */:\\n case 0x25/* % */:\\n case 0x26/* & */:\\n case 0x2A/* * */:\\n case 0x2B/* + */:\\n case 0x2D/* - */:\\n case 0x3A/* : */:\\n case 0x3C/* < */:\\n case 0x3D/* = */:\\n case 0x3E/* > */:\\n case 0x40/* @ */:\\n case 0x5B/* [ */:\\n case 0x5C/* \\\\ */:\\n case 0x5D/* ] */:\\n case 0x5E/* ^ */:\\n case 0x5F/* _ */:\\n case 0x60/* ` */:\\n case 0x7B/* { */:\\n case 0x7D/* } */:\\n case 0x7E/* ~ */:\\n return true\\n default:\\n return false\\n }\\n}\\n\\nexport default function text (state, silent) {\\n let pos = state.pos\\n\\n while (pos < state.posMax && !isTerminatorChar(state.src.charCodeAt(pos))) {\\n pos++\\n }\\n\\n if (pos === state.pos) { return false }\\n\\n if (!silent) { state.pending += state.src.slice(state.pos, pos) }\\n\\n state.pos = pos\\n\\n return true\\n}\\n\\n// Alternative implementation, for memory.\\n//\\n// It costs 10% of performance, but allows extend terminators list, if place it\\n// to `ParserInline` property. Probably, will switch to it sometime, such\\n// flexibility required.\\n\\n/*\\nvar TERMINATOR_RE = /[\\\\n!#$%&*+\\\\-:<=>@[\\\\\\\\\\\\]^_`{}~]/;\\n\\nmodule.exports = function text(state, silent) {\\n var pos = state.pos,\\n idx = state.src.slice(pos).search(TERMINATOR_RE);\\n\\n // first char is terminator -> empty text\\n if (idx === 0) { return false; }\\n\\n // no terminator -> text till end of string\\n if (idx < 0) {\\n if (!silent) { state.pending += state.src.slice(pos); }\\n state.pos = state.src.length;\\n return true;\\n }\\n\\n if (!silent) { state.pending += state.src.slice(pos, pos + idx); }\\n\\n state.pos += idx;\\n\\n return true;\\n}; */\\n\",\"// Process links like https://example.org/\\n\\n// RFC3986: scheme = ALPHA *( ALPHA / DIGIT / \\\"+\\\" / \\\"-\\\" / \\\".\\\" )\\nconst SCHEME_RE = /(?:^|[^a-z0-9.+-])([a-z][a-z0-9.+-]*)$/i\\n\\nexport default function linkify (state, silent) {\\n if (!state.md.options.linkify) return false\\n if (state.linkLevel > 0) return false\\n\\n const pos = state.pos\\n const max = state.posMax\\n\\n if (pos + 3 > max) return false\\n if (state.src.charCodeAt(pos) !== 0x3A/* : */) return false\\n if (state.src.charCodeAt(pos + 1) !== 0x2F/* / */) return false\\n if (state.src.charCodeAt(pos + 2) !== 0x2F/* / */) return false\\n\\n const match = state.pending.match(SCHEME_RE)\\n if (!match) return false\\n\\n const proto = match[1]\\n\\n const link = state.md.linkify.matchAtStart(state.src.slice(pos - proto.length))\\n if (!link) return false\\n\\n let url = link.url\\n\\n // invalid link, but still detected by linkify somehow;\\n // need to check to prevent infinite loop below\\n if (url.length <= proto.length) return false\\n\\n // disallow '*' at the end of the link (conflicts with emphasis)\\n // do manual backsearch to avoid perf issues with regex /\\\\*+$/ on \\\"****...****a\\\".\\n let urlEnd = url.length\\n while (urlEnd > 0 && url.charCodeAt(urlEnd - 1) === 0x2A/* * */) {\\n urlEnd--\\n }\\n if (urlEnd !== url.length) {\\n url = url.slice(0, urlEnd)\\n }\\n\\n const fullUrl = state.md.normalizeLink(url)\\n if (!state.md.validateLink(fullUrl)) return false\\n\\n if (!silent) {\\n state.pending = state.pending.slice(0, -proto.length)\\n\\n const token_o = state.push('link_open', 'a', 1)\\n token_o.attrs = [['href', fullUrl]]\\n token_o.markup = 'linkify'\\n token_o.info = 'auto'\\n\\n const token_t = state.push('text', '', 0)\\n token_t.content = state.md.normalizeLinkText(url)\\n\\n const token_c = state.push('link_close', 'a', -1)\\n token_c.markup = 'linkify'\\n token_c.info = 'auto'\\n }\\n\\n state.pos += url.length - proto.length\\n return true\\n}\\n\",\"// Proceess '\\\\n'\\n\\nimport { isSpace } from '../common/utils.mjs'\\n\\nexport default function newline (state, silent) {\\n let pos = state.pos\\n\\n if (state.src.charCodeAt(pos) !== 0x0A/* \\\\n */) { return false }\\n\\n const pmax = state.pending.length - 1\\n const max = state.posMax\\n\\n // ' \\\\n' -> hardbreak\\n // Lookup in pending chars is bad practice! Don't copy to other rules!\\n // Pending string is stored in concat mode, indexed lookups will cause\\n // convertion to flat mode.\\n if (!silent) {\\n if (pmax >= 0 && state.pending.charCodeAt(pmax) === 0x20) {\\n if (pmax >= 1 && state.pending.charCodeAt(pmax - 1) === 0x20) {\\n // Find whitespaces tail of pending chars.\\n let ws = pmax - 1\\n while (ws >= 1 && state.pending.charCodeAt(ws - 1) === 0x20) ws--\\n\\n state.pending = state.pending.slice(0, ws)\\n state.push('hardbreak', 'br', 0)\\n } else {\\n state.pending = state.pending.slice(0, -1)\\n state.push('softbreak', 'br', 0)\\n }\\n } else {\\n state.push('softbreak', 'br', 0)\\n }\\n }\\n\\n pos++\\n\\n // skip heading spaces for next line\\n while (pos < max && isSpace(state.src.charCodeAt(pos))) { pos++ }\\n\\n state.pos = pos\\n return true\\n}\\n\",\"// Process escaped chars and hardbreaks\\n\\nimport { isSpace } from '../common/utils.mjs'\\n\\nconst ESCAPED = []\\n\\nfor (let i = 0; i < 256; i++) { ESCAPED.push(0) }\\n\\n'\\\\\\\\!\\\"#$%&\\\\'()*+,./:;<=>?@[]^_`{|}~-'\\n .split('').forEach(function (ch) { ESCAPED[ch.charCodeAt(0)] = 1 })\\n\\nexport default function escape (state, silent) {\\n let pos = state.pos\\n const max = state.posMax\\n\\n if (state.src.charCodeAt(pos) !== 0x5C/* \\\\ */) return false\\n pos++\\n\\n // '\\\\' at the end of the inline block\\n if (pos >= max) return false\\n\\n let ch1 = state.src.charCodeAt(pos)\\n\\n if (ch1 === 0x0A) {\\n if (!silent) {\\n state.push('hardbreak', 'br', 0)\\n }\\n\\n pos++\\n // skip leading whitespaces from next line\\n while (pos < max) {\\n ch1 = state.src.charCodeAt(pos)\\n if (!isSpace(ch1)) break\\n pos++\\n }\\n\\n state.pos = pos\\n return true\\n }\\n\\n let escapedStr = state.src[pos]\\n\\n if (ch1 >= 0xD800 && ch1 <= 0xDBFF && pos + 1 < max) {\\n const ch2 = state.src.charCodeAt(pos + 1)\\n\\n if (ch2 >= 0xDC00 && ch2 <= 0xDFFF) {\\n escapedStr += state.src[pos + 1]\\n pos++\\n }\\n }\\n\\n const origStr = '\\\\\\\\' + escapedStr\\n\\n if (!silent) {\\n const token = state.push('text_special', '', 0)\\n\\n if (ch1 < 256 && ESCAPED[ch1] !== 0) {\\n token.content = escapedStr\\n } else {\\n token.content = origStr\\n }\\n\\n token.markup = origStr\\n token.info = 'escape'\\n }\\n\\n state.pos = pos + 1\\n return true\\n}\\n\",\"// Parse backticks\\n\\nexport default function backtick (state, silent) {\\n let pos = state.pos\\n const ch = state.src.charCodeAt(pos)\\n\\n if (ch !== 0x60/* ` */) { return false }\\n\\n const start = pos\\n pos++\\n const max = state.posMax\\n\\n // scan marker length\\n while (pos < max && state.src.charCodeAt(pos) === 0x60/* ` */) { pos++ }\\n\\n const marker = state.src.slice(start, pos)\\n const openerLength = marker.length\\n\\n if (state.backticksScanned && (state.backticks[openerLength] || 0) <= start) {\\n if (!silent) state.pending += marker\\n state.pos += openerLength\\n return true\\n }\\n\\n let matchEnd = pos\\n let matchStart\\n\\n // Nothing found in the cache, scan until the end of the line (or until marker is found)\\n while ((matchStart = state.src.indexOf('`', matchEnd)) !== -1) {\\n matchEnd = matchStart + 1\\n\\n // scan marker length\\n while (matchEnd < max && state.src.charCodeAt(matchEnd) === 0x60/* ` */) { matchEnd++ }\\n\\n const closerLength = matchEnd - matchStart\\n\\n if (closerLength === openerLength) {\\n // Found matching closer length.\\n if (!silent) {\\n const token = state.push('code_inline', 'code', 0)\\n token.markup = marker\\n token.content = state.src.slice(pos, matchStart)\\n .replace(/\\\\n/g, ' ')\\n .replace(/^ (.+) $/, '$1')\\n }\\n state.pos = matchEnd\\n return true\\n }\\n\\n // Some different length found, put it in cache as upper limit of where closer can be found\\n state.backticks[closerLength] = matchStart\\n }\\n\\n // Scanned through the end, didn't find anything\\n state.backticksScanned = true\\n\\n if (!silent) state.pending += marker\\n state.pos += openerLength\\n return true\\n}\\n\",\"// ~~strike through~~\\n//\\n\\n// Insert each marker as a separate text token, and add it to delimiter list\\n//\\nfunction strikethrough_tokenize (state, silent) {\\n const start = state.pos\\n const marker = state.src.charCodeAt(start)\\n\\n if (silent) { return false }\\n\\n if (marker !== 0x7E/* ~ */) { return false }\\n\\n const scanned = state.scanDelims(state.pos, true)\\n let len = scanned.length\\n const ch = String.fromCharCode(marker)\\n\\n if (len < 2) { return false }\\n\\n let token\\n\\n if (len % 2) {\\n token = state.push('text', '', 0)\\n token.content = ch\\n len--\\n }\\n\\n for (let i = 0; i < len; i += 2) {\\n token = state.push('text', '', 0)\\n token.content = ch + ch\\n\\n state.delimiters.push({\\n marker,\\n length: 0, // disable \\\"rule of 3\\\" length checks meant for emphasis\\n token: state.tokens.length - 1,\\n end: -1,\\n open: scanned.can_open,\\n close: scanned.can_close\\n })\\n }\\n\\n state.pos += scanned.length\\n\\n return true\\n}\\n\\nfunction postProcess (state, delimiters) {\\n let token\\n const loneMarkers = []\\n const max = delimiters.length\\n\\n for (let i = 0; i < max; i++) {\\n const startDelim = delimiters[i]\\n\\n if (startDelim.marker !== 0x7E/* ~ */) {\\n continue\\n }\\n\\n if (startDelim.end === -1) {\\n continue\\n }\\n\\n const endDelim = delimiters[startDelim.end]\\n\\n token = state.tokens[startDelim.token]\\n token.type = 's_open'\\n token.tag = 's'\\n token.nesting = 1\\n token.markup = '~~'\\n token.content = ''\\n\\n token = state.tokens[endDelim.token]\\n token.type = 's_close'\\n token.tag = 's'\\n token.nesting = -1\\n token.markup = '~~'\\n token.content = ''\\n\\n if (state.tokens[endDelim.token - 1].type === 'text' &&\\n state.tokens[endDelim.token - 1].content === '~') {\\n loneMarkers.push(endDelim.token - 1)\\n }\\n }\\n\\n // If a marker sequence has an odd number of characters, it's splitted\\n // like this: `~~~~~` -> `~` + `~~` + `~~`, leaving one marker at the\\n // start of the sequence.\\n //\\n // So, we have to move all those markers after subsequent s_close tags.\\n //\\n while (loneMarkers.length) {\\n const i = loneMarkers.pop()\\n let j = i + 1\\n\\n while (j < state.tokens.length && state.tokens[j].type === 's_close') {\\n j++\\n }\\n\\n j--\\n\\n if (i !== j) {\\n token = state.tokens[j]\\n state.tokens[j] = state.tokens[i]\\n state.tokens[i] = token\\n }\\n }\\n}\\n\\n// Walk through delimiter list and replace text tokens with tags\\n//\\nfunction strikethrough_postProcess (state) {\\n const tokens_meta = state.tokens_meta\\n const max = state.tokens_meta.length\\n\\n postProcess(state, state.delimiters)\\n\\n for (let curr = 0; curr < max; curr++) {\\n if (tokens_meta[curr] && tokens_meta[curr].delimiters) {\\n postProcess(state, tokens_meta[curr].delimiters)\\n }\\n }\\n}\\n\\nexport default {\\n tokenize: strikethrough_tokenize,\\n postProcess: strikethrough_postProcess\\n}\\n\",\"// Process *this* and _that_\\n//\\n\\n// Insert each marker as a separate text token, and add it to delimiter list\\n//\\nfunction emphasis_tokenize (state, silent) {\\n const start = state.pos\\n const marker = state.src.charCodeAt(start)\\n\\n if (silent) { return false }\\n\\n if (marker !== 0x5F /* _ */ && marker !== 0x2A /* * */) { return false }\\n\\n const scanned = state.scanDelims(state.pos, marker === 0x2A)\\n\\n for (let i = 0; i < scanned.length; i++) {\\n const token = state.push('text', '', 0)\\n token.content = String.fromCharCode(marker)\\n\\n state.delimiters.push({\\n // Char code of the starting marker (number).\\n //\\n marker,\\n\\n // Total length of these series of delimiters.\\n //\\n length: scanned.length,\\n\\n // A position of the token this delimiter corresponds to.\\n //\\n token: state.tokens.length - 1,\\n\\n // If this delimiter is matched as a valid opener, `end` will be\\n // equal to its position, otherwise it's `-1`.\\n //\\n end: -1,\\n\\n // Boolean flags that determine if this delimiter could open or close\\n // an emphasis.\\n //\\n open: scanned.can_open,\\n close: scanned.can_close\\n })\\n }\\n\\n state.pos += scanned.length\\n\\n return true\\n}\\n\\nfunction postProcess (state, delimiters) {\\n const max = delimiters.length\\n\\n for (let i = max - 1; i >= 0; i--) {\\n const startDelim = delimiters[i]\\n\\n if (startDelim.marker !== 0x5F/* _ */ && startDelim.marker !== 0x2A/* * */) {\\n continue\\n }\\n\\n // Process only opening markers\\n if (startDelim.end === -1) {\\n continue\\n }\\n\\n const endDelim = delimiters[startDelim.end]\\n\\n // If the previous delimiter has the same marker and is adjacent to this one,\\n // merge those into one strong delimiter.\\n //\\n // `whatever` -> `whatever`\\n //\\n const isStrong = i > 0 &&\\n delimiters[i - 1].end === startDelim.end + 1 &&\\n // check that first two markers match and adjacent\\n delimiters[i - 1].marker === startDelim.marker &&\\n delimiters[i - 1].token === startDelim.token - 1 &&\\n // check that last two markers are adjacent (we can safely assume they match)\\n delimiters[startDelim.end + 1].token === endDelim.token + 1\\n\\n const ch = String.fromCharCode(startDelim.marker)\\n\\n const token_o = state.tokens[startDelim.token]\\n token_o.type = isStrong ? 'strong_open' : 'em_open'\\n token_o.tag = isStrong ? 'strong' : 'em'\\n token_o.nesting = 1\\n token_o.markup = isStrong ? ch + ch : ch\\n token_o.content = ''\\n\\n const token_c = state.tokens[endDelim.token]\\n token_c.type = isStrong ? 'strong_close' : 'em_close'\\n token_c.tag = isStrong ? 'strong' : 'em'\\n token_c.nesting = -1\\n token_c.markup = isStrong ? ch + ch : ch\\n token_c.content = ''\\n\\n if (isStrong) {\\n state.tokens[delimiters[i - 1].token].content = ''\\n state.tokens[delimiters[startDelim.end + 1].token].content = ''\\n i--\\n }\\n }\\n}\\n\\n// Walk through delimiter list and replace text tokens with tags\\n//\\nfunction emphasis_post_process (state) {\\n const tokens_meta = state.tokens_meta\\n const max = state.tokens_meta.length\\n\\n postProcess(state, state.delimiters)\\n\\n for (let curr = 0; curr < max; curr++) {\\n if (tokens_meta[curr] && tokens_meta[curr].delimiters) {\\n postProcess(state, tokens_meta[curr].delimiters)\\n }\\n }\\n}\\n\\nexport default {\\n tokenize: emphasis_tokenize,\\n postProcess: emphasis_post_process\\n}\\n\",\"// Process [link]( \\\"stuff\\\")\\n\\nimport { normalizeReference, isSpace } from '../common/utils.mjs'\\n\\nexport default function link (state, silent) {\\n let code, label, res, ref\\n let href = ''\\n let title = ''\\n let start = state.pos\\n let parseReference = true\\n\\n if (state.src.charCodeAt(state.pos) !== 0x5B/* [ */) { return false }\\n\\n const oldPos = state.pos\\n const max = state.posMax\\n const labelStart = state.pos + 1\\n const labelEnd = state.md.helpers.parseLinkLabel(state, state.pos, true)\\n\\n // parser failed to find ']', so it's not a valid link\\n if (labelEnd < 0) { return false }\\n\\n let pos = labelEnd + 1\\n if (pos < max && state.src.charCodeAt(pos) === 0x28/* ( */) {\\n //\\n // Inline link\\n //\\n\\n // might have found a valid shortcut link, disable reference parsing\\n parseReference = false\\n\\n // [link]( \\\"title\\\" )\\n // ^^ skipping these spaces\\n pos++\\n for (; pos < max; pos++) {\\n code = state.src.charCodeAt(pos)\\n if (!isSpace(code) && code !== 0x0A) { break }\\n }\\n if (pos >= max) { return false }\\n\\n // [link]( \\\"title\\\" )\\n // ^^^^^^ parsing link destination\\n start = pos\\n res = state.md.helpers.parseLinkDestination(state.src, pos, state.posMax)\\n if (res.ok) {\\n href = state.md.normalizeLink(res.str)\\n if (state.md.validateLink(href)) {\\n pos = res.pos\\n } else {\\n href = ''\\n }\\n\\n // [link]( \\\"title\\\" )\\n // ^^ skipping these spaces\\n start = pos\\n for (; pos < max; pos++) {\\n code = state.src.charCodeAt(pos)\\n if (!isSpace(code) && code !== 0x0A) { break }\\n }\\n\\n // [link]( \\\"title\\\" )\\n // ^^^^^^^ parsing link title\\n res = state.md.helpers.parseLinkTitle(state.src, pos, state.posMax)\\n if (pos < max && start !== pos && res.ok) {\\n title = res.str\\n pos = res.pos\\n\\n // [link]( \\\"title\\\" )\\n // ^^ skipping these spaces\\n for (; pos < max; pos++) {\\n code = state.src.charCodeAt(pos)\\n if (!isSpace(code) && code !== 0x0A) { break }\\n }\\n }\\n }\\n\\n if (pos >= max || state.src.charCodeAt(pos) !== 0x29/* ) */) {\\n // parsing a valid shortcut link failed, fallback to reference\\n parseReference = true\\n }\\n pos++\\n }\\n\\n if (parseReference) {\\n //\\n // Link reference\\n //\\n if (typeof state.env.references === 'undefined') { return false }\\n\\n if (pos < max && state.src.charCodeAt(pos) === 0x5B/* [ */) {\\n start = pos + 1\\n pos = state.md.helpers.parseLinkLabel(state, pos)\\n if (pos >= 0) {\\n label = state.src.slice(start, pos++)\\n } else {\\n pos = labelEnd + 1\\n }\\n } else {\\n pos = labelEnd + 1\\n }\\n\\n // covers label === '' and label === undefined\\n // (collapsed reference link and shortcut reference link respectively)\\n if (!label) { label = state.src.slice(labelStart, labelEnd) }\\n\\n ref = state.env.references[normalizeReference(label)]\\n if (!ref) {\\n state.pos = oldPos\\n return false\\n }\\n href = ref.href\\n title = ref.title\\n }\\n\\n //\\n // We found the end of the link, and know for a fact it's a valid link;\\n // so all that's left to do is to call tokenizer.\\n //\\n if (!silent) {\\n state.pos = labelStart\\n state.posMax = labelEnd\\n\\n const token_o = state.push('link_open', 'a', 1)\\n const attrs = [['href', href]]\\n token_o.attrs = attrs\\n if (title) {\\n attrs.push(['title', title])\\n }\\n\\n state.linkLevel++\\n state.md.inline.tokenize(state)\\n state.linkLevel--\\n\\n state.push('link_close', 'a', -1)\\n }\\n\\n state.pos = pos\\n state.posMax = max\\n return true\\n}\\n\",\"// Process ![image]( \\\"title\\\")\\n\\nimport { normalizeReference, isSpace } from '../common/utils.mjs'\\n\\nexport default function image (state, silent) {\\n let code, content, label, pos, ref, res, title, start\\n let href = ''\\n const oldPos = state.pos\\n const max = state.posMax\\n\\n if (state.src.charCodeAt(state.pos) !== 0x21/* ! */) { return false }\\n if (state.src.charCodeAt(state.pos + 1) !== 0x5B/* [ */) { return false }\\n\\n const labelStart = state.pos + 2\\n const labelEnd = state.md.helpers.parseLinkLabel(state, state.pos + 1, false)\\n\\n // parser failed to find ']', so it's not a valid link\\n if (labelEnd < 0) { return false }\\n\\n pos = labelEnd + 1\\n if (pos < max && state.src.charCodeAt(pos) === 0x28/* ( */) {\\n //\\n // Inline link\\n //\\n\\n // [link]( \\\"title\\\" )\\n // ^^ skipping these spaces\\n pos++\\n for (; pos < max; pos++) {\\n code = state.src.charCodeAt(pos)\\n if (!isSpace(code) && code !== 0x0A) { break }\\n }\\n if (pos >= max) { return false }\\n\\n // [link]( \\\"title\\\" )\\n // ^^^^^^ parsing link destination\\n start = pos\\n res = state.md.helpers.parseLinkDestination(state.src, pos, state.posMax)\\n if (res.ok) {\\n href = state.md.normalizeLink(res.str)\\n if (state.md.validateLink(href)) {\\n pos = res.pos\\n } else {\\n href = ''\\n }\\n }\\n\\n // [link]( \\\"title\\\" )\\n // ^^ skipping these spaces\\n start = pos\\n for (; pos < max; pos++) {\\n code = state.src.charCodeAt(pos)\\n if (!isSpace(code) && code !== 0x0A) { break }\\n }\\n\\n // [link]( \\\"title\\\" )\\n // ^^^^^^^ parsing link title\\n res = state.md.helpers.parseLinkTitle(state.src, pos, state.posMax)\\n if (pos < max && start !== pos && res.ok) {\\n title = res.str\\n pos = res.pos\\n\\n // [link]( \\\"title\\\" )\\n // ^^ skipping these spaces\\n for (; pos < max; pos++) {\\n code = state.src.charCodeAt(pos)\\n if (!isSpace(code) && code !== 0x0A) { break }\\n }\\n } else {\\n title = ''\\n }\\n\\n if (pos >= max || state.src.charCodeAt(pos) !== 0x29/* ) */) {\\n state.pos = oldPos\\n return false\\n }\\n pos++\\n } else {\\n //\\n // Link reference\\n //\\n if (typeof state.env.references === 'undefined') { return false }\\n\\n if (pos < max && state.src.charCodeAt(pos) === 0x5B/* [ */) {\\n start = pos + 1\\n pos = state.md.helpers.parseLinkLabel(state, pos)\\n if (pos >= 0) {\\n label = state.src.slice(start, pos++)\\n } else {\\n pos = labelEnd + 1\\n }\\n } else {\\n pos = labelEnd + 1\\n }\\n\\n // covers label === '' and label === undefined\\n // (collapsed reference link and shortcut reference link respectively)\\n if (!label) { label = state.src.slice(labelStart, labelEnd) }\\n\\n ref = state.env.references[normalizeReference(label)]\\n if (!ref) {\\n state.pos = oldPos\\n return false\\n }\\n href = ref.href\\n title = ref.title\\n }\\n\\n //\\n // We found the end of the link, and know for a fact it's a valid link;\\n // so all that's left to do is to call tokenizer.\\n //\\n if (!silent) {\\n content = state.src.slice(labelStart, labelEnd)\\n\\n const tokens = []\\n state.md.inline.parse(\\n content,\\n state.md,\\n state.env,\\n tokens\\n )\\n\\n const token = state.push('image', 'img', 0)\\n const attrs = [['src', href], ['alt', '']]\\n token.attrs = attrs\\n token.children = tokens\\n token.content = content\\n\\n if (title) {\\n attrs.push(['title', title])\\n }\\n }\\n\\n state.pos = pos\\n state.posMax = max\\n return true\\n}\\n\",\"// Process autolinks ''\\n\\n/* eslint max-len:0 */\\nconst EMAIL_RE = /^([a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)$/\\n/* eslint-disable-next-line no-control-regex */\\nconst AUTOLINK_RE = /^([a-zA-Z][a-zA-Z0-9+.-]{1,31}):([^<>\\\\x00-\\\\x20]*)$/\\n\\nexport default function autolink (state, silent) {\\n let pos = state.pos\\n\\n if (state.src.charCodeAt(pos) !== 0x3C/* < */) { return false }\\n\\n const start = state.pos\\n const max = state.posMax\\n\\n for (;;) {\\n if (++pos >= max) return false\\n\\n const ch = state.src.charCodeAt(pos)\\n\\n if (ch === 0x3C /* < */) return false\\n if (ch === 0x3E /* > */) break\\n }\\n\\n const url = state.src.slice(start + 1, pos)\\n\\n if (AUTOLINK_RE.test(url)) {\\n const fullUrl = state.md.normalizeLink(url)\\n if (!state.md.validateLink(fullUrl)) { return false }\\n\\n if (!silent) {\\n const token_o = state.push('link_open', 'a', 1)\\n token_o.attrs = [['href', fullUrl]]\\n token_o.markup = 'autolink'\\n token_o.info = 'auto'\\n\\n const token_t = state.push('text', '', 0)\\n token_t.content = state.md.normalizeLinkText(url)\\n\\n const token_c = state.push('link_close', 'a', -1)\\n token_c.markup = 'autolink'\\n token_c.info = 'auto'\\n }\\n\\n state.pos += url.length + 2\\n return true\\n }\\n\\n if (EMAIL_RE.test(url)) {\\n const fullUrl = state.md.normalizeLink('mailto:' + url)\\n if (!state.md.validateLink(fullUrl)) { return false }\\n\\n if (!silent) {\\n const token_o = state.push('link_open', 'a', 1)\\n token_o.attrs = [['href', fullUrl]]\\n token_o.markup = 'autolink'\\n token_o.info = 'auto'\\n\\n const token_t = state.push('text', '', 0)\\n token_t.content = state.md.normalizeLinkText(url)\\n\\n const token_c = state.push('link_close', 'a', -1)\\n token_c.markup = 'autolink'\\n token_c.info = 'auto'\\n }\\n\\n state.pos += url.length + 2\\n return true\\n }\\n\\n return false\\n}\\n\",\"// Process html tags\\n\\nimport { HTML_TAG_RE } from '../common/html_re.mjs'\\n\\nfunction isLinkOpen (str) {\\n return /^\\\\s]/i.test(str)\\n}\\nfunction isLinkClose (str) {\\n return /^<\\\\/a\\\\s*>/i.test(str)\\n}\\n\\nfunction isLetter (ch) {\\n /* eslint no-bitwise:0 */\\n const lc = ch | 0x20 // to lower case\\n return (lc >= 0x61/* a */) && (lc <= 0x7a/* z */)\\n}\\n\\nexport default function html_inline (state, silent) {\\n if (!state.md.options.html) { return false }\\n\\n // Check start\\n const max = state.posMax\\n const pos = state.pos\\n if (state.src.charCodeAt(pos) !== 0x3C/* < */ ||\\n pos + 2 >= max) {\\n return false\\n }\\n\\n // Quick fail on second char\\n const ch = state.src.charCodeAt(pos + 1)\\n if (ch !== 0x21/* ! */ &&\\n ch !== 0x3F/* ? */ &&\\n ch !== 0x2F/* / */ &&\\n !isLetter(ch)) {\\n return false\\n }\\n\\n const match = state.src.slice(pos).match(HTML_TAG_RE)\\n if (!match) { return false }\\n\\n if (!silent) {\\n const token = state.push('html_inline', '', 0)\\n token.content = match[0]\\n\\n if (isLinkOpen(token.content)) state.linkLevel++\\n if (isLinkClose(token.content)) state.linkLevel--\\n }\\n state.pos += match[0].length\\n return true\\n}\\n\",\"// Process html entity - {, ¯, ", ...\\n\\nimport { decodeHTML } from 'entities'\\nimport { isValidEntityCode, fromCodePoint } from '../common/utils.mjs'\\n\\nconst DIGITAL_RE = /^&#((?:x[a-f0-9]{1,6}|[0-9]{1,7}));/i\\nconst NAMED_RE = /^&([a-z][a-z0-9]{1,31});/i\\n\\nexport default function entity (state, silent) {\\n const pos = state.pos\\n const max = state.posMax\\n\\n if (state.src.charCodeAt(pos) !== 0x26/* & */) return false\\n\\n if (pos + 1 >= max) return false\\n\\n const ch = state.src.charCodeAt(pos + 1)\\n\\n if (ch === 0x23 /* # */) {\\n const match = state.src.slice(pos).match(DIGITAL_RE)\\n if (match) {\\n if (!silent) {\\n const code = match[1][0].toLowerCase() === 'x' ? parseInt(match[1].slice(1), 16) : parseInt(match[1], 10)\\n\\n const token = state.push('text_special', '', 0)\\n token.content = isValidEntityCode(code) ? fromCodePoint(code) : fromCodePoint(0xFFFD)\\n token.markup = match[0]\\n token.info = 'entity'\\n }\\n state.pos += match[0].length\\n return true\\n }\\n } else {\\n const match = state.src.slice(pos).match(NAMED_RE)\\n if (match) {\\n const decoded = decodeHTML(match[0])\\n if (decoded !== match[0]) {\\n if (!silent) {\\n const token = state.push('text_special', '', 0)\\n token.content = decoded\\n token.markup = match[0]\\n token.info = 'entity'\\n }\\n state.pos += match[0].length\\n return true\\n }\\n }\\n }\\n\\n return false\\n}\\n\",\"// For each opening emphasis-like marker find a matching closing one\\n//\\n\\nfunction processDelimiters (delimiters) {\\n const openersBottom = {}\\n const max = delimiters.length\\n\\n if (!max) return\\n\\n // headerIdx is the first delimiter of the current (where closer is) delimiter run\\n let headerIdx = 0\\n let lastTokenIdx = -2 // needs any value lower than -1\\n const jumps = []\\n\\n for (let closerIdx = 0; closerIdx < max; closerIdx++) {\\n const closer = delimiters[closerIdx]\\n\\n jumps.push(0)\\n\\n // markers belong to same delimiter run if:\\n // - they have adjacent tokens\\n // - AND markers are the same\\n //\\n if (delimiters[headerIdx].marker !== closer.marker || lastTokenIdx !== closer.token - 1) {\\n headerIdx = closerIdx\\n }\\n\\n lastTokenIdx = closer.token\\n\\n // Length is only used for emphasis-specific \\\"rule of 3\\\",\\n // if it's not defined (in strikethrough or 3rd party plugins),\\n // we can default it to 0 to disable those checks.\\n //\\n closer.length = closer.length || 0\\n\\n if (!closer.close) continue\\n\\n // Previously calculated lower bounds (previous fails)\\n // for each marker, each delimiter length modulo 3,\\n // and for whether this closer can be an opener;\\n // https://github.com/commonmark/cmark/commit/34250e12ccebdc6372b8b49c44fab57c72443460\\n /* eslint-disable-next-line no-prototype-builtins */\\n if (!openersBottom.hasOwnProperty(closer.marker)) {\\n openersBottom[closer.marker] = [-1, -1, -1, -1, -1, -1]\\n }\\n\\n const minOpenerIdx = openersBottom[closer.marker][(closer.open ? 3 : 0) + (closer.length % 3)]\\n\\n let openerIdx = headerIdx - jumps[headerIdx] - 1\\n\\n let newMinOpenerIdx = openerIdx\\n\\n for (; openerIdx > minOpenerIdx; openerIdx -= jumps[openerIdx] + 1) {\\n const opener = delimiters[openerIdx]\\n\\n if (opener.marker !== closer.marker) continue\\n\\n if (opener.open && opener.end < 0) {\\n let isOddMatch = false\\n\\n // from spec:\\n //\\n // If one of the delimiters can both open and close emphasis, then the\\n // sum of the lengths of the delimiter runs containing the opening and\\n // closing delimiters must not be a multiple of 3 unless both lengths\\n // are multiples of 3.\\n //\\n if (opener.close || closer.open) {\\n if ((opener.length + closer.length) % 3 === 0) {\\n if (opener.length % 3 !== 0 || closer.length % 3 !== 0) {\\n isOddMatch = true\\n }\\n }\\n }\\n\\n if (!isOddMatch) {\\n // If previous delimiter cannot be an opener, we can safely skip\\n // the entire sequence in future checks. This is required to make\\n // sure algorithm has linear complexity (see *_*_*_*_*_... case).\\n //\\n const lastJump = openerIdx > 0 && !delimiters[openerIdx - 1].open\\n ? jumps[openerIdx - 1] + 1\\n : 0\\n\\n jumps[closerIdx] = closerIdx - openerIdx + lastJump\\n jumps[openerIdx] = lastJump\\n\\n closer.open = false\\n opener.end = closerIdx\\n opener.close = false\\n newMinOpenerIdx = -1\\n // treat next token as start of run,\\n // it optimizes skips in **<...>**a**<...>** pathological case\\n lastTokenIdx = -2\\n break\\n }\\n }\\n }\\n\\n if (newMinOpenerIdx !== -1) {\\n // If match for this delimiter run failed, we want to set lower bound for\\n // future lookups. This is required to make sure algorithm has linear\\n // complexity.\\n //\\n // See details here:\\n // https://github.com/commonmark/cmark/issues/178#issuecomment-270417442\\n //\\n openersBottom[closer.marker][(closer.open ? 3 : 0) + ((closer.length || 0) % 3)] = newMinOpenerIdx\\n }\\n }\\n}\\n\\nexport default function link_pairs (state) {\\n const tokens_meta = state.tokens_meta\\n const max = state.tokens_meta.length\\n\\n processDelimiters(state.delimiters)\\n\\n for (let curr = 0; curr < max; curr++) {\\n if (tokens_meta[curr] && tokens_meta[curr].delimiters) {\\n processDelimiters(tokens_meta[curr].delimiters)\\n }\\n }\\n}\\n\",\"// Clean up tokens after emphasis and strikethrough postprocessing:\\n// merge adjacent text nodes into one and re-calculate all token levels\\n//\\n// This is necessary because initially emphasis delimiter markers (*, _, ~)\\n// are treated as their own separate text tokens. Then emphasis rule either\\n// leaves them as text (needed to merge with adjacent text) or turns them\\n// into opening/closing tags (which messes up levels inside).\\n//\\n\\nexport default function fragments_join (state) {\\n let curr, last\\n let level = 0\\n const tokens = state.tokens\\n const max = state.tokens.length\\n\\n for (curr = last = 0; curr < max; curr++) {\\n // re-calculate levels after emphasis/strikethrough turns some text nodes\\n // into opening/closing tags\\n if (tokens[curr].nesting < 0) level-- // closing tag\\n tokens[curr].level = level\\n if (tokens[curr].nesting > 0) level++ // opening tag\\n\\n if (tokens[curr].type === 'text' &&\\n curr + 1 < max &&\\n tokens[curr + 1].type === 'text') {\\n // collapse two adjacent text nodes\\n tokens[curr + 1].content = tokens[curr].content + tokens[curr + 1].content\\n } else {\\n if (curr !== last) { tokens[last] = tokens[curr] }\\n\\n last++\\n }\\n }\\n\\n if (curr !== last) {\\n tokens.length = last\\n }\\n}\\n\",\"/** internal\\n * class ParserInline\\n *\\n * Tokenizes paragraph content.\\n **/\\n\\nimport Ruler from './ruler.mjs'\\nimport StateInline from './rules_inline/state_inline.mjs'\\n\\nimport r_text from './rules_inline/text.mjs'\\nimport r_linkify from './rules_inline/linkify.mjs'\\nimport r_newline from './rules_inline/newline.mjs'\\nimport r_escape from './rules_inline/escape.mjs'\\nimport r_backticks from './rules_inline/backticks.mjs'\\nimport r_strikethrough from './rules_inline/strikethrough.mjs'\\nimport r_emphasis from './rules_inline/emphasis.mjs'\\nimport r_link from './rules_inline/link.mjs'\\nimport r_image from './rules_inline/image.mjs'\\nimport r_autolink from './rules_inline/autolink.mjs'\\nimport r_html_inline from './rules_inline/html_inline.mjs'\\nimport r_entity from './rules_inline/entity.mjs'\\n\\nimport r_balance_pairs from './rules_inline/balance_pairs.mjs'\\nimport r_fragments_join from './rules_inline/fragments_join.mjs'\\n\\n// Parser rules\\n\\nconst _rules = [\\n ['text', r_text],\\n ['linkify', r_linkify],\\n ['newline', r_newline],\\n ['escape', r_escape],\\n ['backticks', r_backticks],\\n ['strikethrough', r_strikethrough.tokenize],\\n ['emphasis', r_emphasis.tokenize],\\n ['link', r_link],\\n ['image', r_image],\\n ['autolink', r_autolink],\\n ['html_inline', r_html_inline],\\n ['entity', r_entity]\\n]\\n\\n// `rule2` ruleset was created specifically for emphasis/strikethrough\\n// post-processing and may be changed in the future.\\n//\\n// Don't use this for anything except pairs (plugins working with `balance_pairs`).\\n//\\nconst _rules2 = [\\n ['balance_pairs', r_balance_pairs],\\n ['strikethrough', r_strikethrough.postProcess],\\n ['emphasis', r_emphasis.postProcess],\\n // rules for pairs separate '**' into its own text tokens, which may be left unused,\\n // rule below merges unused segments back with the rest of the text\\n ['fragments_join', r_fragments_join]\\n]\\n\\n/**\\n * new ParserInline()\\n **/\\nfunction ParserInline () {\\n /**\\n * ParserInline#ruler -> Ruler\\n *\\n * [[Ruler]] instance. Keep configuration of inline rules.\\n **/\\n this.ruler = new Ruler()\\n\\n for (let i = 0; i < _rules.length; i++) {\\n this.ruler.push(_rules[i][0], _rules[i][1])\\n }\\n\\n /**\\n * ParserInline#ruler2 -> Ruler\\n *\\n * [[Ruler]] instance. Second ruler used for post-processing\\n * (e.g. in emphasis-like rules).\\n **/\\n this.ruler2 = new Ruler()\\n\\n for (let i = 0; i < _rules2.length; i++) {\\n this.ruler2.push(_rules2[i][0], _rules2[i][1])\\n }\\n}\\n\\n// Skip single token by running all rules in validation mode;\\n// returns `true` if any rule reported success\\n//\\nParserInline.prototype.skipToken = function (state) {\\n const pos = state.pos\\n const rules = this.ruler.getRules('')\\n const len = rules.length\\n const maxNesting = state.md.options.maxNesting\\n const cache = state.cache\\n\\n if (typeof cache[pos] !== 'undefined') {\\n state.pos = cache[pos]\\n return\\n }\\n\\n let ok = false\\n\\n if (state.level < maxNesting) {\\n for (let i = 0; i < len; i++) {\\n // Increment state.level and decrement it later to limit recursion.\\n // It's harmless to do here, because no tokens are created. But ideally,\\n // we'd need a separate private state variable for this purpose.\\n //\\n state.level++\\n ok = rules[i](state, true)\\n state.level--\\n\\n if (ok) {\\n if (pos >= state.pos) { throw new Error(\\\"inline rule didn't increment state.pos\\\") }\\n break\\n }\\n }\\n } else {\\n // Too much nesting, just skip until the end of the paragraph.\\n //\\n // NOTE: this will cause links to behave incorrectly in the following case,\\n // when an amount of `[` is exactly equal to `maxNesting + 1`:\\n //\\n // [[[[[[[[[[[[[[[[[[[[[foo]()\\n //\\n // TODO: remove this workaround when CM standard will allow nested links\\n // (we can replace it by preventing links from being parsed in\\n // validation mode)\\n //\\n state.pos = state.posMax\\n }\\n\\n if (!ok) { state.pos++ }\\n cache[pos] = state.pos\\n}\\n\\n// Generate tokens for input range\\n//\\nParserInline.prototype.tokenize = function (state) {\\n const rules = this.ruler.getRules('')\\n const len = rules.length\\n const end = state.posMax\\n const maxNesting = state.md.options.maxNesting\\n\\n while (state.pos < end) {\\n // Try all possible rules.\\n // On success, rule should:\\n //\\n // - update `state.pos`\\n // - update `state.tokens`\\n // - return true\\n const prevPos = state.pos\\n let ok = false\\n\\n if (state.level < maxNesting) {\\n for (let i = 0; i < len; i++) {\\n ok = rules[i](state, false)\\n if (ok) {\\n if (prevPos >= state.pos) { throw new Error(\\\"inline rule didn't increment state.pos\\\") }\\n break\\n }\\n }\\n }\\n\\n if (ok) {\\n if (state.pos >= end) { break }\\n continue\\n }\\n\\n state.pending += state.src[state.pos++]\\n }\\n\\n if (state.pending) {\\n state.pushPending()\\n }\\n}\\n\\n/**\\n * ParserInline.parse(str, md, env, outTokens)\\n *\\n * Process input string and push inline tokens into `outTokens`\\n **/\\nParserInline.prototype.parse = function (str, md, env, outTokens) {\\n const state = new this.State(str, md, env, outTokens)\\n\\n this.tokenize(state)\\n\\n const rules = this.ruler2.getRules('')\\n const len = rules.length\\n\\n for (let i = 0; i < len; i++) {\\n rules[i](state)\\n }\\n}\\n\\nParserInline.prototype.State = StateInline\\n\\nexport default ParserInline\\n\",\"'use strict';\\n\\n/** Highest positive signed 32-bit float value */\\nconst maxInt = 2147483647; // aka. 0x7FFFFFFF or 2^31-1\\n\\n/** Bootstring parameters */\\nconst base = 36;\\nconst tMin = 1;\\nconst tMax = 26;\\nconst skew = 38;\\nconst damp = 700;\\nconst initialBias = 72;\\nconst initialN = 128; // 0x80\\nconst delimiter = '-'; // '\\\\x2D'\\n\\n/** Regular expressions */\\nconst regexPunycode = /^xn--/;\\nconst regexNonASCII = /[^\\\\0-\\\\x7F]/; // Note: U+007F DEL is excluded too.\\nconst regexSeparators = /[\\\\x2E\\\\u3002\\\\uFF0E\\\\uFF61]/g; // RFC 3490 separators\\n\\n/** Error messages */\\nconst errors = {\\n\\t'overflow': 'Overflow: input needs wider integers to process',\\n\\t'not-basic': 'Illegal input >= 0x80 (not a basic code point)',\\n\\t'invalid-input': 'Invalid input'\\n};\\n\\n/** Convenience shortcuts */\\nconst baseMinusTMin = base - tMin;\\nconst floor = Math.floor;\\nconst stringFromCharCode = String.fromCharCode;\\n\\n/*--------------------------------------------------------------------------*/\\n\\n/**\\n * A generic error utility function.\\n * @private\\n * @param {String} type The error type.\\n * @returns {Error} Throws a `RangeError` with the applicable error message.\\n */\\nfunction error(type) {\\n\\tthrow new RangeError(errors[type]);\\n}\\n\\n/**\\n * A generic `Array#map` utility function.\\n * @private\\n * @param {Array} array The array to iterate over.\\n * @param {Function} callback The function that gets called for every array\\n * item.\\n * @returns {Array} A new array of values returned by the callback function.\\n */\\nfunction map(array, callback) {\\n\\tconst result = [];\\n\\tlet length = array.length;\\n\\twhile (length--) {\\n\\t\\tresult[length] = callback(array[length]);\\n\\t}\\n\\treturn result;\\n}\\n\\n/**\\n * A simple `Array#map`-like wrapper to work with domain name strings or email\\n * addresses.\\n * @private\\n * @param {String} domain The domain name or email address.\\n * @param {Function} callback The function that gets called for every\\n * character.\\n * @returns {String} A new string of characters returned by the callback\\n * function.\\n */\\nfunction mapDomain(domain, callback) {\\n\\tconst parts = domain.split('@');\\n\\tlet result = '';\\n\\tif (parts.length > 1) {\\n\\t\\t// In email addresses, only the domain name should be punycoded. Leave\\n\\t\\t// the local part (i.e. everything up to `@`) intact.\\n\\t\\tresult = parts[0] + '@';\\n\\t\\tdomain = parts[1];\\n\\t}\\n\\t// Avoid `split(regex)` for IE8 compatibility. See #17.\\n\\tdomain = domain.replace(regexSeparators, '\\\\x2E');\\n\\tconst labels = domain.split('.');\\n\\tconst encoded = map(labels, callback).join('.');\\n\\treturn result + encoded;\\n}\\n\\n/**\\n * Creates an array containing the numeric code points of each Unicode\\n * character in the string. While JavaScript uses UCS-2 internally,\\n * this function will convert a pair of surrogate halves (each of which\\n * UCS-2 exposes as separate characters) into a single code point,\\n * matching UTF-16.\\n * @see `punycode.ucs2.encode`\\n * @see \\n * @memberOf punycode.ucs2\\n * @name decode\\n * @param {String} string The Unicode input string (UCS-2).\\n * @returns {Array} The new array of code points.\\n */\\nfunction ucs2decode(string) {\\n\\tconst output = [];\\n\\tlet counter = 0;\\n\\tconst length = string.length;\\n\\twhile (counter < length) {\\n\\t\\tconst value = string.charCodeAt(counter++);\\n\\t\\tif (value >= 0xD800 && value <= 0xDBFF && counter < length) {\\n\\t\\t\\t// It's a high surrogate, and there is a next character.\\n\\t\\t\\tconst extra = string.charCodeAt(counter++);\\n\\t\\t\\tif ((extra & 0xFC00) == 0xDC00) { // Low surrogate.\\n\\t\\t\\t\\toutput.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);\\n\\t\\t\\t} else {\\n\\t\\t\\t\\t// It's an unmatched surrogate; only append this code unit, in case the\\n\\t\\t\\t\\t// next code unit is the high surrogate of a surrogate pair.\\n\\t\\t\\t\\toutput.push(value);\\n\\t\\t\\t\\tcounter--;\\n\\t\\t\\t}\\n\\t\\t} else {\\n\\t\\t\\toutput.push(value);\\n\\t\\t}\\n\\t}\\n\\treturn output;\\n}\\n\\n/**\\n * Creates a string based on an array of numeric code points.\\n * @see `punycode.ucs2.decode`\\n * @memberOf punycode.ucs2\\n * @name encode\\n * @param {Array} codePoints The array of numeric code points.\\n * @returns {String} The new Unicode string (UCS-2).\\n */\\nconst ucs2encode = codePoints => String.fromCodePoint(...codePoints);\\n\\n/**\\n * Converts a basic code point into a digit/integer.\\n * @see `digitToBasic()`\\n * @private\\n * @param {Number} codePoint The basic numeric code point value.\\n * @returns {Number} The numeric value of a basic code point (for use in\\n * representing integers) in the range `0` to `base - 1`, or `base` if\\n * the code point does not represent a value.\\n */\\nconst basicToDigit = function(codePoint) {\\n\\tif (codePoint >= 0x30 && codePoint < 0x3A) {\\n\\t\\treturn 26 + (codePoint - 0x30);\\n\\t}\\n\\tif (codePoint >= 0x41 && codePoint < 0x5B) {\\n\\t\\treturn codePoint - 0x41;\\n\\t}\\n\\tif (codePoint >= 0x61 && codePoint < 0x7B) {\\n\\t\\treturn codePoint - 0x61;\\n\\t}\\n\\treturn base;\\n};\\n\\n/**\\n * Converts a digit/integer into a basic code point.\\n * @see `basicToDigit()`\\n * @private\\n * @param {Number} digit The numeric value of a basic code point.\\n * @returns {Number} The basic code point whose value (when used for\\n * representing integers) is `digit`, which needs to be in the range\\n * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is\\n * used; else, the lowercase form is used. The behavior is undefined\\n * if `flag` is non-zero and `digit` has no uppercase form.\\n */\\nconst digitToBasic = function(digit, flag) {\\n\\t// 0..25 map to ASCII a..z or A..Z\\n\\t// 26..35 map to ASCII 0..9\\n\\treturn digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);\\n};\\n\\n/**\\n * Bias adaptation function as per section 3.4 of RFC 3492.\\n * https://tools.ietf.org/html/rfc3492#section-3.4\\n * @private\\n */\\nconst adapt = function(delta, numPoints, firstTime) {\\n\\tlet k = 0;\\n\\tdelta = firstTime ? floor(delta / damp) : delta >> 1;\\n\\tdelta += floor(delta / numPoints);\\n\\tfor (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {\\n\\t\\tdelta = floor(delta / baseMinusTMin);\\n\\t}\\n\\treturn floor(k + (baseMinusTMin + 1) * delta / (delta + skew));\\n};\\n\\n/**\\n * Converts a Punycode string of ASCII-only symbols to a string of Unicode\\n * symbols.\\n * @memberOf punycode\\n * @param {String} input The Punycode string of ASCII-only symbols.\\n * @returns {String} The resulting string of Unicode symbols.\\n */\\nconst decode = function(input) {\\n\\t// Don't use UCS-2.\\n\\tconst output = [];\\n\\tconst inputLength = input.length;\\n\\tlet i = 0;\\n\\tlet n = initialN;\\n\\tlet bias = initialBias;\\n\\n\\t// Handle the basic code points: let `basic` be the number of input code\\n\\t// points before the last delimiter, or `0` if there is none, then copy\\n\\t// the first basic code points to the output.\\n\\n\\tlet basic = input.lastIndexOf(delimiter);\\n\\tif (basic < 0) {\\n\\t\\tbasic = 0;\\n\\t}\\n\\n\\tfor (let j = 0; j < basic; ++j) {\\n\\t\\t// if it's not a basic code point\\n\\t\\tif (input.charCodeAt(j) >= 0x80) {\\n\\t\\t\\terror('not-basic');\\n\\t\\t}\\n\\t\\toutput.push(input.charCodeAt(j));\\n\\t}\\n\\n\\t// Main decoding loop: start just after the last delimiter if any basic code\\n\\t// points were copied; start at the beginning otherwise.\\n\\n\\tfor (let index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {\\n\\n\\t\\t// `index` is the index of the next character to be consumed.\\n\\t\\t// Decode a generalized variable-length integer into `delta`,\\n\\t\\t// which gets added to `i`. The overflow checking is easier\\n\\t\\t// if we increase `i` as we go, then subtract off its starting\\n\\t\\t// value at the end to obtain `delta`.\\n\\t\\tconst oldi = i;\\n\\t\\tfor (let w = 1, k = base; /* no condition */; k += base) {\\n\\n\\t\\t\\tif (index >= inputLength) {\\n\\t\\t\\t\\terror('invalid-input');\\n\\t\\t\\t}\\n\\n\\t\\t\\tconst digit = basicToDigit(input.charCodeAt(index++));\\n\\n\\t\\t\\tif (digit >= base) {\\n\\t\\t\\t\\terror('invalid-input');\\n\\t\\t\\t}\\n\\t\\t\\tif (digit > floor((maxInt - i) / w)) {\\n\\t\\t\\t\\terror('overflow');\\n\\t\\t\\t}\\n\\n\\t\\t\\ti += digit * w;\\n\\t\\t\\tconst t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);\\n\\n\\t\\t\\tif (digit < t) {\\n\\t\\t\\t\\tbreak;\\n\\t\\t\\t}\\n\\n\\t\\t\\tconst baseMinusT = base - t;\\n\\t\\t\\tif (w > floor(maxInt / baseMinusT)) {\\n\\t\\t\\t\\terror('overflow');\\n\\t\\t\\t}\\n\\n\\t\\t\\tw *= baseMinusT;\\n\\n\\t\\t}\\n\\n\\t\\tconst out = output.length + 1;\\n\\t\\tbias = adapt(i - oldi, out, oldi == 0);\\n\\n\\t\\t// `i` was supposed to wrap around from `out` to `0`,\\n\\t\\t// incrementing `n` each time, so we'll fix that now:\\n\\t\\tif (floor(i / out) > maxInt - n) {\\n\\t\\t\\terror('overflow');\\n\\t\\t}\\n\\n\\t\\tn += floor(i / out);\\n\\t\\ti %= out;\\n\\n\\t\\t// Insert `n` at position `i` of the output.\\n\\t\\toutput.splice(i++, 0, n);\\n\\n\\t}\\n\\n\\treturn String.fromCodePoint(...output);\\n};\\n\\n/**\\n * Converts a string of Unicode symbols (e.g. a domain name label) to a\\n * Punycode string of ASCII-only symbols.\\n * @memberOf punycode\\n * @param {String} input The string of Unicode symbols.\\n * @returns {String} The resulting Punycode string of ASCII-only symbols.\\n */\\nconst encode = function(input) {\\n\\tconst output = [];\\n\\n\\t// Convert the input in UCS-2 to an array of Unicode code points.\\n\\tinput = ucs2decode(input);\\n\\n\\t// Cache the length.\\n\\tconst inputLength = input.length;\\n\\n\\t// Initialize the state.\\n\\tlet n = initialN;\\n\\tlet delta = 0;\\n\\tlet bias = initialBias;\\n\\n\\t// Handle the basic code points.\\n\\tfor (const currentValue of input) {\\n\\t\\tif (currentValue < 0x80) {\\n\\t\\t\\toutput.push(stringFromCharCode(currentValue));\\n\\t\\t}\\n\\t}\\n\\n\\tconst basicLength = output.length;\\n\\tlet handledCPCount = basicLength;\\n\\n\\t// `handledCPCount` is the number of code points that have been handled;\\n\\t// `basicLength` is the number of basic code points.\\n\\n\\t// Finish the basic string with a delimiter unless it's empty.\\n\\tif (basicLength) {\\n\\t\\toutput.push(delimiter);\\n\\t}\\n\\n\\t// Main encoding loop:\\n\\twhile (handledCPCount < inputLength) {\\n\\n\\t\\t// All non-basic code points < n have been handled already. Find the next\\n\\t\\t// larger one:\\n\\t\\tlet m = maxInt;\\n\\t\\tfor (const currentValue of input) {\\n\\t\\t\\tif (currentValue >= n && currentValue < m) {\\n\\t\\t\\t\\tm = currentValue;\\n\\t\\t\\t}\\n\\t\\t}\\n\\n\\t\\t// Increase `delta` enough to advance the decoder's state to ,\\n\\t\\t// but guard against overflow.\\n\\t\\tconst handledCPCountPlusOne = handledCPCount + 1;\\n\\t\\tif (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {\\n\\t\\t\\terror('overflow');\\n\\t\\t}\\n\\n\\t\\tdelta += (m - n) * handledCPCountPlusOne;\\n\\t\\tn = m;\\n\\n\\t\\tfor (const currentValue of input) {\\n\\t\\t\\tif (currentValue < n && ++delta > maxInt) {\\n\\t\\t\\t\\terror('overflow');\\n\\t\\t\\t}\\n\\t\\t\\tif (currentValue === n) {\\n\\t\\t\\t\\t// Represent delta as a generalized variable-length integer.\\n\\t\\t\\t\\tlet q = delta;\\n\\t\\t\\t\\tfor (let k = base; /* no condition */; k += base) {\\n\\t\\t\\t\\t\\tconst t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);\\n\\t\\t\\t\\t\\tif (q < t) {\\n\\t\\t\\t\\t\\t\\tbreak;\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t\\tconst qMinusT = q - t;\\n\\t\\t\\t\\t\\tconst baseMinusT = base - t;\\n\\t\\t\\t\\t\\toutput.push(\\n\\t\\t\\t\\t\\t\\tstringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))\\n\\t\\t\\t\\t\\t);\\n\\t\\t\\t\\t\\tq = floor(qMinusT / baseMinusT);\\n\\t\\t\\t\\t}\\n\\n\\t\\t\\t\\toutput.push(stringFromCharCode(digitToBasic(q, 0)));\\n\\t\\t\\t\\tbias = adapt(delta, handledCPCountPlusOne, handledCPCount === basicLength);\\n\\t\\t\\t\\tdelta = 0;\\n\\t\\t\\t\\t++handledCPCount;\\n\\t\\t\\t}\\n\\t\\t}\\n\\n\\t\\t++delta;\\n\\t\\t++n;\\n\\n\\t}\\n\\treturn output.join('');\\n};\\n\\n/**\\n * Converts a Punycode string representing a domain name or an email address\\n * to Unicode. Only the Punycoded parts of the input will be converted, i.e.\\n * it doesn't matter if you call it on a string that has already been\\n * converted to Unicode.\\n * @memberOf punycode\\n * @param {String} input The Punycoded domain name or email address to\\n * convert to Unicode.\\n * @returns {String} The Unicode representation of the given Punycode\\n * string.\\n */\\nconst toUnicode = function(input) {\\n\\treturn mapDomain(input, function(string) {\\n\\t\\treturn regexPunycode.test(string)\\n\\t\\t\\t? decode(string.slice(4).toLowerCase())\\n\\t\\t\\t: string;\\n\\t});\\n};\\n\\n/**\\n * Converts a Unicode string representing a domain name or an email address to\\n * Punycode. Only the non-ASCII parts of the domain name will be converted,\\n * i.e. it doesn't matter if you call it with a domain that's already in\\n * ASCII.\\n * @memberOf punycode\\n * @param {String} input The domain name or email address to convert, as a\\n * Unicode string.\\n * @returns {String} The Punycode representation of the given domain name or\\n * email address.\\n */\\nconst toASCII = function(input) {\\n\\treturn mapDomain(input, function(string) {\\n\\t\\treturn regexNonASCII.test(string)\\n\\t\\t\\t? 'xn--' + encode(string)\\n\\t\\t\\t: string;\\n\\t});\\n};\\n\\n/*--------------------------------------------------------------------------*/\\n\\n/** Define the public API */\\nconst punycode = {\\n\\t/**\\n\\t * A string representing the current Punycode.js version number.\\n\\t * @memberOf punycode\\n\\t * @type String\\n\\t */\\n\\t'version': '2.3.1',\\n\\t/**\\n\\t * An object of methods to convert from JavaScript's internal character\\n\\t * representation (UCS-2) to Unicode code points, and back.\\n\\t * @see \\n\\t * @memberOf punycode\\n\\t * @type Object\\n\\t */\\n\\t'ucs2': {\\n\\t\\t'decode': ucs2decode,\\n\\t\\t'encode': ucs2encode\\n\\t},\\n\\t'decode': decode,\\n\\t'encode': encode,\\n\\t'toASCII': toASCII,\\n\\t'toUnicode': toUnicode\\n};\\n\\nexport { ucs2decode, ucs2encode, decode, encode, toASCII, toUnicode };\\nexport default punycode;\\n\",\"// markdown-it default options\\n\\nexport default {\\n options: {\\n // Enable HTML tags in source\\n html: false,\\n\\n // Use '/' to close single tags (
)\\n xhtmlOut: false,\\n\\n // Convert '\\\\n' in paragraphs into
\\n breaks: false,\\n\\n // CSS language prefix for fenced blocks\\n langPrefix: 'language-',\\n\\n // autoconvert URL-like texts to links\\n linkify: false,\\n\\n // Enable some language-neutral replacements + quotes beautification\\n typographer: false,\\n\\n // Double + single quotes replacement pairs, when typographer enabled,\\n // and smartquotes on. Could be either a String or an Array.\\n //\\n // For example, you can use '«»„“' for Russian, '„“‚‘' for German,\\n // and ['«\\\\xA0', '\\\\xA0»', '‹\\\\xA0', '\\\\xA0›'] for French (including nbsp).\\n quotes: '\\\\u201c\\\\u201d\\\\u2018\\\\u2019', /* “”‘’ */\\n\\n // Highlighter function. Should return escaped HTML,\\n // or '' if the source string is not changed and should be escaped externaly.\\n // If result starts with )\\n xhtmlOut: false,\\n\\n // Convert '\\\\n' in paragraphs into
\\n breaks: false,\\n\\n // CSS language prefix for fenced blocks\\n langPrefix: 'language-',\\n\\n // autoconvert URL-like texts to links\\n linkify: false,\\n\\n // Enable some language-neutral replacements + quotes beautification\\n typographer: false,\\n\\n // Double + single quotes replacement pairs, when typographer enabled,\\n // and smartquotes on. Could be either a String or an Array.\\n //\\n // For example, you can use '«»„“' for Russian, '„“‚‘' for German,\\n // and ['«\\\\xA0', '\\\\xA0»', '‹\\\\xA0', '\\\\xA0›'] for French (including nbsp).\\n quotes: '\\\\u201c\\\\u201d\\\\u2018\\\\u2019', /* “”‘’ */\\n\\n // Highlighter function. Should return escaped HTML,\\n // or '' if the source string is not changed and should be escaped externaly.\\n // If result starts with )\\n xhtmlOut: true,\\n\\n // Convert '\\\\n' in paragraphs into
\\n breaks: false,\\n\\n // CSS language prefix for fenced blocks\\n langPrefix: 'language-',\\n\\n // autoconvert URL-like texts to links\\n linkify: false,\\n\\n // Enable some language-neutral replacements + quotes beautification\\n typographer: false,\\n\\n // Double + single quotes replacement pairs, when typographer enabled,\\n // and smartquotes on. Could be either a String or an Array.\\n //\\n // For example, you can use '«»„“' for Russian, '„“‚‘' for German,\\n // and ['«\\\\xA0', '\\\\xA0»', '‹\\\\xA0', '\\\\xA0›'] for French (including nbsp).\\n quotes: '\\\\u201c\\\\u201d\\\\u2018\\\\u2019', /* “”‘’ */\\n\\n // Highlighter function. Should return escaped HTML,\\n // or '' if the source string is not changed and should be escaped externaly.\\n // If result starts with = 0) {\\n try {\\n parsed.hostname = punycode.toASCII(parsed.hostname)\\n } catch (er) { /**/ }\\n }\\n }\\n\\n return mdurl.encode(mdurl.format(parsed))\\n}\\n\\nfunction normalizeLinkText (url) {\\n const parsed = mdurl.parse(url, true)\\n\\n if (parsed.hostname) {\\n // Encode hostnames in urls like:\\n // `http://host/`, `https://host/`, `mailto:user@host`, `//host/`\\n //\\n // We don't encode unknown schemas, because it's likely that we encode\\n // something we shouldn't (e.g. `skype:name` treated as `skype:host`)\\n //\\n if (!parsed.protocol || RECODE_HOSTNAME_FOR.indexOf(parsed.protocol) >= 0) {\\n try {\\n parsed.hostname = punycode.toUnicode(parsed.hostname)\\n } catch (er) { /**/ }\\n }\\n }\\n\\n // add '%' to exclude list because of https://github.com/markdown-it/markdown-it/issues/720\\n return mdurl.decode(mdurl.format(parsed), mdurl.decode.defaultChars + '%')\\n}\\n\\n/**\\n * class MarkdownIt\\n *\\n * Main parser/renderer class.\\n *\\n * ##### Usage\\n *\\n * ```javascript\\n * // node.js, \\\"classic\\\" way:\\n * var MarkdownIt = require('markdown-it'),\\n * md = new MarkdownIt();\\n * var result = md.render('# markdown-it rulezz!');\\n *\\n * // node.js, the same, but with sugar:\\n * var md = require('markdown-it')();\\n * var result = md.render('# markdown-it rulezz!');\\n *\\n * // browser without AMD, added to \\\"window\\\" on script load\\n * // Note, there are no dash.\\n * var md = window.markdownit();\\n * var result = md.render('# markdown-it rulezz!');\\n * ```\\n *\\n * Single line rendering, without paragraph wrap:\\n *\\n * ```javascript\\n * var md = require('markdown-it')();\\n * var result = md.renderInline('__markdown-it__ rulezz!');\\n * ```\\n **/\\n\\n/**\\n * new MarkdownIt([presetName, options])\\n * - presetName (String): optional, `commonmark` / `zero`\\n * - options (Object)\\n *\\n * Creates parser instanse with given config. Can be called without `new`.\\n *\\n * ##### presetName\\n *\\n * MarkdownIt provides named presets as a convenience to quickly\\n * enable/disable active syntax rules and options for common use cases.\\n *\\n * - [\\\"commonmark\\\"](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/commonmark.mjs) -\\n * configures parser to strict [CommonMark](http://commonmark.org/) mode.\\n * - [default](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/default.mjs) -\\n * similar to GFM, used when no preset name given. Enables all available rules,\\n * but still without html, typographer & autolinker.\\n * - [\\\"zero\\\"](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/zero.mjs) -\\n * all rules disabled. Useful to quickly setup your config via `.enable()`.\\n * For example, when you need only `bold` and `italic` markup and nothing else.\\n *\\n * ##### options:\\n *\\n * - __html__ - `false`. Set `true` to enable HTML tags in source. Be careful!\\n * That's not safe! You may need external sanitizer to protect output from XSS.\\n * It's better to extend features via plugins, instead of enabling HTML.\\n * - __xhtmlOut__ - `false`. Set `true` to add '/' when closing single tags\\n * (`
`). This is needed only for full CommonMark compatibility. In real\\n * world you will need HTML output.\\n * - __breaks__ - `false`. Set `true` to convert `\\\\n` in paragraphs into `
`.\\n * - __langPrefix__ - `language-`. CSS language class prefix for fenced blocks.\\n * Can be useful for external highlighters.\\n * - __linkify__ - `false`. Set `true` to autoconvert URL-like text to links.\\n * - __typographer__ - `false`. Set `true` to enable [some language-neutral\\n * replacement](https://github.com/markdown-it/markdown-it/blob/master/lib/rules_core/replacements.mjs) +\\n * quotes beautification (smartquotes).\\n * - __quotes__ - `“”‘’`, String or Array. Double + single quotes replacement\\n * pairs, when typographer enabled and smartquotes on. For example, you can\\n * use `'«»„“'` for Russian, `'„“‚‘'` for German, and\\n * `['«\\\\xA0', '\\\\xA0»', '‹\\\\xA0', '\\\\xA0›']` for French (including nbsp).\\n * - __highlight__ - `null`. Highlighter function for fenced code blocks.\\n * Highlighter `function (str, lang)` should return escaped HTML. It can also\\n * return empty string if the source was not changed and should be escaped\\n * externaly. If result starts with ` or ``):\\n *\\n * ```javascript\\n * var hljs = require('highlight.js') // https://highlightjs.org/\\n *\\n * // Actual default values\\n * var md = require('markdown-it')({\\n * highlight: function (str, lang) {\\n * if (lang && hljs.getLanguage(lang)) {\\n * try {\\n * return '
' +\\n *                hljs.highlight(str, { language: lang, ignoreIllegals: true }).value +\\n *                '
';\\n * } catch (__) {}\\n * }\\n *\\n * return '
' + md.utils.escapeHtml(str) + '
';\\n * }\\n * });\\n * ```\\n *\\n **/\\nfunction MarkdownIt (presetName, options) {\\n if (!(this instanceof MarkdownIt)) {\\n return new MarkdownIt(presetName, options)\\n }\\n\\n if (!options) {\\n if (!utils.isString(presetName)) {\\n options = presetName || {}\\n presetName = 'default'\\n }\\n }\\n\\n /**\\n * MarkdownIt#inline -> ParserInline\\n *\\n * Instance of [[ParserInline]]. You may need it to add new rules when\\n * writing plugins. For simple rules control use [[MarkdownIt.disable]] and\\n * [[MarkdownIt.enable]].\\n **/\\n this.inline = new ParserInline()\\n\\n /**\\n * MarkdownIt#block -> ParserBlock\\n *\\n * Instance of [[ParserBlock]]. You may need it to add new rules when\\n * writing plugins. For simple rules control use [[MarkdownIt.disable]] and\\n * [[MarkdownIt.enable]].\\n **/\\n this.block = new ParserBlock()\\n\\n /**\\n * MarkdownIt#core -> Core\\n *\\n * Instance of [[Core]] chain executor. You may need it to add new rules when\\n * writing plugins. For simple rules control use [[MarkdownIt.disable]] and\\n * [[MarkdownIt.enable]].\\n **/\\n this.core = new ParserCore()\\n\\n /**\\n * MarkdownIt#renderer -> Renderer\\n *\\n * Instance of [[Renderer]]. Use it to modify output look. Or to add rendering\\n * rules for new token types, generated by plugins.\\n *\\n * ##### Example\\n *\\n * ```javascript\\n * var md = require('markdown-it')();\\n *\\n * function myToken(tokens, idx, options, env, self) {\\n * //...\\n * return result;\\n * };\\n *\\n * md.renderer.rules['my_token'] = myToken\\n * ```\\n *\\n * See [[Renderer]] docs and [source code](https://github.com/markdown-it/markdown-it/blob/master/lib/renderer.mjs).\\n **/\\n this.renderer = new Renderer()\\n\\n /**\\n * MarkdownIt#linkify -> LinkifyIt\\n *\\n * [linkify-it](https://github.com/markdown-it/linkify-it) instance.\\n * Used by [linkify](https://github.com/markdown-it/markdown-it/blob/master/lib/rules_core/linkify.mjs)\\n * rule.\\n **/\\n this.linkify = new LinkifyIt()\\n\\n /**\\n * MarkdownIt#validateLink(url) -> Boolean\\n *\\n * Link validation function. CommonMark allows too much in links. By default\\n * we disable `javascript:`, `vbscript:`, `file:` schemas, and almost all `data:...` schemas\\n * except some embedded image types.\\n *\\n * You can change this behaviour:\\n *\\n * ```javascript\\n * var md = require('markdown-it')();\\n * // enable everything\\n * md.validateLink = function () { return true; }\\n * ```\\n **/\\n this.validateLink = validateLink\\n\\n /**\\n * MarkdownIt#normalizeLink(url) -> String\\n *\\n * Function used to encode link url to a machine-readable format,\\n * which includes url-encoding, punycode, etc.\\n **/\\n this.normalizeLink = normalizeLink\\n\\n /**\\n * MarkdownIt#normalizeLinkText(url) -> String\\n *\\n * Function used to decode link url to a human-readable format`\\n **/\\n this.normalizeLinkText = normalizeLinkText\\n\\n // Expose utils & helpers for easy acces from plugins\\n\\n /**\\n * MarkdownIt#utils -> utils\\n *\\n * Assorted utility functions, useful to write plugins. See details\\n * [here](https://github.com/markdown-it/markdown-it/blob/master/lib/common/utils.mjs).\\n **/\\n this.utils = utils\\n\\n /**\\n * MarkdownIt#helpers -> helpers\\n *\\n * Link components parser functions, useful to write plugins. See details\\n * [here](https://github.com/markdown-it/markdown-it/blob/master/lib/helpers).\\n **/\\n this.helpers = utils.assign({}, helpers)\\n\\n this.options = {}\\n this.configure(presetName)\\n\\n if (options) { this.set(options) }\\n}\\n\\n/** chainable\\n * MarkdownIt.set(options)\\n *\\n * Set parser options (in the same format as in constructor). Probably, you\\n * will never need it, but you can change options after constructor call.\\n *\\n * ##### Example\\n *\\n * ```javascript\\n * var md = require('markdown-it')()\\n * .set({ html: true, breaks: true })\\n * .set({ typographer, true });\\n * ```\\n *\\n * __Note:__ To achieve the best possible performance, don't modify a\\n * `markdown-it` instance options on the fly. If you need multiple configurations\\n * it's best to create multiple instances and initialize each with separate\\n * config.\\n **/\\nMarkdownIt.prototype.set = function (options) {\\n utils.assign(this.options, options)\\n return this\\n}\\n\\n/** chainable, internal\\n * MarkdownIt.configure(presets)\\n *\\n * Batch load of all options and compenent settings. This is internal method,\\n * and you probably will not need it. But if you will - see available presets\\n * and data structure [here](https://github.com/markdown-it/markdown-it/tree/master/lib/presets)\\n *\\n * We strongly recommend to use presets instead of direct config loads. That\\n * will give better compatibility with next versions.\\n **/\\nMarkdownIt.prototype.configure = function (presets) {\\n const self = this\\n\\n if (utils.isString(presets)) {\\n const presetName = presets\\n presets = config[presetName]\\n if (!presets) { throw new Error('Wrong `markdown-it` preset \\\"' + presetName + '\\\", check name') }\\n }\\n\\n if (!presets) { throw new Error('Wrong `markdown-it` preset, can\\\\'t be empty') }\\n\\n if (presets.options) { self.set(presets.options) }\\n\\n if (presets.components) {\\n Object.keys(presets.components).forEach(function (name) {\\n if (presets.components[name].rules) {\\n self[name].ruler.enableOnly(presets.components[name].rules)\\n }\\n if (presets.components[name].rules2) {\\n self[name].ruler2.enableOnly(presets.components[name].rules2)\\n }\\n })\\n }\\n return this\\n}\\n\\n/** chainable\\n * MarkdownIt.enable(list, ignoreInvalid)\\n * - list (String|Array): rule name or list of rule names to enable\\n * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.\\n *\\n * Enable list or rules. It will automatically find appropriate components,\\n * containing rules with given names. If rule not found, and `ignoreInvalid`\\n * not set - throws exception.\\n *\\n * ##### Example\\n *\\n * ```javascript\\n * var md = require('markdown-it')()\\n * .enable(['sub', 'sup'])\\n * .disable('smartquotes');\\n * ```\\n **/\\nMarkdownIt.prototype.enable = function (list, ignoreInvalid) {\\n let result = []\\n\\n if (!Array.isArray(list)) { list = [list] }\\n\\n ['core', 'block', 'inline'].forEach(function (chain) {\\n result = result.concat(this[chain].ruler.enable(list, true))\\n }, this)\\n\\n result = result.concat(this.inline.ruler2.enable(list, true))\\n\\n const missed = list.filter(function (name) { return result.indexOf(name) < 0 })\\n\\n if (missed.length && !ignoreInvalid) {\\n throw new Error('MarkdownIt. Failed to enable unknown rule(s): ' + missed)\\n }\\n\\n return this\\n}\\n\\n/** chainable\\n * MarkdownIt.disable(list, ignoreInvalid)\\n * - list (String|Array): rule name or list of rule names to disable.\\n * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.\\n *\\n * The same as [[MarkdownIt.enable]], but turn specified rules off.\\n **/\\nMarkdownIt.prototype.disable = function (list, ignoreInvalid) {\\n let result = []\\n\\n if (!Array.isArray(list)) { list = [list] }\\n\\n ['core', 'block', 'inline'].forEach(function (chain) {\\n result = result.concat(this[chain].ruler.disable(list, true))\\n }, this)\\n\\n result = result.concat(this.inline.ruler2.disable(list, true))\\n\\n const missed = list.filter(function (name) { return result.indexOf(name) < 0 })\\n\\n if (missed.length && !ignoreInvalid) {\\n throw new Error('MarkdownIt. Failed to disable unknown rule(s): ' + missed)\\n }\\n return this\\n}\\n\\n/** chainable\\n * MarkdownIt.use(plugin, params)\\n *\\n * Load specified plugin with given params into current parser instance.\\n * It's just a sugar to call `plugin(md, params)` with curring.\\n *\\n * ##### Example\\n *\\n * ```javascript\\n * var iterator = require('markdown-it-for-inline');\\n * var md = require('markdown-it')()\\n * .use(iterator, 'foo_replace', 'text', function (tokens, idx) {\\n * tokens[idx].content = tokens[idx].content.replace(/foo/g, 'bar');\\n * });\\n * ```\\n **/\\nMarkdownIt.prototype.use = function (plugin /*, params, ... */) {\\n const args = [this].concat(Array.prototype.slice.call(arguments, 1))\\n plugin.apply(plugin, args)\\n return this\\n}\\n\\n/** internal\\n * MarkdownIt.parse(src, env) -> Array\\n * - src (String): source string\\n * - env (Object): environment sandbox\\n *\\n * Parse input string and return list of block tokens (special token type\\n * \\\"inline\\\" will contain list of inline tokens). You should not call this\\n * method directly, until you write custom renderer (for example, to produce\\n * AST).\\n *\\n * `env` is used to pass data between \\\"distributed\\\" rules and return additional\\n * metadata like reference info, needed for the renderer. It also can be used to\\n * inject data in specific cases. Usually, you will be ok to pass `{}`,\\n * and then pass updated object to renderer.\\n **/\\nMarkdownIt.prototype.parse = function (src, env) {\\n if (typeof src !== 'string') {\\n throw new Error('Input data should be a String')\\n }\\n\\n const state = new this.core.State(src, this, env)\\n\\n this.core.process(state)\\n\\n return state.tokens\\n}\\n\\n/**\\n * MarkdownIt.render(src [, env]) -> String\\n * - src (String): source string\\n * - env (Object): environment sandbox\\n *\\n * Render markdown string into html. It does all magic for you :).\\n *\\n * `env` can be used to inject additional metadata (`{}` by default).\\n * But you will not need it with high probability. See also comment\\n * in [[MarkdownIt.parse]].\\n **/\\nMarkdownIt.prototype.render = function (src, env) {\\n env = env || {}\\n\\n return this.renderer.render(this.parse(src, env), this.options, env)\\n}\\n\\n/** internal\\n * MarkdownIt.parseInline(src, env) -> Array\\n * - src (String): source string\\n * - env (Object): environment sandbox\\n *\\n * The same as [[MarkdownIt.parse]] but skip all block rules. It returns the\\n * block tokens list with the single `inline` element, containing parsed inline\\n * tokens in `children` property. Also updates `env` object.\\n **/\\nMarkdownIt.prototype.parseInline = function (src, env) {\\n const state = new this.core.State(src, this, env)\\n\\n state.inlineMode = true\\n this.core.process(state)\\n\\n return state.tokens\\n}\\n\\n/**\\n * MarkdownIt.renderInline(src [, env]) -> String\\n * - src (String): source string\\n * - env (Object): environment sandbox\\n *\\n * Similar to [[MarkdownIt.render]] but for single paragraph content. Result\\n * will NOT be wrapped into `

` tags.\\n **/\\nMarkdownIt.prototype.renderInline = function (src, env) {\\n env = env || {}\\n\\n return this.renderer.render(this.parseInline(src, env), this.options, env)\\n}\\n\\nexport default MarkdownIt\\n\",\"/**\\n * Utilities for hex, bytes, CSPRNG.\\n * @module\\n */\\n/*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */\\n\\n// We use WebCrypto aka globalThis.crypto, which exists in browsers and node.js 16+.\\n// node.js versions earlier than v19 don't declare it in global scope.\\n// For node.js, package.json#exports field mapping rewrites import\\n// from `crypto` to `cryptoNode`, which imports native module.\\n// Makes the utils un-importable in browsers without a bundler.\\n// Once node.js 18 is deprecated (2025-04-30), we can just drop the import.\\nimport { crypto } from '@noble/hashes/crypto';\\n\\n/** Checks if something is Uint8Array. Be careful: nodejs Buffer will return true. */\\nexport function isBytes(a: unknown): a is Uint8Array {\\n return a instanceof Uint8Array || (ArrayBuffer.isView(a) && a.constructor.name === 'Uint8Array');\\n}\\n\\n/** Asserts something is positive integer. */\\nexport function anumber(n: number): void {\\n if (!Number.isSafeInteger(n) || n < 0) throw new Error('positive integer expected, got ' + n);\\n}\\n\\n/** Asserts something is Uint8Array. */\\nexport function abytes(b: Uint8Array | undefined, ...lengths: number[]): void {\\n if (!isBytes(b)) throw new Error('Uint8Array expected');\\n if (lengths.length > 0 && !lengths.includes(b.length))\\n throw new Error('Uint8Array expected of length ' + lengths + ', got length=' + b.length);\\n}\\n\\n/** Asserts something is hash */\\nexport function ahash(h: IHash): void {\\n if (typeof h !== 'function' || typeof h.create !== 'function')\\n throw new Error('Hash should be wrapped by utils.createHasher');\\n anumber(h.outputLen);\\n anumber(h.blockLen);\\n}\\n\\n/** Asserts a hash instance has not been destroyed / finished */\\nexport function aexists(instance: any, checkFinished = true): void {\\n if (instance.destroyed) throw new Error('Hash instance has been destroyed');\\n if (checkFinished && instance.finished) throw new Error('Hash#digest() has already been called');\\n}\\n\\n/** Asserts output is properly-sized byte array */\\nexport function aoutput(out: any, instance: any): void {\\n abytes(out);\\n const min = instance.outputLen;\\n if (out.length < min) {\\n throw new Error('digestInto() expects output buffer of length at least ' + min);\\n }\\n}\\n\\n/** Generic type encompassing 8/16/32-byte arrays - but not 64-byte. */\\n// prettier-ignore\\nexport type TypedArray = Int8Array | Uint8ClampedArray | Uint8Array |\\n Uint16Array | Int16Array | Uint32Array | Int32Array;\\n\\n/** Cast u8 / u16 / u32 to u8. */\\nexport function u8(arr: TypedArray): Uint8Array {\\n return new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength);\\n}\\n\\n/** Cast u8 / u16 / u32 to u32. */\\nexport function u32(arr: TypedArray): Uint32Array {\\n return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4));\\n}\\n\\n/** Zeroize a byte array. Warning: JS provides no guarantees. */\\nexport function clean(...arrays: TypedArray[]): void {\\n for (let i = 0; i < arrays.length; i++) {\\n arrays[i].fill(0);\\n }\\n}\\n\\n/** Create DataView of an array for easy byte-level manipulation. */\\nexport function createView(arr: TypedArray): DataView {\\n return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);\\n}\\n\\n/** The rotate right (circular right shift) operation for uint32 */\\nexport function rotr(word: number, shift: number): number {\\n return (word << (32 - shift)) | (word >>> shift);\\n}\\n\\n/** The rotate left (circular left shift) operation for uint32 */\\nexport function rotl(word: number, shift: number): number {\\n return (word << shift) | ((word >>> (32 - shift)) >>> 0);\\n}\\n\\n/** Is current platform little-endian? Most are. Big-Endian platform: IBM */\\nexport const isLE: boolean = /* @__PURE__ */ (() =>\\n new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x44)();\\n\\n/** The byte swap operation for uint32 */\\nexport function byteSwap(word: number): number {\\n return (\\n ((word << 24) & 0xff000000) |\\n ((word << 8) & 0xff0000) |\\n ((word >>> 8) & 0xff00) |\\n ((word >>> 24) & 0xff)\\n );\\n}\\n/** Conditionally byte swap if on a big-endian platform */\\nexport const swap8IfBE: (n: number) => number = isLE\\n ? (n: number) => n\\n : (n: number) => byteSwap(n);\\n\\n/** @deprecated */\\nexport const byteSwapIfBE: typeof swap8IfBE = swap8IfBE;\\n/** In place byte swap for Uint32Array */\\nexport function byteSwap32(arr: Uint32Array): Uint32Array {\\n for (let i = 0; i < arr.length; i++) {\\n arr[i] = byteSwap(arr[i]);\\n }\\n return arr;\\n}\\n\\nexport const swap32IfBE: (u: Uint32Array) => Uint32Array = isLE\\n ? (u: Uint32Array) => u\\n : byteSwap32;\\n\\n// Built-in hex conversion https://caniuse.com/mdn-javascript_builtins_uint8array_fromhex\\nconst hasHexBuiltin: boolean = /* @__PURE__ */ (() =>\\n // @ts-ignore\\n typeof Uint8Array.from([]).toHex === 'function' && typeof Uint8Array.fromHex === 'function')();\\n\\n// Array where index 0xf0 (240) is mapped to string 'f0'\\nconst hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) =>\\n i.toString(16).padStart(2, '0')\\n);\\n\\n/**\\n * Convert byte array to hex string. Uses built-in function, when available.\\n * @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'\\n */\\nexport function bytesToHex(bytes: Uint8Array): string {\\n abytes(bytes);\\n // @ts-ignore\\n if (hasHexBuiltin) return bytes.toHex();\\n // pre-caching improves the speed 6x\\n let hex = '';\\n for (let i = 0; i < bytes.length; i++) {\\n hex += hexes[bytes[i]];\\n }\\n return hex;\\n}\\n\\n// We use optimized technique to convert hex string to byte array\\nconst asciis = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 } as const;\\nfunction asciiToBase16(ch: number): number | undefined {\\n if (ch >= asciis._0 && ch <= asciis._9) return ch - asciis._0; // '2' => 50-48\\n if (ch >= asciis.A && ch <= asciis.F) return ch - (asciis.A - 10); // 'B' => 66-(65-10)\\n if (ch >= asciis.a && ch <= asciis.f) return ch - (asciis.a - 10); // 'b' => 98-(97-10)\\n return;\\n}\\n\\n/**\\n * Convert hex string to byte array. Uses built-in function, when available.\\n * @example hexToBytes('cafe0123') // Uint8Array.from([0xca, 0xfe, 0x01, 0x23])\\n */\\nexport function hexToBytes(hex: string): Uint8Array {\\n if (typeof hex !== 'string') throw new Error('hex string expected, got ' + typeof hex);\\n // @ts-ignore\\n if (hasHexBuiltin) return Uint8Array.fromHex(hex);\\n const hl = hex.length;\\n const al = hl / 2;\\n if (hl % 2) throw new Error('hex string expected, got unpadded hex of length ' + hl);\\n const array = new Uint8Array(al);\\n for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {\\n const n1 = asciiToBase16(hex.charCodeAt(hi));\\n const n2 = asciiToBase16(hex.charCodeAt(hi + 1));\\n if (n1 === undefined || n2 === undefined) {\\n const char = hex[hi] + hex[hi + 1];\\n throw new Error('hex string expected, got non-hex character \\\"' + char + '\\\" at index ' + hi);\\n }\\n array[ai] = n1 * 16 + n2; // multiply first octet, e.g. 'a3' => 10*16+3 => 160 + 3 => 163\\n }\\n return array;\\n}\\n\\n/**\\n * There is no setImmediate in browser and setTimeout is slow.\\n * Call of async fn will return Promise, which will be fullfiled only on\\n * next scheduler queue processing step and this is exactly what we need.\\n */\\nexport const nextTick = async (): Promise => {};\\n\\n/** Returns control to thread each 'tick' ms to avoid blocking. */\\nexport async function asyncLoop(\\n iters: number,\\n tick: number,\\n cb: (i: number) => void\\n): Promise {\\n let ts = Date.now();\\n for (let i = 0; i < iters; i++) {\\n cb(i);\\n // Date.now() is not monotonic, so in case if clock goes backwards we return return control too\\n const diff = Date.now() - ts;\\n if (diff >= 0 && diff < tick) continue;\\n await nextTick();\\n ts += diff;\\n }\\n}\\n\\n// Global symbols, but ts doesn't see them: https://github.com/microsoft/TypeScript/issues/31535\\ndeclare const TextEncoder: any;\\ndeclare const TextDecoder: any;\\n\\n/**\\n * Converts string to bytes using UTF8 encoding.\\n * @example utf8ToBytes('abc') // Uint8Array.from([97, 98, 99])\\n */\\nexport function utf8ToBytes(str: string): Uint8Array {\\n if (typeof str !== 'string') throw new Error('string expected');\\n return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809\\n}\\n\\n/**\\n * Converts bytes to string using UTF8 encoding.\\n * @example bytesToUtf8(Uint8Array.from([97, 98, 99])) // 'abc'\\n */\\nexport function bytesToUtf8(bytes: Uint8Array): string {\\n return new TextDecoder().decode(bytes);\\n}\\n\\n/** Accepted input of hash functions. Strings are converted to byte arrays. */\\nexport type Input = string | Uint8Array;\\n/**\\n * Normalizes (non-hex) string or Uint8Array to Uint8Array.\\n * Warning: when Uint8Array is passed, it would NOT get copied.\\n * Keep in mind for future mutable operations.\\n */\\nexport function toBytes(data: Input): Uint8Array {\\n if (typeof data === 'string') data = utf8ToBytes(data);\\n abytes(data);\\n return data;\\n}\\n\\n/** KDFs can accept string or Uint8Array for user convenience. */\\nexport type KDFInput = string | Uint8Array;\\n/**\\n * Helper for KDFs: consumes uint8array or string.\\n * When string is passed, does utf8 decoding, using TextDecoder.\\n */\\nexport function kdfInputToBytes(data: KDFInput): Uint8Array {\\n if (typeof data === 'string') data = utf8ToBytes(data);\\n abytes(data);\\n return data;\\n}\\n\\n/** Copies several Uint8Arrays into one. */\\nexport function concatBytes(...arrays: Uint8Array[]): Uint8Array {\\n let sum = 0;\\n for (let i = 0; i < arrays.length; i++) {\\n const a = arrays[i];\\n abytes(a);\\n sum += a.length;\\n }\\n const res = new Uint8Array(sum);\\n for (let i = 0, pad = 0; i < arrays.length; i++) {\\n const a = arrays[i];\\n res.set(a, pad);\\n pad += a.length;\\n }\\n return res;\\n}\\n\\ntype EmptyObj = {};\\nexport function checkOpts(\\n defaults: T1,\\n opts?: T2\\n): T1 & T2 {\\n if (opts !== undefined && {}.toString.call(opts) !== '[object Object]')\\n throw new Error('options should be object or undefined');\\n const merged = Object.assign(defaults, opts);\\n return merged as T1 & T2;\\n}\\n\\n/** Hash interface. */\\nexport type IHash = {\\n (data: Uint8Array): Uint8Array;\\n blockLen: number;\\n outputLen: number;\\n create: any;\\n};\\n\\n/** For runtime check if class implements interface */\\nexport abstract class Hash> {\\n abstract blockLen: number; // Bytes per block\\n abstract outputLen: number; // Bytes in output\\n abstract update(buf: Input): this;\\n // Writes digest into buf\\n abstract digestInto(buf: Uint8Array): void;\\n abstract digest(): Uint8Array;\\n /**\\n * Resets internal state. Makes Hash instance unusable.\\n * Reset is impossible for keyed hashes if key is consumed into state. If digest is not consumed\\n * by user, they will need to manually call `destroy()` when zeroing is necessary.\\n */\\n abstract destroy(): void;\\n /**\\n * Clones hash instance. Unsafe: doesn't check whether `to` is valid. Can be used as `clone()`\\n * when no options are passed.\\n * Reasons to use `_cloneInto` instead of clone: 1) performance 2) reuse instance => all internal\\n * buffers are overwritten => causes buffer overwrite which is used for digest in some cases.\\n * There are no guarantees for clean-up because it's impossible in JS.\\n */\\n abstract _cloneInto(to?: T): T;\\n // Safe version that clones internal state\\n abstract clone(): T;\\n}\\n\\n/**\\n * XOF: streaming API to read digest in chunks.\\n * Same as 'squeeze' in keccak/k12 and 'seek' in blake3, but more generic name.\\n * When hash used in XOF mode it is up to user to call '.destroy' afterwards, since we cannot\\n * destroy state, next call can require more bytes.\\n */\\nexport type HashXOF> = Hash & {\\n xof(bytes: number): Uint8Array; // Read 'bytes' bytes from digest stream\\n xofInto(buf: Uint8Array): Uint8Array; // read buf.length bytes from digest stream into buf\\n};\\n\\n/** Hash function */\\nexport type CHash = ReturnType;\\n/** Hash function with output */\\nexport type CHashO = ReturnType;\\n/** XOF with output */\\nexport type CHashXO = ReturnType;\\n\\n/** Wraps hash function, creating an interface on top of it */\\nexport function createHasher>(\\n hashCons: () => Hash\\n): {\\n (msg: Input): Uint8Array;\\n outputLen: number;\\n blockLen: number;\\n create(): Hash;\\n} {\\n const hashC = (msg: Input): Uint8Array => hashCons().update(toBytes(msg)).digest();\\n const tmp = hashCons();\\n hashC.outputLen = tmp.outputLen;\\n hashC.blockLen = tmp.blockLen;\\n hashC.create = () => hashCons();\\n return hashC;\\n}\\n\\nexport function createOptHasher, T extends Object>(\\n hashCons: (opts?: T) => Hash\\n): {\\n (msg: Input, opts?: T): Uint8Array;\\n outputLen: number;\\n blockLen: number;\\n create(opts?: T): Hash;\\n} {\\n const hashC = (msg: Input, opts?: T): Uint8Array => hashCons(opts).update(toBytes(msg)).digest();\\n const tmp = hashCons({} as T);\\n hashC.outputLen = tmp.outputLen;\\n hashC.blockLen = tmp.blockLen;\\n hashC.create = (opts?: T) => hashCons(opts);\\n return hashC;\\n}\\n\\nexport function createXOFer, T extends Object>(\\n hashCons: (opts?: T) => HashXOF\\n): {\\n (msg: Input, opts?: T): Uint8Array;\\n outputLen: number;\\n blockLen: number;\\n create(opts?: T): HashXOF;\\n} {\\n const hashC = (msg: Input, opts?: T): Uint8Array => hashCons(opts).update(toBytes(msg)).digest();\\n const tmp = hashCons({} as T);\\n hashC.outputLen = tmp.outputLen;\\n hashC.blockLen = tmp.blockLen;\\n hashC.create = (opts?: T) => hashCons(opts);\\n return hashC;\\n}\\nexport const wrapConstructor: typeof createHasher = createHasher;\\nexport const wrapConstructorWithOpts: typeof createOptHasher = createOptHasher;\\nexport const wrapXOFConstructorWithOpts: typeof createXOFer = createXOFer;\\n\\n/** Cryptographically secure PRNG. Uses internal OS-level `crypto.getRandomValues`. */\\nexport function randomBytes(bytesLength = 32): Uint8Array {\\n if (crypto && typeof crypto.getRandomValues === 'function') {\\n return crypto.getRandomValues(new Uint8Array(bytesLength));\\n }\\n // Legacy Node.js compatibility\\n if (crypto && typeof crypto.randomBytes === 'function') {\\n return Uint8Array.from(crypto.randomBytes(bytesLength));\\n }\\n throw new Error('crypto.getRandomValues must be defined');\\n}\\n\",\"/**\\n * Internal Merkle-Damgard hash utils.\\n * @module\\n */\\nimport { type Input, Hash, abytes, aexists, aoutput, clean, createView, toBytes } from './utils.ts';\\n\\n/** Polyfill for Safari 14. https://caniuse.com/mdn-javascript_builtins_dataview_setbiguint64 */\\nexport function setBigUint64(\\n view: DataView,\\n byteOffset: number,\\n value: bigint,\\n isLE: boolean\\n): void {\\n if (typeof view.setBigUint64 === 'function') return view.setBigUint64(byteOffset, value, isLE);\\n const _32n = BigInt(32);\\n const _u32_max = BigInt(0xffffffff);\\n const wh = Number((value >> _32n) & _u32_max);\\n const wl = Number(value & _u32_max);\\n const h = isLE ? 4 : 0;\\n const l = isLE ? 0 : 4;\\n view.setUint32(byteOffset + h, wh, isLE);\\n view.setUint32(byteOffset + l, wl, isLE);\\n}\\n\\n/** Choice: a ? b : c */\\nexport function Chi(a: number, b: number, c: number): number {\\n return (a & b) ^ (~a & c);\\n}\\n\\n/** Majority function, true if any two inputs is true. */\\nexport function Maj(a: number, b: number, c: number): number {\\n return (a & b) ^ (a & c) ^ (b & c);\\n}\\n\\n/**\\n * Merkle-Damgard hash construction base class.\\n * Could be used to create MD5, RIPEMD, SHA1, SHA2.\\n */\\nexport abstract class HashMD> extends Hash {\\n protected abstract process(buf: DataView, offset: number): void;\\n protected abstract get(): number[];\\n protected abstract set(...args: number[]): void;\\n abstract destroy(): void;\\n protected abstract roundClean(): void;\\n\\n readonly blockLen: number;\\n readonly outputLen: number;\\n readonly padOffset: number;\\n readonly isLE: boolean;\\n\\n // For partial updates less than block size\\n protected buffer: Uint8Array;\\n protected view: DataView;\\n protected finished = false;\\n protected length = 0;\\n protected pos = 0;\\n protected destroyed = false;\\n\\n constructor(blockLen: number, outputLen: number, padOffset: number, isLE: boolean) {\\n super();\\n this.blockLen = blockLen;\\n this.outputLen = outputLen;\\n this.padOffset = padOffset;\\n this.isLE = isLE;\\n this.buffer = new Uint8Array(blockLen);\\n this.view = createView(this.buffer);\\n }\\n update(data: Input): this {\\n aexists(this);\\n data = toBytes(data);\\n abytes(data);\\n const { view, buffer, blockLen } = this;\\n const len = data.length;\\n for (let pos = 0; pos < len; ) {\\n const take = Math.min(blockLen - this.pos, len - pos);\\n // Fast path: we have at least one block in input, cast it to view and process\\n if (take === blockLen) {\\n const dataView = createView(data);\\n for (; blockLen <= len - pos; pos += blockLen) this.process(dataView, pos);\\n continue;\\n }\\n buffer.set(data.subarray(pos, pos + take), this.pos);\\n this.pos += take;\\n pos += take;\\n if (this.pos === blockLen) {\\n this.process(view, 0);\\n this.pos = 0;\\n }\\n }\\n this.length += data.length;\\n this.roundClean();\\n return this;\\n }\\n digestInto(out: Uint8Array): void {\\n aexists(this);\\n aoutput(out, this);\\n this.finished = true;\\n // Padding\\n // We can avoid allocation of buffer for padding completely if it\\n // was previously not allocated here. But it won't change performance.\\n const { buffer, view, blockLen, isLE } = this;\\n let { pos } = this;\\n // append the bit '1' to the message\\n buffer[pos++] = 0b10000000;\\n clean(this.buffer.subarray(pos));\\n // we have less than padOffset left in buffer, so we cannot put length in\\n // current block, need process it and pad again\\n if (this.padOffset > blockLen - pos) {\\n this.process(view, 0);\\n pos = 0;\\n }\\n // Pad until full block byte with zeros\\n for (let i = pos; i < blockLen; i++) buffer[i] = 0;\\n // Note: sha512 requires length to be 128bit integer, but length in JS will overflow before that\\n // You need to write around 2 exabytes (u64_max / 8 / (1024**6)) for this to happen.\\n // So we just write lowest 64 bits of that value.\\n setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE);\\n this.process(view, 0);\\n const oview = createView(out);\\n const len = this.outputLen;\\n // NOTE: we do division by 4 later, which should be fused in single op with modulo by JIT\\n if (len % 4) throw new Error('_sha2: outputLen should be aligned to 32bit');\\n const outLen = len / 4;\\n const state = this.get();\\n if (outLen > state.length) throw new Error('_sha2: outputLen bigger than state');\\n for (let i = 0; i < outLen; i++) oview.setUint32(4 * i, state[i], isLE);\\n }\\n digest(): Uint8Array {\\n const { buffer, outputLen } = this;\\n this.digestInto(buffer);\\n const res = buffer.slice(0, outputLen);\\n this.destroy();\\n return res;\\n }\\n _cloneInto(to?: T): T {\\n to ||= new (this.constructor as any)() as T;\\n to.set(...this.get());\\n const { blockLen, buffer, length, finished, destroyed, pos } = this;\\n to.destroyed = destroyed;\\n to.finished = finished;\\n to.length = length;\\n to.pos = pos;\\n if (length % blockLen) to.buffer.set(buffer);\\n return to;\\n }\\n clone(): T {\\n return this._cloneInto();\\n }\\n}\\n\\n/**\\n * Initial SHA-2 state: fractional parts of square roots of first 16 primes 2..53.\\n * Check out `test/misc/sha2-gen-iv.js` for recomputation guide.\\n */\\n\\n/** Initial SHA256 state. Bits 0..32 of frac part of sqrt of primes 2..19 */\\nexport const SHA256_IV: Uint32Array = /* @__PURE__ */ Uint32Array.from([\\n 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,\\n]);\\n\\n/** Initial SHA224 state. Bits 32..64 of frac part of sqrt of primes 23..53 */\\nexport const SHA224_IV: Uint32Array = /* @__PURE__ */ Uint32Array.from([\\n 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4,\\n]);\\n\\n/** Initial SHA384 state. Bits 0..64 of frac part of sqrt of primes 23..53 */\\nexport const SHA384_IV: Uint32Array = /* @__PURE__ */ Uint32Array.from([\\n 0xcbbb9d5d, 0xc1059ed8, 0x629a292a, 0x367cd507, 0x9159015a, 0x3070dd17, 0x152fecd8, 0xf70e5939,\\n 0x67332667, 0xffc00b31, 0x8eb44a87, 0x68581511, 0xdb0c2e0d, 0x64f98fa7, 0x47b5481d, 0xbefa4fa4,\\n]);\\n\\n/** Initial SHA512 state. Bits 0..64 of frac part of sqrt of primes 2..19 */\\nexport const SHA512_IV: Uint32Array = /* @__PURE__ */ Uint32Array.from([\\n 0x6a09e667, 0xf3bcc908, 0xbb67ae85, 0x84caa73b, 0x3c6ef372, 0xfe94f82b, 0xa54ff53a, 0x5f1d36f1,\\n 0x510e527f, 0xade682d1, 0x9b05688c, 0x2b3e6c1f, 0x1f83d9ab, 0xfb41bd6b, 0x5be0cd19, 0x137e2179,\\n]);\\n\",\"/**\\n * SHA2 hash function. A.k.a. sha256, sha384, sha512, sha512_224, sha512_256.\\n * SHA256 is the fastest hash implementable in JS, even faster than Blake3.\\n * Check out [RFC 4634](https://datatracker.ietf.org/doc/html/rfc4634) and\\n * [FIPS 180-4](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf).\\n * @module\\n */\\nimport { Chi, HashMD, Maj, SHA224_IV, SHA256_IV, SHA384_IV, SHA512_IV } from './_md.ts';\\nimport * as u64 from './_u64.ts';\\nimport { type CHash, clean, createHasher, rotr } from './utils.ts';\\n\\n/**\\n * Round constants:\\n * First 32 bits of fractional parts of the cube roots of the first 64 primes 2..311)\\n */\\n// prettier-ignore\\nconst SHA256_K = /* @__PURE__ */ Uint32Array.from([\\n 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,\\n 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,\\n 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,\\n 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,\\n 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,\\n 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,\\n 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,\\n 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2\\n]);\\n\\n/** Reusable temporary buffer. \\\"W\\\" comes straight from spec. */\\nconst SHA256_W = /* @__PURE__ */ new Uint32Array(64);\\nexport class SHA256 extends HashMD {\\n // We cannot use array here since array allows indexing by variable\\n // which means optimizer/compiler cannot use registers.\\n protected A: number = SHA256_IV[0] | 0;\\n protected B: number = SHA256_IV[1] | 0;\\n protected C: number = SHA256_IV[2] | 0;\\n protected D: number = SHA256_IV[3] | 0;\\n protected E: number = SHA256_IV[4] | 0;\\n protected F: number = SHA256_IV[5] | 0;\\n protected G: number = SHA256_IV[6] | 0;\\n protected H: number = SHA256_IV[7] | 0;\\n\\n constructor(outputLen: number = 32) {\\n super(64, outputLen, 8, false);\\n }\\n protected get(): [number, number, number, number, number, number, number, number] {\\n const { A, B, C, D, E, F, G, H } = this;\\n return [A, B, C, D, E, F, G, H];\\n }\\n // prettier-ignore\\n protected set(\\n A: number, B: number, C: number, D: number, E: number, F: number, G: number, H: number\\n ): void {\\n this.A = A | 0;\\n this.B = B | 0;\\n this.C = C | 0;\\n this.D = D | 0;\\n this.E = E | 0;\\n this.F = F | 0;\\n this.G = G | 0;\\n this.H = H | 0;\\n }\\n protected process(view: DataView, offset: number): void {\\n // Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array\\n for (let i = 0; i < 16; i++, offset += 4) SHA256_W[i] = view.getUint32(offset, false);\\n for (let i = 16; i < 64; i++) {\\n const W15 = SHA256_W[i - 15];\\n const W2 = SHA256_W[i - 2];\\n const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ (W15 >>> 3);\\n const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ (W2 >>> 10);\\n SHA256_W[i] = (s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16]) | 0;\\n }\\n // Compression function main loop, 64 rounds\\n let { A, B, C, D, E, F, G, H } = this;\\n for (let i = 0; i < 64; i++) {\\n const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);\\n const T1 = (H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i]) | 0;\\n const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22);\\n const T2 = (sigma0 + Maj(A, B, C)) | 0;\\n H = G;\\n G = F;\\n F = E;\\n E = (D + T1) | 0;\\n D = C;\\n C = B;\\n B = A;\\n A = (T1 + T2) | 0;\\n }\\n // Add the compressed chunk to the current hash value\\n A = (A + this.A) | 0;\\n B = (B + this.B) | 0;\\n C = (C + this.C) | 0;\\n D = (D + this.D) | 0;\\n E = (E + this.E) | 0;\\n F = (F + this.F) | 0;\\n G = (G + this.G) | 0;\\n H = (H + this.H) | 0;\\n this.set(A, B, C, D, E, F, G, H);\\n }\\n protected roundClean(): void {\\n clean(SHA256_W);\\n }\\n destroy(): void {\\n this.set(0, 0, 0, 0, 0, 0, 0, 0);\\n clean(this.buffer);\\n }\\n}\\n\\nexport class SHA224 extends SHA256 {\\n protected A: number = SHA224_IV[0] | 0;\\n protected B: number = SHA224_IV[1] | 0;\\n protected C: number = SHA224_IV[2] | 0;\\n protected D: number = SHA224_IV[3] | 0;\\n protected E: number = SHA224_IV[4] | 0;\\n protected F: number = SHA224_IV[5] | 0;\\n protected G: number = SHA224_IV[6] | 0;\\n protected H: number = SHA224_IV[7] | 0;\\n constructor() {\\n super(28);\\n }\\n}\\n\\n// SHA2-512 is slower than sha256 in js because u64 operations are slow.\\n\\n// Round contants\\n// First 32 bits of the fractional parts of the cube roots of the first 80 primes 2..409\\n// prettier-ignore\\nconst K512 = /* @__PURE__ */ (() => u64.split([\\n '0x428a2f98d728ae22', '0x7137449123ef65cd', '0xb5c0fbcfec4d3b2f', '0xe9b5dba58189dbbc',\\n '0x3956c25bf348b538', '0x59f111f1b605d019', '0x923f82a4af194f9b', '0xab1c5ed5da6d8118',\\n '0xd807aa98a3030242', '0x12835b0145706fbe', '0x243185be4ee4b28c', '0x550c7dc3d5ffb4e2',\\n '0x72be5d74f27b896f', '0x80deb1fe3b1696b1', '0x9bdc06a725c71235', '0xc19bf174cf692694',\\n '0xe49b69c19ef14ad2', '0xefbe4786384f25e3', '0x0fc19dc68b8cd5b5', '0x240ca1cc77ac9c65',\\n '0x2de92c6f592b0275', '0x4a7484aa6ea6e483', '0x5cb0a9dcbd41fbd4', '0x76f988da831153b5',\\n '0x983e5152ee66dfab', '0xa831c66d2db43210', '0xb00327c898fb213f', '0xbf597fc7beef0ee4',\\n '0xc6e00bf33da88fc2', '0xd5a79147930aa725', '0x06ca6351e003826f', '0x142929670a0e6e70',\\n '0x27b70a8546d22ffc', '0x2e1b21385c26c926', '0x4d2c6dfc5ac42aed', '0x53380d139d95b3df',\\n '0x650a73548baf63de', '0x766a0abb3c77b2a8', '0x81c2c92e47edaee6', '0x92722c851482353b',\\n '0xa2bfe8a14cf10364', '0xa81a664bbc423001', '0xc24b8b70d0f89791', '0xc76c51a30654be30',\\n '0xd192e819d6ef5218', '0xd69906245565a910', '0xf40e35855771202a', '0x106aa07032bbd1b8',\\n '0x19a4c116b8d2d0c8', '0x1e376c085141ab53', '0x2748774cdf8eeb99', '0x34b0bcb5e19b48a8',\\n '0x391c0cb3c5c95a63', '0x4ed8aa4ae3418acb', '0x5b9cca4f7763e373', '0x682e6ff3d6b2b8a3',\\n '0x748f82ee5defb2fc', '0x78a5636f43172f60', '0x84c87814a1f0ab72', '0x8cc702081a6439ec',\\n '0x90befffa23631e28', '0xa4506cebde82bde9', '0xbef9a3f7b2c67915', '0xc67178f2e372532b',\\n '0xca273eceea26619c', '0xd186b8c721c0c207', '0xeada7dd6cde0eb1e', '0xf57d4f7fee6ed178',\\n '0x06f067aa72176fba', '0x0a637dc5a2c898a6', '0x113f9804bef90dae', '0x1b710b35131c471b',\\n '0x28db77f523047d84', '0x32caab7b40c72493', '0x3c9ebe0a15c9bebc', '0x431d67c49c100d4c',\\n '0x4cc5d4becb3e42b6', '0x597f299cfc657e2a', '0x5fcb6fab3ad6faec', '0x6c44198c4a475817'\\n].map(n => BigInt(n))))();\\nconst SHA512_Kh = /* @__PURE__ */ (() => K512[0])();\\nconst SHA512_Kl = /* @__PURE__ */ (() => K512[1])();\\n\\n// Reusable temporary buffers\\nconst SHA512_W_H = /* @__PURE__ */ new Uint32Array(80);\\nconst SHA512_W_L = /* @__PURE__ */ new Uint32Array(80);\\n\\nexport class SHA512 extends HashMD {\\n // We cannot use array here since array allows indexing by variable\\n // which means optimizer/compiler cannot use registers.\\n // h -- high 32 bits, l -- low 32 bits\\n protected Ah: number = SHA512_IV[0] | 0;\\n protected Al: number = SHA512_IV[1] | 0;\\n protected Bh: number = SHA512_IV[2] | 0;\\n protected Bl: number = SHA512_IV[3] | 0;\\n protected Ch: number = SHA512_IV[4] | 0;\\n protected Cl: number = SHA512_IV[5] | 0;\\n protected Dh: number = SHA512_IV[6] | 0;\\n protected Dl: number = SHA512_IV[7] | 0;\\n protected Eh: number = SHA512_IV[8] | 0;\\n protected El: number = SHA512_IV[9] | 0;\\n protected Fh: number = SHA512_IV[10] | 0;\\n protected Fl: number = SHA512_IV[11] | 0;\\n protected Gh: number = SHA512_IV[12] | 0;\\n protected Gl: number = SHA512_IV[13] | 0;\\n protected Hh: number = SHA512_IV[14] | 0;\\n protected Hl: number = SHA512_IV[15] | 0;\\n\\n constructor(outputLen: number = 64) {\\n super(128, outputLen, 16, false);\\n }\\n // prettier-ignore\\n protected get(): [\\n number, number, number, number, number, number, number, number,\\n number, number, number, number, number, number, number, number\\n ] {\\n const { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this;\\n return [Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl];\\n }\\n // prettier-ignore\\n protected set(\\n Ah: number, Al: number, Bh: number, Bl: number, Ch: number, Cl: number, Dh: number, Dl: number,\\n Eh: number, El: number, Fh: number, Fl: number, Gh: number, Gl: number, Hh: number, Hl: number\\n ): void {\\n this.Ah = Ah | 0;\\n this.Al = Al | 0;\\n this.Bh = Bh | 0;\\n this.Bl = Bl | 0;\\n this.Ch = Ch | 0;\\n this.Cl = Cl | 0;\\n this.Dh = Dh | 0;\\n this.Dl = Dl | 0;\\n this.Eh = Eh | 0;\\n this.El = El | 0;\\n this.Fh = Fh | 0;\\n this.Fl = Fl | 0;\\n this.Gh = Gh | 0;\\n this.Gl = Gl | 0;\\n this.Hh = Hh | 0;\\n this.Hl = Hl | 0;\\n }\\n protected process(view: DataView, offset: number): void {\\n // Extend the first 16 words into the remaining 64 words w[16..79] of the message schedule array\\n for (let i = 0; i < 16; i++, offset += 4) {\\n SHA512_W_H[i] = view.getUint32(offset);\\n SHA512_W_L[i] = view.getUint32((offset += 4));\\n }\\n for (let i = 16; i < 80; i++) {\\n // s0 := (w[i-15] rightrotate 1) xor (w[i-15] rightrotate 8) xor (w[i-15] rightshift 7)\\n const W15h = SHA512_W_H[i - 15] | 0;\\n const W15l = SHA512_W_L[i - 15] | 0;\\n const s0h = u64.rotrSH(W15h, W15l, 1) ^ u64.rotrSH(W15h, W15l, 8) ^ u64.shrSH(W15h, W15l, 7);\\n const s0l = u64.rotrSL(W15h, W15l, 1) ^ u64.rotrSL(W15h, W15l, 8) ^ u64.shrSL(W15h, W15l, 7);\\n // s1 := (w[i-2] rightrotate 19) xor (w[i-2] rightrotate 61) xor (w[i-2] rightshift 6)\\n const W2h = SHA512_W_H[i - 2] | 0;\\n const W2l = SHA512_W_L[i - 2] | 0;\\n const s1h = u64.rotrSH(W2h, W2l, 19) ^ u64.rotrBH(W2h, W2l, 61) ^ u64.shrSH(W2h, W2l, 6);\\n const s1l = u64.rotrSL(W2h, W2l, 19) ^ u64.rotrBL(W2h, W2l, 61) ^ u64.shrSL(W2h, W2l, 6);\\n // SHA256_W[i] = s0 + s1 + SHA256_W[i - 7] + SHA256_W[i - 16];\\n const SUMl = u64.add4L(s0l, s1l, SHA512_W_L[i - 7], SHA512_W_L[i - 16]);\\n const SUMh = u64.add4H(SUMl, s0h, s1h, SHA512_W_H[i - 7], SHA512_W_H[i - 16]);\\n SHA512_W_H[i] = SUMh | 0;\\n SHA512_W_L[i] = SUMl | 0;\\n }\\n let { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this;\\n // Compression function main loop, 80 rounds\\n for (let i = 0; i < 80; i++) {\\n // S1 := (e rightrotate 14) xor (e rightrotate 18) xor (e rightrotate 41)\\n const sigma1h = u64.rotrSH(Eh, El, 14) ^ u64.rotrSH(Eh, El, 18) ^ u64.rotrBH(Eh, El, 41);\\n const sigma1l = u64.rotrSL(Eh, El, 14) ^ u64.rotrSL(Eh, El, 18) ^ u64.rotrBL(Eh, El, 41);\\n //const T1 = (H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i]) | 0;\\n const CHIh = (Eh & Fh) ^ (~Eh & Gh);\\n const CHIl = (El & Fl) ^ (~El & Gl);\\n // T1 = H + sigma1 + Chi(E, F, G) + SHA512_K[i] + SHA512_W[i]\\n // prettier-ignore\\n const T1ll = u64.add5L(Hl, sigma1l, CHIl, SHA512_Kl[i], SHA512_W_L[i]);\\n const T1h = u64.add5H(T1ll, Hh, sigma1h, CHIh, SHA512_Kh[i], SHA512_W_H[i]);\\n const T1l = T1ll | 0;\\n // S0 := (a rightrotate 28) xor (a rightrotate 34) xor (a rightrotate 39)\\n const sigma0h = u64.rotrSH(Ah, Al, 28) ^ u64.rotrBH(Ah, Al, 34) ^ u64.rotrBH(Ah, Al, 39);\\n const sigma0l = u64.rotrSL(Ah, Al, 28) ^ u64.rotrBL(Ah, Al, 34) ^ u64.rotrBL(Ah, Al, 39);\\n const MAJh = (Ah & Bh) ^ (Ah & Ch) ^ (Bh & Ch);\\n const MAJl = (Al & Bl) ^ (Al & Cl) ^ (Bl & Cl);\\n Hh = Gh | 0;\\n Hl = Gl | 0;\\n Gh = Fh | 0;\\n Gl = Fl | 0;\\n Fh = Eh | 0;\\n Fl = El | 0;\\n ({ h: Eh, l: El } = u64.add(Dh | 0, Dl | 0, T1h | 0, T1l | 0));\\n Dh = Ch | 0;\\n Dl = Cl | 0;\\n Ch = Bh | 0;\\n Cl = Bl | 0;\\n Bh = Ah | 0;\\n Bl = Al | 0;\\n const All = u64.add3L(T1l, sigma0l, MAJl);\\n Ah = u64.add3H(All, T1h, sigma0h, MAJh);\\n Al = All | 0;\\n }\\n // Add the compressed chunk to the current hash value\\n ({ h: Ah, l: Al } = u64.add(this.Ah | 0, this.Al | 0, Ah | 0, Al | 0));\\n ({ h: Bh, l: Bl } = u64.add(this.Bh | 0, this.Bl | 0, Bh | 0, Bl | 0));\\n ({ h: Ch, l: Cl } = u64.add(this.Ch | 0, this.Cl | 0, Ch | 0, Cl | 0));\\n ({ h: Dh, l: Dl } = u64.add(this.Dh | 0, this.Dl | 0, Dh | 0, Dl | 0));\\n ({ h: Eh, l: El } = u64.add(this.Eh | 0, this.El | 0, Eh | 0, El | 0));\\n ({ h: Fh, l: Fl } = u64.add(this.Fh | 0, this.Fl | 0, Fh | 0, Fl | 0));\\n ({ h: Gh, l: Gl } = u64.add(this.Gh | 0, this.Gl | 0, Gh | 0, Gl | 0));\\n ({ h: Hh, l: Hl } = u64.add(this.Hh | 0, this.Hl | 0, Hh | 0, Hl | 0));\\n this.set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl);\\n }\\n protected roundClean(): void {\\n clean(SHA512_W_H, SHA512_W_L);\\n }\\n destroy(): void {\\n clean(this.buffer);\\n this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\\n }\\n}\\n\\nexport class SHA384 extends SHA512 {\\n protected Ah: number = SHA384_IV[0] | 0;\\n protected Al: number = SHA384_IV[1] | 0;\\n protected Bh: number = SHA384_IV[2] | 0;\\n protected Bl: number = SHA384_IV[3] | 0;\\n protected Ch: number = SHA384_IV[4] | 0;\\n protected Cl: number = SHA384_IV[5] | 0;\\n protected Dh: number = SHA384_IV[6] | 0;\\n protected Dl: number = SHA384_IV[7] | 0;\\n protected Eh: number = SHA384_IV[8] | 0;\\n protected El: number = SHA384_IV[9] | 0;\\n protected Fh: number = SHA384_IV[10] | 0;\\n protected Fl: number = SHA384_IV[11] | 0;\\n protected Gh: number = SHA384_IV[12] | 0;\\n protected Gl: number = SHA384_IV[13] | 0;\\n protected Hh: number = SHA384_IV[14] | 0;\\n protected Hl: number = SHA384_IV[15] | 0;\\n\\n constructor() {\\n super(48);\\n }\\n}\\n\\n/**\\n * Truncated SHA512/256 and SHA512/224.\\n * SHA512_IV is XORed with 0xa5a5a5a5a5a5a5a5, then used as \\\"intermediary\\\" IV of SHA512/t.\\n * Then t hashes string to produce result IV.\\n * See `test/misc/sha2-gen-iv.js`.\\n */\\n\\n/** SHA512/224 IV */\\nconst T224_IV = /* @__PURE__ */ Uint32Array.from([\\n 0x8c3d37c8, 0x19544da2, 0x73e19966, 0x89dcd4d6, 0x1dfab7ae, 0x32ff9c82, 0x679dd514, 0x582f9fcf,\\n 0x0f6d2b69, 0x7bd44da8, 0x77e36f73, 0x04c48942, 0x3f9d85a8, 0x6a1d36c8, 0x1112e6ad, 0x91d692a1,\\n]);\\n\\n/** SHA512/256 IV */\\nconst T256_IV = /* @__PURE__ */ Uint32Array.from([\\n 0x22312194, 0xfc2bf72c, 0x9f555fa3, 0xc84c64c2, 0x2393b86b, 0x6f53b151, 0x96387719, 0x5940eabd,\\n 0x96283ee2, 0xa88effe3, 0xbe5e1e25, 0x53863992, 0x2b0199fc, 0x2c85b8aa, 0x0eb72ddc, 0x81c52ca2,\\n]);\\n\\nexport class SHA512_224 extends SHA512 {\\n protected Ah: number = T224_IV[0] | 0;\\n protected Al: number = T224_IV[1] | 0;\\n protected Bh: number = T224_IV[2] | 0;\\n protected Bl: number = T224_IV[3] | 0;\\n protected Ch: number = T224_IV[4] | 0;\\n protected Cl: number = T224_IV[5] | 0;\\n protected Dh: number = T224_IV[6] | 0;\\n protected Dl: number = T224_IV[7] | 0;\\n protected Eh: number = T224_IV[8] | 0;\\n protected El: number = T224_IV[9] | 0;\\n protected Fh: number = T224_IV[10] | 0;\\n protected Fl: number = T224_IV[11] | 0;\\n protected Gh: number = T224_IV[12] | 0;\\n protected Gl: number = T224_IV[13] | 0;\\n protected Hh: number = T224_IV[14] | 0;\\n protected Hl: number = T224_IV[15] | 0;\\n\\n constructor() {\\n super(28);\\n }\\n}\\n\\nexport class SHA512_256 extends SHA512 {\\n protected Ah: number = T256_IV[0] | 0;\\n protected Al: number = T256_IV[1] | 0;\\n protected Bh: number = T256_IV[2] | 0;\\n protected Bl: number = T256_IV[3] | 0;\\n protected Ch: number = T256_IV[4] | 0;\\n protected Cl: number = T256_IV[5] | 0;\\n protected Dh: number = T256_IV[6] | 0;\\n protected Dl: number = T256_IV[7] | 0;\\n protected Eh: number = T256_IV[8] | 0;\\n protected El: number = T256_IV[9] | 0;\\n protected Fh: number = T256_IV[10] | 0;\\n protected Fl: number = T256_IV[11] | 0;\\n protected Gh: number = T256_IV[12] | 0;\\n protected Gl: number = T256_IV[13] | 0;\\n protected Hh: number = T256_IV[14] | 0;\\n protected Hl: number = T256_IV[15] | 0;\\n\\n constructor() {\\n super(32);\\n }\\n}\\n\\n/**\\n * SHA2-256 hash function from RFC 4634.\\n *\\n * It is the fastest JS hash, even faster than Blake3.\\n * To break sha256 using birthday attack, attackers need to try 2^128 hashes.\\n * BTC network is doing 2^70 hashes/sec (2^95 hashes/year) as per 2025.\\n */\\nexport const sha256: CHash = /* @__PURE__ */ createHasher(() => new SHA256());\\n/** SHA2-224 hash function from RFC 4634 */\\nexport const sha224: CHash = /* @__PURE__ */ createHasher(() => new SHA224());\\n\\n/** SHA2-512 hash function from RFC 4634. */\\nexport const sha512: CHash = /* @__PURE__ */ createHasher(() => new SHA512());\\n/** SHA2-384 hash function from RFC 4634. */\\nexport const sha384: CHash = /* @__PURE__ */ createHasher(() => new SHA384());\\n\\n/**\\n * SHA2-512/256 \\\"truncated\\\" hash function, with improved resistance to length extension attacks.\\n * See the paper on [truncated SHA512](https://eprint.iacr.org/2010/548.pdf).\\n */\\nexport const sha512_256: CHash = /* @__PURE__ */ createHasher(() => new SHA512_256());\\n/**\\n * SHA2-512/224 \\\"truncated\\\" hash function, with improved resistance to length extension attacks.\\n * See the paper on [truncated SHA512](https://eprint.iacr.org/2010/548.pdf).\\n */\\nexport const sha512_224: CHash = /* @__PURE__ */ createHasher(() => new SHA512_224());\\n\",\"/**\\n * SHA2-256 a.k.a. sha256. In JS, it is the fastest hash, even faster than Blake3.\\n *\\n * To break sha256 using birthday attack, attackers need to try 2^128 hashes.\\n * BTC network is doing 2^70 hashes/sec (2^95 hashes/year) as per 2025.\\n *\\n * Check out [FIPS 180-4](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf).\\n * @module\\n * @deprecated\\n */\\nimport {\\n SHA224 as SHA224n,\\n sha224 as sha224n,\\n SHA256 as SHA256n,\\n sha256 as sha256n,\\n} from './sha2.ts';\\n/** @deprecated Use import from `noble/hashes/sha2` module */\\nexport const SHA256: typeof SHA256n = SHA256n;\\n/** @deprecated Use import from `noble/hashes/sha2` module */\\nexport const sha256: typeof sha256n = sha256n;\\n/** @deprecated Use import from `noble/hashes/sha2` module */\\nexport const SHA224: typeof SHA224n = SHA224n;\\n/** @deprecated Use import from `noble/hashes/sha2` module */\\nexport const sha224: typeof sha224n = sha224n;\\n\",\"\\nexport default class TinyQueue {\\n constructor(data = [], compare = (a, b) => (a < b ? -1 : a > b ? 1 : 0)) {\\n this.data = data;\\n this.length = this.data.length;\\n this.compare = compare;\\n\\n if (this.length > 0) {\\n for (let i = (this.length >> 1) - 1; i >= 0; i--) this._down(i);\\n }\\n }\\n\\n push(item) {\\n this.data.push(item);\\n this._up(this.length++);\\n }\\n\\n pop() {\\n if (this.length === 0) return undefined;\\n\\n const top = this.data[0];\\n const bottom = this.data.pop();\\n\\n if (--this.length > 0) {\\n this.data[0] = bottom;\\n this._down(0);\\n }\\n\\n return top;\\n }\\n\\n peek() {\\n return this.data[0];\\n }\\n\\n _up(pos) {\\n const {data, compare} = this;\\n const item = data[pos];\\n\\n while (pos > 0) {\\n const parent = (pos - 1) >> 1;\\n const current = data[parent];\\n if (compare(item, current) >= 0) break;\\n data[pos] = current;\\n pos = parent;\\n }\\n\\n data[pos] = item;\\n }\\n\\n _down(pos) {\\n const {data, compare} = this;\\n const halfLength = this.length >> 1;\\n const item = data[pos];\\n\\n while (pos < halfLength) {\\n let bestChild = (pos << 1) + 1; // initially it is the left child\\n const right = bestChild + 1;\\n\\n if (right < this.length && compare(data[right], data[bestChild]) < 0) {\\n bestChild = right;\\n }\\n if (compare(data[bestChild], item) >= 0) break;\\n\\n data[pos] = data[bestChild];\\n pos = bestChild;\\n }\\n\\n data[pos] = item;\\n }\\n}\\n\"],\"version\":3}", + "originMeta": { + "originalPath": "node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/_md.js", + "packageName": "@noble/hashes", + "packageVersion": "1.8.0", + "integrity": "483aad47a5ae3669a320d313a6ce1be9be705b5c52775cba1b4f45d1fada0562" + } + } + ], + "builderVersion": "deterministic-builder-v1", + "dependencyIntegrity": "483aad47a5ae3669a320d313a6ce1be9be705b5c52775cba1b4f45d1fada0562", + "diagnosticsMeta": { + "entryPath": "/workspace/apps/ecosystem-certifier/fixtures/flagship/knowledge-pack-entry.ts", + "modulePaths": [ + "./knowledge-pack-entry.js" + ] + }, + "graphHash": "c1aa035e83f709d6345f4b3c0208d5217d7deac086a3d5f98b296035e3145ec8" + } + } + }, + "manifest": { + "abi_id": "Host.v2", + "abi_version": 2, + "functions": [ + { + "fn_id": 1, + "js_path": [ + "document", + "get" + ], + "effect": "READ", + "arity": 1, + "arg_schema": [ + { + "type": "string" + } + ], + "return_schema": { + "type": "dv" + }, + "gas": { + "schedule_id": "doc-read-v1", + "base": 20, + "k_arg_bytes": 1, + "k_ret_bytes": 1, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 4096, + "max_response_bytes": 262144, + "max_units": 1000, + "arg_utf8_max": [ + 2048 + ] + }, + "error_codes": [ + { + "code": "INVALID_PATH", + "tag": "host/invalid_path" + }, + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + }, + { + "code": "NOT_FOUND", + "tag": "host/not_found" + } + ] + }, + { + "fn_id": 2, + "js_path": [ + "document", + "getCanonical" + ], + "effect": "READ", + "arity": 1, + "arg_schema": [ + { + "type": "string" + } + ], + "return_schema": { + "type": "dv" + }, + "gas": { + "schedule_id": "doc-read-v1", + "base": 20, + "k_arg_bytes": 1, + "k_ret_bytes": 1, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 4096, + "max_response_bytes": 262144, + "max_units": 1000, + "arg_utf8_max": [ + 2048 + ] + }, + "error_codes": [ + { + "code": "INVALID_PATH", + "tag": "host/invalid_path" + }, + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + }, + { + "code": "NOT_FOUND", + "tag": "host/not_found" + } + ] + }, + { + "fn_id": 3, + "js_path": [ + "emit" + ], + "effect": "EMIT", + "arity": 1, + "arg_schema": [ + { + "type": "dv" + } + ], + "return_schema": { + "type": "null" + }, + "gas": { + "schedule_id": "emit-v1", + "base": 5, + "k_arg_bytes": 1, + "k_ret_bytes": 0, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 32768, + "max_response_bytes": 64, + "max_units": 1024 + }, + "error_codes": [ + { + "code": "LIMIT_EXCEEDED", + "tag": "host/limit" + } + ] + } + ] + } + } + ] +} diff --git a/apps/bluequickjs-playground/public/generated/playground-oog-boundaries.json b/apps/bluequickjs-playground/public/generated/playground-oog-boundaries.json new file mode 100644 index 0000000..a619b43 --- /dev/null +++ b/apps/bluequickjs-playground/public/generated/playground-oog-boundaries.json @@ -0,0 +1,109 @@ +{ + "generatedAt": "current-worktree", + "metadata": { + "engineBuildHash": "f91091cb7feb788df340305a877a9cadb0c6f4d13aea8a7da4040b6367d178ea", + "gasVersion": 8 + }, + "boundaries": { + "example-basic-script": { + "firstSuccessGas": "74", + "lastFailureGas": "73", + "successGasUsed": "74", + "successGasRemaining": "0", + "failureGasUsed": "73", + "failureGasRemaining": "0", + "failureCode": "OOG", + "failureTag": "vm/out_of_gas" + }, + "example-module-pack": { + "firstSuccessGas": "145", + "lastFailureGas": "144", + "successGasUsed": "145", + "successGasRemaining": "0", + "failureGasUsed": "144", + "failureGasRemaining": "0", + "failureCode": "MODULE_EXPORT_MISSING", + "failureTag": "vm/module_pack" + }, + "example-library-reuse": { + "firstSuccessGas": "2070503", + "lastFailureGas": "2070502", + "successGasUsed": "2070503", + "successGasRemaining": "0", + "failureGasUsed": "2070502", + "failureGasRemaining": "0", + "failureCode": "MODULE_EXPORT_MISSING", + "failureTag": "vm/module_pack" + }, + "example-promises-async": { + "firstSuccessGas": "128", + "lastFailureGas": "127", + "successGasUsed": "128", + "successGasRemaining": "0", + "failureGasUsed": "127", + "failureGasRemaining": "0", + "failureCode": "OOG", + "failureTag": "vm/out_of_gas" + }, + "example-promises-library-host": { + "firstSuccessGas": "290", + "lastFailureGas": "289", + "successGasUsed": "290", + "successGasRemaining": "0", + "failureGasUsed": "289", + "failureGasRemaining": "0", + "failureCode": "MODULE_EVALUATION_ERROR", + "failureTag": "vm/module_pack" + }, + "example-binary-host-v2": { + "firstSuccessGas": "253", + "lastFailureGas": "252", + "successGasUsed": "253", + "successGasRemaining": "0", + "failureGasUsed": "252", + "failureGasRemaining": "0", + "failureCode": "OOG", + "failureTag": "vm/out_of_gas" + }, + "example-console-shim": { + "firstSuccessGas": "139", + "lastFailureGas": "138", + "successGasUsed": "139", + "successGasRemaining": "0", + "failureGasUsed": "138", + "failureGasRemaining": "0", + "failureCode": "OOG", + "failureTag": "vm/out_of_gas" + }, + "example-stable-sort": { + "firstSuccessGas": "1020", + "lastFailureGas": "1019", + "successGasUsed": "1020", + "successGasRemaining": "0", + "failureGasUsed": "1019", + "failureGasRemaining": "0", + "failureCode": "OOG", + "failureTag": "vm/out_of_gas" + }, + "example-kitchen-sink": { + "firstSuccessGas": "1390", + "lastFailureGas": "1389", + "successGasUsed": "1390", + "successGasRemaining": "0", + "failureGasUsed": "1389", + "failureGasRemaining": "0", + "failureCode": "MODULE_EVALUATION_ERROR", + "failureTag": "vm/module_pack" + }, + "example-max-gas-policy": { + "firstSuccessGas": "170099", + "lastFailureGas": "170098", + "successGasUsed": "170099", + "successGasRemaining": "0", + "failureGasUsed": "170098", + "failureGasRemaining": "0", + "failureCode": "OOG", + "failureTag": "vm/out_of_gas" + } + } +} diff --git a/apps/bluequickjs-playground/public/generated/playground-red-fixtures.json b/apps/bluequickjs-playground/public/generated/playground-red-fixtures.json new file mode 100644 index 0000000..1d16a3a --- /dev/null +++ b/apps/bluequickjs-playground/public/generated/playground-red-fixtures.json @@ -0,0 +1,170 @@ +{ + "generatedAt": "current-worktree", + "metadata": { + "engineBuildHash": "f91091cb7feb788df340305a877a9cadb0c6f4d13aea8a7da4040b6367d178ea", + "gasVersion": 8 + }, + "fixtures": [ + { + "id": "red-diff-timers", + "title": "diff package timer references are deterministically rejected", + "kind": "negative", + "executionProfile": "compat-general-v1", + "failureStage": "builder_reject", + "errorCode": null, + "errorTag": null, + "certified": true, + "docsLinks": [ + { + "label": "Workload certification", + "href": "/docs/workload-certification.md" + }, + { + "label": "Compatibility report", + "href": "/docs/ecosystem-compatibility-report.md" + }, + { + "label": "Unsupported features and why", + "href": "/docs/unsupported-features-and-why.md" + } + ], + "diagnostics": [ + { + "filePath": "./diff-entry.js", + "ruleId": "timers_disabled", + "message": "forbidden API used: setTimeout" + } + ], + "runtimeArtifact": null, + "reportSource": "ecosystem-certifier:red-diff-timers" + }, + { + "id": "red-dynamic-import", + "title": "dynamic import must be rejected at build stage", + "kind": "negative", + "executionProfile": "compat-general-v1", + "failureStage": "builder_reject", + "errorCode": null, + "errorTag": null, + "certified": true, + "docsLinks": [ + { + "label": "Workload certification", + "href": "/docs/workload-certification.md" + }, + { + "label": "Compatibility report", + "href": "/docs/ecosystem-compatibility-report.md" + }, + { + "label": "Unsupported features and why", + "href": "/docs/unsupported-features-and-why.md" + } + ], + "diagnostics": [ + { + "filePath": "./dynamic-import-entry.js", + "ruleId": "dynamic_import_disabled", + "message": "dynamic import() is disabled in deterministic mode" + } + ], + "runtimeArtifact": null, + "reportSource": "ecosystem-certifier:red-dynamic-import" + }, + { + "id": "red-proxy", + "title": "Proxy usage must be rejected at build stage", + "kind": "negative", + "executionProfile": "compat-general-v1", + "failureStage": "builder_reject", + "errorCode": null, + "errorTag": null, + "certified": true, + "docsLinks": [ + { + "label": "Workload certification", + "href": "/docs/workload-certification.md" + }, + { + "label": "Compatibility report", + "href": "/docs/ecosystem-compatibility-report.md" + }, + { + "label": "Unsupported features and why", + "href": "/docs/unsupported-features-and-why.md" + } + ], + "diagnostics": [ + { + "filePath": "./proxy-entry.js", + "ruleId": "proxy_disabled", + "message": "forbidden API used: Proxy" + } + ], + "runtimeArtifact": null, + "reportSource": "ecosystem-certifier:red-proxy" + }, + { + "id": "red-function-constructor", + "title": "Function constructor must fail deterministically in module-pack flow", + "kind": "negative", + "executionProfile": "compat-general-v1", + "failureStage": "artifact_validation", + "errorCode": "MODULE_EXPORT_MISSING", + "errorTag": "vm/module_pack", + "certified": true, + "docsLinks": [ + { + "label": "Workload certification", + "href": "/docs/workload-certification.md" + }, + { + "label": "Compatibility report", + "href": "/docs/ecosystem-compatibility-report.md" + }, + { + "label": "Unsupported features and why", + "href": "/docs/unsupported-features-and-why.md" + } + ], + "diagnostics": [], + "runtimeArtifact": { + "version": 2, + "abiId": "Host.v1", + "abiVersion": 1, + "abiManifestHash": "e23b0b2ee169900bbde7aff78e6ce20fead1715c60f8a8e3106d9959450a3d34", + "engineBuildHash": "f91091cb7feb788df340305a877a9cadb0c6f4d13aea8a7da4040b6367d178ea", + "gasVersion": 8, + "executionProfile": "compat-general-v1", + "sourceKind": "module-pack", + "source": { + "modulePack": { + "version": 1, + "entrySpecifier": "./function-constructor-entry.js", + "entryExport": "default", + "modules": [ + { + "specifier": "./function-constructor-entry.js", + "source": "// apps/ecosystem-certifier/fixtures/negative/function-constructor-entry.ts\nvar make = new Function(\"return 41 + 1;\");\nvar function_constructor_entry_default = make();\nexport {\n function_constructor_entry_default as default\n};\n", + "sourceMap": "{\"mappings\":\";AAAA,IAAM,OAAO,IAAI,SAAS,gBAAgB;AAE1C,IAAO,qCAAQ,KAAK;\",\"names\":[],\"sources\":[\"../apps/ecosystem-certifier/fixtures/negative/function-constructor-entry.ts\"],\"sourcesContent\":[\"const make = new Function('return 41 + 1;');\\n\\nexport default make();\\n\"],\"version\":3}", + "originMeta": { + "originalPath": "apps/ecosystem-certifier/fixtures/negative/function-constructor-entry.ts" + } + } + ], + "builderVersion": "deterministic-builder-v1", + "dependencyIntegrity": "483aad47a5ae3669a320d313a6ce1be9be705b5c52775cba1b4f45d1fada0562", + "diagnosticsMeta": { + "entryPath": "/workspace/apps/ecosystem-certifier/fixtures/negative/function-constructor-entry.ts", + "modulePaths": [ + "./function-constructor-entry.js" + ] + }, + "graphHash": "540034aad543c614a540b986b8c391e620261b8046c00edede6484f37461f21b" + } + } + }, + "reportSource": "ecosystem-certifier:red-function-constructor" + } + ] +} diff --git a/apps/bluequickjs-playground/scripts/dev.sh b/apps/bluequickjs-playground/scripts/dev.sh new file mode 100644 index 0000000..21a2890 --- /dev/null +++ b/apps/bluequickjs-playground/scripts/dev.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd -- "${SCRIPT_DIR}/../../.." && pwd)" + +cd "${REPO_ROOT}" + +if [ ! -f "tools/emsdk/emsdk_env.sh" ]; then + echo "Missing tools/emsdk/emsdk_env.sh" + echo "Run: bash tools/scripts/setup-emsdk.sh" + exit 1 +fi + +bash tools/scripts/prepare-quickjs-source.sh +source tools/emsdk/emsdk_env.sh +pnpm nx build bluequickjs-playground +node apps/bluequickjs-playground/scripts/generate-playground-data.mjs +exec pnpm vite --host --port 4325 --config apps/bluequickjs-playground/vite.config.mts diff --git a/apps/bluequickjs-playground/scripts/generate-playground-data.mjs b/apps/bluequickjs-playground/scripts/generate-playground-data.mjs new file mode 100644 index 0000000..5c9d1c8 --- /dev/null +++ b/apps/bluequickjs-playground/scripts/generate-playground-data.mjs @@ -0,0 +1,987 @@ +#!/usr/bin/env node + +import { createHash } from 'node:crypto'; +import { spawnSync } from 'node:child_process'; +import { existsSync } from 'node:fs'; +import { mkdir, readFile, writeFile } from 'node:fs/promises'; +import path from 'node:path'; +import process from 'node:process'; +import { fileURLToPath } from 'node:url'; +import jiti from 'jiti'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const repoRoot = path.resolve(__dirname, '..', '..', '..'); +const outDir = path.resolve( + repoRoot, + 'apps/bluequickjs-playground/public/generated', +); +const args = parseArgs(process.argv.slice(2)); + +await ensurePlaygroundBuildArtifacts(); + +const require = jiti(import.meta.url, { interopDefault: true }); + +const { + HOST_V1_HASH, + HOST_V1_MANIFEST, + HOST_V2_HASH, + HOST_V2_MANIFEST, +} = require('../../../libs/abi-manifest/src/index.ts'); +const { + buildDeterministicModulePack, + DeterministicBuilderError, +} = require('../../../libs/deterministic-builder/src/index.ts'); +const { encodeDv2 } = require('../../../libs/dv/src/index.ts'); +const { evaluate } = require('../../../libs/quickjs-runtime/src/index.ts'); +const { + loadQuickjsWasmBinary, + loadQuickjsWasmMetadata, +} = require('../../../libs/quickjs-wasm/src/index.ts'); +const { + EXAMPLE_CORPUS, + DETERMINISM_INPUT, + createDeterminismHost, + serializeHostTape, +} = require('../../../libs/test-harness/src/index.ts'); +const { + CERTIFIER_FIXTURES, + manifestForFixture, +} = require('../../../apps/ecosystem-certifier/src/shared/fixtures.ts'); +const { + createCertificationHost, +} = require('../../../apps/ecosystem-certifier/src/shared/host.ts'); + +const CERTIFICATION_INPUT = { + event: { type: 'ecosystem-certifier' }, + eventCanonical: { type: 'ecosystem-certifier' }, + steps: [], + currentContract: { id: 'ecosystem-certifier' }, + currentContractCanonical: { id: { value: 'ecosystem-certifier' } }, +}; + +const HOST_PRESET_SUMMARIES = { + determinism: { + label: 'Determinism fixture host', + description: + 'Provides stable Host.v1/Host.v2 document responses plus deterministic emit tape capture.', + documents: [ + 'path/to/doc', + 'path/to/canonical', + 'path/to/first', + 'path/to/second', + 'path/to/third', + 'bytes/payload', + ], + }, + certification: { + label: 'Certification host', + description: + 'Provides the ecosystem-certifier text and binary documents used for workload certification.', + documents: [ + 'pack/metadata.json', + 'pack/metadata.yaml', + 'docs/a.md', + 'docs/b.md', + 'docs/c.md', + 'docs/d.md', + 'bytes/payload', + 'bytes/flagship-extra', + 'pack/attachment.deflated', + ], + }, +}; + +const SELECTED_GREEN_FIXTURE_IDS = [ + 'green-semver', + 'green-base64', + 'green-markdown-it', + 'green-noble-sha', +]; + +const SELECTED_RED_FIXTURE_IDS = [ + 'red-diff-timers', + 'red-dynamic-import', + 'red-proxy', + 'red-function-constructor', +]; + +const metadata = await loadQuickjsWasmMetadata(); +const wasmBinary = await loadQuickjsWasmBinary('wasm32', 'release', metadata); +const engineBuildHash = + metadata.variants?.wasm32?.release?.engineBuildHash ?? + metadata.engineBuildHash ?? + null; +const gasVersion = metadata.gasVersion ?? null; +const generatedAt = 'current-worktree'; + +const runnableExamples = await buildExampleEntries(); +const selectedGreenFixtures = await buildGreenFixtures(); +const flagshipFixture = await buildFlagshipFixture(); +const redFixtures = await buildRedFixtures(); +const oogBoundaries = await buildOogBoundaries(runnableExamples); + +const examplesPayload = { + generatedAt, + metadata: { + engineBuildHash, + gasVersion, + wasmVariant: 'wasm32', + wasmBuildType: 'release', + }, + examples: [ + ...runnableExamples.galleryEntries, + ...selectedGreenFixtures.galleryEntries, + flagshipFixture.galleryEntry, + ], +}; + +const evidencePayload = { + generatedAt, + metadata: { + engineBuildHash, + gasVersion, + }, + evidence: { + ...runnableExamples.evidenceById, + ...selectedGreenFixtures.evidenceById, + ...flagshipFixture.evidenceById, + }, +}; + +const oogPayload = { + generatedAt, + metadata: { + engineBuildHash, + gasVersion, + }, + boundaries: oogBoundaries, +}; + +const redPayload = { + generatedAt, + metadata: { + engineBuildHash, + gasVersion, + }, + fixtures: redFixtures, +}; + +const outputs = new Map([ + [ + 'playground-examples.json', + `${JSON.stringify(canonicalizeGeneratedValue(examplesPayload), null, 2)}\n`, + ], + [ + 'playground-evidence.json', + `${JSON.stringify(canonicalizeGeneratedValue(evidencePayload), null, 2)}\n`, + ], + [ + 'playground-oog-boundaries.json', + `${JSON.stringify(canonicalizeGeneratedValue(oogPayload), null, 2)}\n`, + ], + [ + 'playground-red-fixtures.json', + `${JSON.stringify(canonicalizeGeneratedValue(redPayload), null, 2)}\n`, + ], +]); + +await mkdir(outDir, { recursive: true }); + +if (args.check) { + const mismatches = []; + for (const [filename, expected] of outputs) { + const targetPath = path.join(outDir, filename); + let current = null; + try { + current = await readFile(targetPath, 'utf8'); + } catch { + current = null; + } + if (current !== expected) { + mismatches.push(filename); + } + } + + process.stdout.write( + `${JSON.stringify( + { + status: mismatches.length === 0 ? 'ok' : 'stale', + outDir: path.relative(repoRoot, outDir), + checkedFiles: [...outputs.keys()], + mismatches, + }, + null, + 2, + )}\n`, + ); + + if (mismatches.length > 0) { + process.exitCode = 1; + } +} else { + for (const [filename, contents] of outputs) { + await writeFile(path.join(outDir, filename), contents, 'utf8'); + } + + process.stdout.write( + `${JSON.stringify( + { + status: 'generated', + outDir: path.relative(repoRoot, outDir), + files: [...outputs.keys()], + }, + null, + 2, + )}\n`, + ); +} + +async function buildExampleEntries() { + const galleryEntries = []; + const evidenceById = {}; + + for (const entry of EXAMPLE_CORPUS) { + const built = await buildCorpusEntry(entry); + galleryEntries.push(built.galleryEntry); + evidenceById[built.galleryEntry.id] = built.evidence; + } + + return { galleryEntries, evidenceById }; +} + +async function buildCorpusEntry(entry) { + const id = `example-${entry.slug}`; + const docsLinks = docsLinksForExample(entry.slug); + const gasLimit = gasLimitForExample(entry.slug); + const sourcePaths = entry.sourcePaths; + const sourceText = await readPrimarySource(sourcePaths[0]); + const profile = Array.isArray(entry.profile) + ? entry.profile[0] + : entry.profile; + + let program; + let manifest; + const hostPreset = 'determinism'; + let description = exampleDescription(entry.slug); + + switch (entry.slug) { + case 'basic-script': + case 'promises-async': + case 'console-shim': + case 'stable-sort': + case 'max-gas-policy': + program = createScriptProgram({ + code: await readPrimarySource(sourcePaths[0]), + profile, + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + }); + manifest = HOST_V1_MANIFEST; + break; + case 'binary-host-v2': + program = createScriptProgram({ + code: await readPrimarySource(sourcePaths[0]), + profile: 'compat-binary-v1', + abiId: 'Host.v2', + abiVersion: 2, + abiManifestHash: HOST_V2_HASH, + }); + manifest = HOST_V2_MANIFEST; + break; + case 'module-pack': + case 'promises-library-host': + case 'kitchen-sink': { + const built = await buildProgramArtifact({ + entryPath: sourcePaths[0], + profile, + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + }); + program = built.programArtifact; + manifest = HOST_V1_MANIFEST; + break; + } + case 'library-reuse': { + const built = await buildProgramArtifact({ + entryPath: 'libs/test-harness/fixtures/library-reuse/chess-entry.ts', + profile: 'compat-general-v1', + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + }); + program = built.programArtifact; + manifest = HOST_V1_MANIFEST; + description += + ' The binary base64 companion source remains listed alongside the chess.js entry for comparison.'; + break; + } + default: + throw new Error(`unhandled example corpus slug: ${entry.slug}`); + } + + const execution = await evaluateWithPreset({ + id, + title: entry.title, + program, + manifest, + gasLimit, + hostPreset, + }); + + return { + galleryEntry: { + id, + title: entry.title, + kind: 'example', + badge: `Example ${entry.id}`, + description, + certified: true, + executionProfile: program.executionProfile, + sourceKind: program.sourceKind, + abiId: program.abiId, + gasLimit: gasLimit.toString(), + sourcePaths, + sourceText, + hostPreset, + hostSummary: HOST_PRESET_SUMMARIES[hostPreset], + docsLinks, + supportsOogSearch: true, + program, + manifest, + }, + evidence: { + ...execution.snapshot, + certified: true, + reportSource: `examples/${entry.id.toString().padStart(2, '0')}-${entry.slug}`, + fixtureCoverage: entry.coverage, + }, + }; +} + +async function buildGreenFixtures() { + const galleryEntries = []; + const evidenceById = {}; + + for (const fixtureId of SELECTED_GREEN_FIXTURE_IDS) { + const fixture = CERTIFIER_FIXTURES.find((item) => item.id === fixtureId); + if (!fixture) { + throw new Error(`unknown selected green fixture: ${fixtureId}`); + } + + const built = await buildProgramArtifact({ + entryPath: fixture.entryPath, + profile: fixture.profile, + abiId: fixture.abiId, + abiVersion: fixture.abiVersion, + abiManifestHash: fixture.abiManifestHash, + }); + const manifest = manifestForFixture(fixture); + const execution = await evaluateWithPreset({ + id: fixture.id, + title: fixture.title, + program: built.programArtifact, + manifest, + gasLimit: fixture.gasLimit, + hostPreset: 'certification', + }); + + galleryEntries.push({ + id: fixture.id, + title: fixture.title, + kind: 'ecosystem-green', + badge: 'Green ecosystem fixture', + description: fixtureDescription(fixture.id), + certified: true, + executionProfile: built.programArtifact.executionProfile, + sourceKind: built.programArtifact.sourceKind, + abiId: built.programArtifact.abiId, + gasLimit: fixture.gasLimit.toString(), + sourcePaths: [fixture.entryPath], + sourceText: await readPrimarySource(fixture.entryPath), + hostPreset: 'certification', + hostSummary: HOST_PRESET_SUMMARIES.certification, + docsLinks: docsLinksForFixture(fixture.id), + supportsOogSearch: false, + program: built.programArtifact, + manifest, + }); + + evidenceById[fixture.id] = { + ...execution.snapshot, + certified: true, + reportSource: `ecosystem-certifier:${fixture.id}`, + fixtureCoverage: [ + { suite: 'ecosystem-certifier', fixtureName: fixture.id }, + ], + }; + } + + return { galleryEntries, evidenceById }; +} + +async function buildFlagshipFixture() { + const fixture = CERTIFIER_FIXTURES.find( + (item) => item.id === 'flagship-knowledge-pack', + ); + if (!fixture) { + throw new Error('flagship fixture not found'); + } + + const built = await buildProgramArtifact({ + entryPath: fixture.entryPath, + profile: fixture.profile, + abiId: fixture.abiId, + abiVersion: fixture.abiVersion, + abiManifestHash: fixture.abiManifestHash, + }); + const manifest = manifestForFixture(fixture); + const execution = await evaluateWithPreset({ + id: fixture.id, + title: fixture.title, + program: built.programArtifact, + manifest, + gasLimit: fixture.gasLimit, + hostPreset: 'certification', + }); + + return { + galleryEntry: { + id: fixture.id, + title: fixture.title, + kind: 'flagship', + badge: 'Flagship workload', + description: + 'A browsable flagship deterministic workload that mixes static imports, Promise jobs, text and binary host data, and certification-ready evidence.', + certified: true, + executionProfile: built.programArtifact.executionProfile, + sourceKind: built.programArtifact.sourceKind, + abiId: built.programArtifact.abiId, + gasLimit: fixture.gasLimit.toString(), + sourcePaths: [fixture.entryPath], + sourceText: await readPrimarySource(fixture.entryPath), + hostPreset: 'certification', + hostSummary: HOST_PRESET_SUMMARIES.certification, + docsLinks: docsLinksForFixture(fixture.id), + supportsOogSearch: false, + program: built.programArtifact, + manifest, + }, + evidenceById: { + [fixture.id]: { + ...execution.snapshot, + certified: true, + reportSource: `ecosystem-certifier:${fixture.id}`, + fixtureCoverage: [ + { suite: 'ecosystem-certifier', fixtureName: fixture.id }, + ], + }, + }, + }; +} + +async function buildRedFixtures() { + const fixtures = []; + + for (const fixtureId of SELECTED_RED_FIXTURE_IDS) { + const fixture = CERTIFIER_FIXTURES.find((item) => item.id === fixtureId); + if (!fixture) { + throw new Error(`unknown selected red fixture: ${fixtureId}`); + } + + try { + const built = await buildProgramArtifact({ + entryPath: fixture.entryPath, + profile: fixture.profile, + abiId: fixture.abiId, + abiVersion: fixture.abiVersion, + abiManifestHash: fixture.abiManifestHash, + }); + const manifest = manifestForFixture(fixture); + const execution = await evaluateWithPreset({ + id: fixture.id, + title: fixture.title, + program: built.programArtifact, + manifest, + gasLimit: fixture.gasLimit, + hostPreset: 'certification', + }); + + fixtures.push({ + id: fixture.id, + title: fixture.title, + kind: fixture.kind, + executionProfile: fixture.profile, + failureStage: execution.snapshot.stage, + errorCode: execution.snapshot.errorCode, + errorTag: execution.snapshot.errorTag, + certified: true, + docsLinks: docsLinksForFixture(fixture.id), + diagnostics: [], + runtimeArtifact: built.programArtifact, + reportSource: `ecosystem-certifier:${fixture.id}`, + }); + } catch (error) { + if (!(error instanceof DeterministicBuilderError)) { + throw error; + } + + fixtures.push({ + id: fixture.id, + title: fixture.title, + kind: fixture.kind, + executionProfile: fixture.profile, + failureStage: 'builder_reject', + errorCode: null, + errorTag: null, + certified: true, + docsLinks: docsLinksForFixture(fixture.id), + diagnostics: error.diagnostics, + runtimeArtifact: null, + reportSource: `ecosystem-certifier:${fixture.id}`, + }); + } + } + + return fixtures; +} + +async function buildOogBoundaries(runnableExamples) { + const boundaries = {}; + + for (const example of runnableExamples.galleryEntries) { + const boundary = await findOogBoundary({ + program: example.program, + manifest: example.manifest, + gasLimit: BigInt(example.gasLimit), + hostPreset: example.hostPreset, + }); + boundaries[example.id] = boundary; + } + + return boundaries; +} + +async function findOogBoundary({ program, manifest, gasLimit, hostPreset }) { + const successful = await evaluateWithPreset({ + id: 'boundary', + title: 'boundary', + program, + manifest, + gasLimit, + hostPreset, + }); + let upperGas = BigInt(successful.snapshot.gasUsed); + let upperResult = await runRawEvaluate({ + program, + manifest, + gasLimit: upperGas, + hostPreset, + }); + + while (!upperResult.ok) { + upperGas *= 2n; + upperResult = await runRawEvaluate({ + program, + manifest, + gasLimit: upperGas, + hostPreset, + }); + } + + let lowerGas = 0n; + let lowerResult = await runRawEvaluate({ + program, + manifest, + gasLimit: lowerGas, + hostPreset, + }); + + while (lowerGas + 1n < upperGas) { + const mid = (lowerGas + upperGas) >> 1n; + const current = await runRawEvaluate({ + program, + manifest, + gasLimit: mid, + hostPreset, + }); + if (current.ok) { + upperGas = mid; + upperResult = current; + } else { + lowerGas = mid; + lowerResult = current; + } + } + + return { + firstSuccessGas: upperGas.toString(), + lastFailureGas: lowerGas.toString(), + successGasUsed: upperResult.gasUsed.toString(), + successGasRemaining: upperResult.gasRemaining.toString(), + failureGasUsed: lowerResult.gasUsed.toString(), + failureGasRemaining: lowerResult.gasRemaining.toString(), + failureCode: lowerResult.ok ? null : lowerResult.error.code, + failureTag: + !lowerResult.ok && 'tag' in lowerResult.error + ? lowerResult.error.tag + : null, + }; +} + +async function evaluateWithPreset({ + id, + title, + program, + manifest, + gasLimit, + hostPreset, +}) { + const result = await runRawEvaluate({ + program, + manifest, + gasLimit, + hostPreset, + }); + + const snapshot = await snapshotFromResult(result); + return { id, title, snapshot }; +} + +async function runRawEvaluate({ program, manifest, gasLimit, hostPreset }) { + const host = createHostPreset(hostPreset); + return evaluate({ + program, + input: + hostPreset === 'certification' ? CERTIFICATION_INPUT : DETERMINISM_INPUT, + gasLimit, + manifest, + handlers: host.handlers, + tape: { capacity: 128 }, + metadata, + wasmBinary, + releaseMode: true, + expectedExecutionProfile: program.executionProfile, + }); +} + +async function snapshotFromResult(result) { + const tape = result.tape ?? []; + const tapeHash = + tape.length === 0 ? null : sha256Hex(serializeHostTape(tape)); + + if (result.ok) { + return { + stage: 'success', + resultHash: sha256Hex(encodeDv2(result.value)), + errorCode: null, + errorTag: null, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + tapeHash, + tapeLength: tape.length, + }; + } + + return { + stage: normalizeFailureStage(result.error.kind), + resultHash: null, + errorCode: result.error.code, + errorTag: 'tag' in result.error ? result.error.tag : null, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + tapeHash, + tapeLength: tape.length, + }; +} + +function normalizeFailureStage(kind) { + if (kind === 'module-pack') { + return 'artifact_validation'; + } + if (kind === 'execution-surface-mismatch') { + return 'pin_enforcement'; + } + return 'runtime_error'; +} + +function createHostPreset(hostPreset) { + return hostPreset === 'certification' + ? createCertificationHost() + : createDeterminismHost(); +} + +function createScriptProgram({ + code, + profile, + abiId, + abiVersion, + abiManifestHash, +}) { + return { + version: 2, + abiId, + abiVersion, + abiManifestHash, + executionProfile: profile, + sourceKind: 'script', + source: { code }, + ...(engineBuildHash ? { engineBuildHash } : {}), + ...(gasVersion !== null ? { gasVersion } : {}), + }; +} + +async function buildProgramArtifact({ + entryPath, + profile, + abiId, + abiVersion, + abiManifestHash, +}) { + const built = await buildDeterministicModulePack({ + absWorkingDir: repoRoot, + entryPath, + profile, + emitProgramArtifact: true, + abiId, + abiVersion, + abiManifestHash, + ...(engineBuildHash ? { engineBuildHash } : {}), + ...(gasVersion !== null ? { gasVersion } : {}), + }); + + if (!built.programArtifact) { + throw new Error( + `builder did not return ProgramArtifact.v2 for ${entryPath}`, + ); + } + + return built; +} + +function docsLinksForExample(slug) { + const base = [ + { label: 'Learn path', href: '/docs/learn/README.md' }, + { label: 'Examples corpus', href: '/examples/README.md' }, + ]; + + switch (slug) { + case 'module-pack': + return [ + ...base, + { + label: 'Module packs', + href: '/docs/learn/03-module-packs-and-imports.md', + }, + ]; + case 'promises-async': + case 'promises-library-host': + return [ + ...base, + { + label: 'Promises and microtasks', + href: '/docs/learn/04-promises-async-and-microtasks.md', + }, + ]; + case 'binary-host-v2': + return [ + ...base, + { + label: 'Binary mode and Host.v2', + href: '/docs/learn/05-binary-and-host-v2.md', + }, + ]; + case 'max-gas-policy': + return [ + ...base, + { + label: 'Gas and OOG', + href: '/docs/learn/06-gas-oog-and-max-gas-policies.md', + }, + ]; + default: + return base; + } +} + +function docsLinksForFixture(fixtureId) { + const base = [ + { + label: 'Workload certification', + href: '/docs/workload-certification.md', + }, + { + label: 'Compatibility report', + href: '/docs/ecosystem-compatibility-report.md', + }, + ]; + + if (fixtureId.startsWith('red-')) { + return [ + ...base, + { + label: 'Unsupported features and why', + href: '/docs/unsupported-features-and-why.md', + }, + ]; + } + + if (fixtureId === 'flagship-knowledge-pack') { + return [ + ...base, + { + label: 'Architecture overview', + href: '/docs/architecture-overview.md', + }, + ]; + } + + return base; +} + +function exampleDescription(slug) { + return { + 'basic-script': 'Smallest possible deterministic script-mode example.', + 'module-pack': + 'Static ESM module-pack example with a deterministic graph hash.', + 'library-reuse': + 'Real library reuse through a deterministic module-pack instead of runtime imports.', + 'promises-async': + 'Promise job draining under an explicitly compatible profile.', + 'promises-library-host': + 'Imported module code plus Promise jobs plus host interaction.', + 'binary-host-v2': + 'Typed-array and bytes boundary example using Host.v2 and DV2.', + 'console-shim': 'Deterministic console shimming routed through host tape.', + 'stable-sort': + 'Compatibility profile example showing deterministic stable sort.', + 'kitchen-sink': + 'Composite example mixing modules, Promise jobs, host calls, and stable sort.', + 'max-gas-policy': + 'Shows how exact OOG boundaries are part of the release contract.', + }[slug]; +} + +function fixtureDescription(fixtureId) { + return { + 'green-semver': + 'Semver constraint evaluation from the certified green ecosystem corpus.', + 'green-base64': + 'Binary roundtrip coverage from the certified green ecosystem corpus.', + 'green-markdown-it': + 'A larger parser-oriented compatibility fixture running under deterministic constraints.', + 'green-noble-sha': + 'A binary-heavy crypto-style fixture showing deterministic digest behavior.', + }[fixtureId]; +} + +function gasLimitForExample(slug) { + return { + 'basic-script': 1_000_000n, + 'module-pack': 50_000n, + 'library-reuse': 5_000_000n, + 'promises-async': 50_000n, + 'promises-library-host': 100_000n, + 'binary-host-v2': 50_000n, + 'console-shim': 50_000n, + 'stable-sort': 100_000n, + 'kitchen-sink': 200_000n, + 'max-gas-policy': 1_000_000n, + }[slug]; +} + +async function readPrimarySource(relativePath) { + return readFile(path.join(repoRoot, relativePath), 'utf8'); +} + +function sha256Hex(input) { + const bytes = + typeof input === 'string' ? new TextEncoder().encode(input) : input; + return createHash('sha256').update(bytes).digest('hex'); +} + +function canonicalizeGeneratedValue(value) { + if (typeof value === 'string') { + return value.split(repoRoot).join('/workspace'); + } + if (Array.isArray(value)) { + return value.map((item) => canonicalizeGeneratedValue(item)); + } + if (value && typeof value === 'object') { + return Object.fromEntries( + Object.entries(value).map(([key, item]) => [ + key, + canonicalizeGeneratedValue(item), + ]), + ); + } + return value; +} + +function parseArgs(argv) { + return { + check: argv.includes('--check'), + }; +} + +async function ensurePlaygroundBuildArtifacts() { + const requiredFiles = [ + 'libs/dv/dist/index.js', + 'libs/abi-manifest/dist/index.js', + 'libs/quickjs-runtime/dist/index.js', + 'libs/quickjs-wasm/dist/index.js', + 'libs/test-harness/dist/index.js', + 'libs/deterministic-builder/dist/index.js', + ].map((relativePath) => path.join(repoRoot, relativePath)); + + if (requiredFiles.every((targetPath) => existsSync(targetPath))) { + return; + } + + const emsdkEnvPath = path.join(repoRoot, 'tools/emsdk/emsdk_env.sh'); + if (!existsSync(emsdkEnvPath)) { + throw new Error( + [ + 'Playground generation needs built workspace libraries and the pinned Emscripten toolchain.', + 'Missing tools/emsdk/emsdk_env.sh.', + 'Run:', + ' bash tools/scripts/setup-emsdk.sh', + ' source tools/emsdk/emsdk_env.sh', + ' pnpm nx build bluequickjs-playground', + 'or use:', + ' bash apps/bluequickjs-playground/scripts/dev.sh', + ].join('\n'), + ); + } + + const buildCommand = + 'source tools/emsdk/emsdk_env.sh && pnpm nx build bluequickjs-playground'; + process.stderr.write( + [ + 'bluequickjs-playground: built workspace outputs were not found.', + 'Bootstrapping them now with:', + ` ${buildCommand}`, + '', + ].join('\n'), + ); + + const result = spawnSync('bash', ['-lc', buildCommand], { + cwd: repoRoot, + stdio: 'inherit', + env: process.env, + }); + + if (result.status !== 0) { + throw new Error( + [ + 'Automatic playground bootstrap build failed.', + 'If tools/scripts/setup-emsdk.sh was interrupted, rerun it because the install is idempotent.', + 'Then run:', + ' source tools/emsdk/emsdk_env.sh', + ' pnpm nx build bluequickjs-playground', + ' node apps/bluequickjs-playground/scripts/generate-playground-data.mjs', + ].join('\n'), + ); + } +} diff --git a/apps/bluequickjs-playground/src/app/format.spec.ts b/apps/bluequickjs-playground/src/app/format.spec.ts new file mode 100644 index 0000000..830701c --- /dev/null +++ b/apps/bluequickjs-playground/src/app/format.spec.ts @@ -0,0 +1,31 @@ +import { + formatGas, + formatStage, + shortenHash, + slugToLabel, + toPrettyJson, +} from './format.js'; + +describe('playground format helpers', () => { + it('formats gas values with grouping', () => { + expect(formatGas('1000000')).toBe('1,000,000'); + expect(formatGas(74n)).toBe('74'); + }); + + it('shortens hashes for UI display', () => { + expect(shortenHash('a'.repeat(64), 6)).toBe('aaaaaa…aaaaaa'); + expect(shortenHash(null)).toBe('—'); + }); + + it('formats failure stages for labels', () => { + expect(formatStage('artifact_validation')).toBe('artifact validation'); + }); + + it('converts slugs into labels', () => { + expect(slugToLabel('ecosystem-green')).toBe('Ecosystem Green'); + }); + + it('pretty prints json content', () => { + expect(toPrettyJson({ ok: true })).toContain('"ok": true'); + }); +}); diff --git a/apps/bluequickjs-playground/src/app/format.ts b/apps/bluequickjs-playground/src/app/format.ts new file mode 100644 index 0000000..cd93f5e --- /dev/null +++ b/apps/bluequickjs-playground/src/app/format.ts @@ -0,0 +1,29 @@ +export function formatGas(value: string | bigint): string { + const raw = typeof value === 'bigint' ? value.toString() : value; + return Number(raw).toLocaleString('en-US'); +} + +export function shortenHash(value: string | null, size = 8): string { + if (!value) { + return '—'; + } + if (value.length <= size * 2) { + return value; + } + return `${value.slice(0, size)}…${value.slice(-size)}`; +} + +export function toPrettyJson(value: unknown): string { + return `${JSON.stringify(value, null, 2)}\n`; +} + +export function formatStage(stage: string): string { + return stage.replace(/[-_]/g, ' '); +} + +export function slugToLabel(value: string): string { + return value + .split(/[-_]/g) + .map((part) => part.charAt(0).toUpperCase() + part.slice(1)) + .join(' '); +} diff --git a/apps/bluequickjs-playground/src/app/monaco.ts b/apps/bluequickjs-playground/src/app/monaco.ts new file mode 100644 index 0000000..024c4d4 --- /dev/null +++ b/apps/bluequickjs-playground/src/app/monaco.ts @@ -0,0 +1,14 @@ +import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'; +import jsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker'; +import * as monaco from 'monaco-editor'; + +window.MonacoEnvironment = { + getWorker(_: unknown, label: string) { + if (label === 'json') { + return new jsonWorker(); + } + return new editorWorker(); + }, +}; + +export { monaco }; diff --git a/apps/bluequickjs-playground/src/app/playground-app.ts b/apps/bluequickjs-playground/src/app/playground-app.ts new file mode 100644 index 0000000..bf21231 --- /dev/null +++ b/apps/bluequickjs-playground/src/app/playground-app.ts @@ -0,0 +1,965 @@ +import { + isKnownExecutionProfile, + type PublicExecutionProfile, +} from '@blue-quickjs/execution-profiles'; +import { monaco } from './monaco.js'; +import { formatGas, shortenHash, slugToLabel, toPrettyJson } from './format.js'; +import { + compareAgainstEvidence, + createScriptArtifact, + defaultManifestForArtifact, + findOogBoundary, + loadPlaygroundData, + parseArtifactJson, + runArtifact, +} from './runtime.js'; +import { + getInitialExample, + getProfileSummary, + groupExamples, +} from './state.js'; +import type { + GalleryEntry, + HostPresetId, + LoadedPlaygroundData, + OogBoundaryRecord, + PlaygroundRunResult, + RedFixtureRecord, +} from './types.js'; + +type Selection = { type: 'gallery'; id: string } | { type: 'red'; id: string }; + +export class PlaygroundApp { + private data: LoadedPlaygroundData | null = null; + + private selection: Selection | null = null; + + private mode: 'gallery' | 'script' | 'artifact' = 'gallery'; + + private runResult: PlaygroundRunResult | null = null; + + private activeTab: 'result' | 'evidence' | 'host' | 'metadata' | 'help' = + 'result'; + + private hostPreset: HostPresetId = 'determinism'; + + private editor: monaco.editor.IStandaloneCodeEditor | null = null; + + private boundaryOverride: OogBoundaryRecord | null = null; + + private scriptProfile: PublicExecutionProfile = 'baseline-v1'; + + private artifactJson = ''; + + private readonly root: HTMLElement; + + constructor(root: HTMLElement) { + this.root = root; + } + + async init(): Promise { + this.root.innerHTML = + '

Loading BlueQuickjs Playground…
'; + this.data = await loadPlaygroundData(); + const initial = getInitialExample(this.data); + this.selection = { type: 'gallery', id: initial.id }; + this.hostPreset = initial.hostPreset; + this.renderShell(); + this.renderLists(); + this.syncSelectionToSurface(); + this.bindEvents(); + this.createEditor(); + this.updateEditorForMode(); + this.updatePanels(); + } + + private renderShell(): void { + this.root.innerHTML = ` +
+
+
+ +
+

web.blue visual language

+

BlueQuickjs Playground

+
+
+

+ Explore deterministic JavaScript execution with the same wasm32 engine + and evidence model used by the release process. Consensus-safe scope is + explicitly wasm-node vs wasm-browser; native remains + diagnostic-only. +

+
+ Consensus-safe: wasm32 only + Exact gas + exact OOG + Generated evidence-backed examples +
+
+ +
+ + +
+
+
+
+

+

+
+
+ + +
+
+
+
+ + +
+
+
+ +
+
+
+

Run output

+

Result bytes, gas, host tape, evidence match status, and release pins.

+
+
+ Idle + No run yet +
+
+
+
+ + + + + +
+
+
+
+
+
+ `; + } + + private bindEvents(): void { + this.root + .querySelectorAll('[data-mode]') + .forEach((button) => { + button.addEventListener('click', () => { + this.mode = button.dataset.mode as typeof this.mode; + this.updateEditorForMode(); + this.updateControls(); + this.updatePanels(); + }); + }); + + this.root + .querySelector('[data-profile]') + ?.addEventListener('change', (event) => { + const next = (event.currentTarget as HTMLSelectElement).value; + if (isKnownExecutionProfile(next)) { + this.scriptProfile = next; + this.updateControls(); + } + }); + + this.root + .querySelector('[data-gas-limit]') + ?.addEventListener('change', () => this.updatePanels()); + + this.root + .querySelector('[data-host-preset]') + ?.addEventListener('change', (event) => { + this.hostPreset = (event.currentTarget as HTMLSelectElement) + .value as HostPresetId; + this.updatePanels(); + }); + + this.root + .querySelectorAll('[data-gas-preset]') + .forEach((button) => { + button.addEventListener('click', () => { + const input = + this.root.querySelector('[data-gas-limit]'); + if (input && button.dataset.gasPreset) { + input.value = button.dataset.gasPreset; + } + }); + }); + + this.root + .querySelector('[data-run]') + ?.addEventListener('click', () => void this.runCurrentSelection()); + this.root + .querySelector('[data-find-oog]') + ?.addEventListener('click', () => void this.findBoundary()); + this.root + .querySelector('[data-export-artifact]') + ?.addEventListener('click', () => this.exportArtifact()); + this.root + .querySelector('[data-export-evidence]') + ?.addEventListener('click', () => this.exportEvidence()); + + this.root + .querySelectorAll('[data-tab]') + .forEach((button) => { + button.addEventListener('click', () => { + this.activeTab = button.dataset.tab as typeof this.activeTab; + this.updatePanels(); + }); + }); + } + + private createEditor(): void { + const mount = this.root.querySelector('[data-editor]'); + if (!mount) { + return; + } + this.editor = monaco.editor.create(mount, { + value: '', + language: 'javascript', + automaticLayout: true, + minimap: { enabled: false }, + fontFamily: 'Roboto Mono, monospace', + fontSize: 14, + lineHeight: 20, + scrollBeyondLastLine: false, + roundedSelection: true, + readOnly: true, + theme: 'vs', + padding: { top: 16, bottom: 16 }, + }); + } + + private renderLists(): void { + if (!this.data) { + return; + } + + const grouped = groupExamples(this.data.examples.examples); + const groupsMount = this.root.querySelector( + '[data-gallery-groups]', + ); + const redMount = this.root.querySelector('[data-red-list]'); + + if (groupsMount) { + groupsMount.innerHTML = Object.entries(grouped) + .map( + ([key, entries]) => ` + + `, + ) + .join(''); + + groupsMount + .querySelectorAll('[data-gallery-id]') + .forEach((button) => { + button.addEventListener('click', () => { + const galleryId = button.dataset.galleryId; + if (!galleryId) { + return; + } + this.selection = { type: 'gallery', id: galleryId }; + this.mode = 'gallery'; + this.boundaryOverride = null; + this.runResult = null; + const current = this.currentGalleryEntry(); + if (current) { + this.hostPreset = current.hostPreset; + } + this.updateEditorForMode(); + this.updateControls(); + this.updatePanels(); + }); + }); + } + + if (redMount) { + redMount.innerHTML = this.data.red.fixtures + .map( + (fixture) => ` + + `, + ) + .join(''); + + redMount + .querySelectorAll('[data-red-id]') + .forEach((button) => { + button.addEventListener('click', () => { + const redId = button.dataset.redId; + if (!redId) { + return; + } + this.selection = { type: 'red', id: redId }; + this.mode = 'gallery'; + this.boundaryOverride = null; + this.runResult = null; + this.hostPreset = 'certification'; + this.updateEditorForMode(); + this.updateControls(); + this.updatePanels(); + }); + }); + } + } + + private currentGalleryEntry(): GalleryEntry | null { + if (!this.data || !this.selection || this.selection.type !== 'gallery') { + return null; + } + return ( + this.data.examples.examples.find( + (entry) => entry.id === this.selection?.id, + ) ?? null + ); + } + + private currentRedFixture(): RedFixtureRecord | null { + if (!this.data || !this.selection || this.selection.type !== 'red') { + return null; + } + return ( + this.data.red.fixtures.find((entry) => entry.id === this.selection?.id) ?? + null + ); + } + + private updateEditorForMode(): void { + if (!this.editor || !this.data) { + return; + } + + const selection = this.currentGalleryEntry(); + const redFixture = this.currentRedFixture(); + const modeLabel = this.root.querySelector( + '[data-editor-mode-label]', + ); + const sourcePaths = this.root.querySelector( + '[data-editor-source-paths]', + ); + + if (this.mode === 'script') { + const seed = selection?.sourceText ?? 'export default (() => 1 + 2)();\n'; + this.editor.updateOptions({ readOnly: false }); + this.editor.setValue(seed); + const model = this.editor.getModel(); + if (model) { + monaco.editor.setModelLanguage(model, 'javascript'); + } + if (modeLabel) modeLabel.textContent = 'Script mode'; + if (sourcePaths) sourcePaths.textContent = 'Editable JavaScript snippet'; + return; + } + + if (this.mode === 'artifact') { + if (!this.artifactJson) { + this.artifactJson = toPrettyJson( + selection?.program ?? + redFixture?.runtimeArtifact ?? + createScriptArtifact( + 'export default (() => 1 + 2)();\n', + this.scriptProfile, + this.data.examples.metadata, + ), + ); + } + this.editor.updateOptions({ readOnly: false }); + this.editor.setValue(this.artifactJson); + const model = this.editor.getModel(); + if (model) { + monaco.editor.setModelLanguage(model, 'json'); + } + if (modeLabel) modeLabel.textContent = 'Artifact JSON import mode'; + if (sourcePaths) + sourcePaths.textContent = 'Paste or edit ProgramArtifact.v2 JSON'; + return; + } + + this.editor.updateOptions({ readOnly: true }); + if (selection) { + this.editor.setValue(selection.sourceText); + const model = this.editor.getModel(); + if (model) { + monaco.editor.setModelLanguage( + model, + selection.sourcePaths[0]?.endsWith('.ts') + ? 'typescript' + : 'javascript', + ); + } + if (modeLabel) modeLabel.textContent = 'Certified gallery source'; + if (sourcePaths) + sourcePaths.textContent = selection.sourcePaths.join(' · '); + } else if (redFixture) { + const payload = redFixture.runtimeArtifact ?? { + diagnostics: redFixture.diagnostics, + failureStage: redFixture.failureStage, + }; + this.editor.setValue(toPrettyJson(payload)); + const model = this.editor.getModel(); + if (model) { + monaco.editor.setModelLanguage(model, 'json'); + } + if (modeLabel) modeLabel.textContent = 'Deterministic failure fixture'; + if (sourcePaths) sourcePaths.textContent = redFixture.reportSource; + } + } + + private updateControls(): void { + const selection = this.currentGalleryEntry(); + const redFixture = this.currentRedFixture(); + const profileSelect = + this.root.querySelector('[data-profile]'); + const gasInput = + this.root.querySelector('[data-gas-limit]'); + const hostPreset = + this.root.querySelector('[data-host-preset]'); + const profileHelp = this.root.querySelector( + '[data-profile-help]', + ); + const runButton = this.root.querySelector('[data-run]'); + const oogButton = + this.root.querySelector('[data-find-oog]'); + + if (selection) { + if (gasInput) gasInput.value = selection.gasLimit; + if (hostPreset) hostPreset.value = this.hostPreset; + } + if (redFixture && gasInput) { + gasInput.value = '1000000'; + } + + if (profileSelect) { + profileSelect.value = + this.mode === 'script' + ? this.scriptProfile + : (selection?.executionProfile ?? 'baseline-v1'); + profileSelect.disabled = this.mode !== 'script'; + } + + if (profileHelp) { + profileHelp.textContent = getProfileSummary( + (this.mode === 'script' + ? this.scriptProfile + : (selection?.executionProfile ?? 'baseline-v1')) as never, + ); + } + + if (runButton) { + runButton.disabled = + this.mode === 'gallery' && + redFixture !== null && + redFixture.runtimeArtifact === null; + } + + if (oogButton) { + oogButton.disabled = + this.mode === 'gallery' + ? selection === null || !selection.supportsOogSearch + : false; + } + + this.root + .querySelectorAll('[data-mode]') + .forEach((button) => { + button.dataset.active = String(button.dataset.mode === this.mode); + }); + this.root + .querySelectorAll('[data-tab]') + .forEach((button) => { + button.dataset.active = String(button.dataset.tab === this.activeTab); + }); + } + + private syncSelectionToSurface(): void { + const selection = this.currentGalleryEntry(); + const redFixture = this.currentRedFixture(); + const title = this.root.querySelector( + '[data-selection-title]', + ); + const description = this.root.querySelector( + '[data-selection-description]', + ); + const badge = this.root.querySelector( + '[data-selection-badge]', + ); + const cert = this.root.querySelector('[data-selection-cert]'); + const meta = this.root.querySelector('[data-selection-meta]'); + + if (selection) { + if (title) title.textContent = selection.title; + if (description) description.textContent = selection.description; + if (badge) badge.textContent = selection.badge; + if (cert) + cert.textContent = selection.certified + ? 'Consensus-certified evidence' + : 'Uncertified'; + if (meta) { + meta.innerHTML = ` + ${selection.executionProfile} + ${selection.sourceKind} + ${selection.abiId} + ${selection.hostSummary.label} + `; + } + return; + } + + if (redFixture) { + if (title) title.textContent = redFixture.title; + if (description) { + description.textContent = + redFixture.runtimeArtifact === null + ? 'Builder rejection fixture that teaches why unsupported code never reaches runtime.' + : 'Runtime-level deterministic failure fixture with a stable failure stage.'; + } + if (badge) badge.textContent = 'Red deterministic failure'; + if (cert) cert.textContent = 'Certified deterministic rejection'; + if (meta) { + meta.innerHTML = ` + ${redFixture.executionProfile} + ${redFixture.failureStage} + ${redFixture.reportSource} + `; + } + } + } + + private updatePanels(): void { + this.syncSelectionToSurface(); + this.updateControls(); + this.renderMetrics(); + this.renderTabPanel(); + } + + private renderMetrics(): void { + const mount = this.root.querySelector('[data-metrics-grid]'); + const runStatus = this.root.querySelector('[data-run-status]'); + const evidenceStatus = this.root.querySelector( + '[data-evidence-status]', + ); + if (!mount) { + return; + } + + if (!this.runResult) { + mount.innerHTML = ` +
+ Awaiting run + Choose an example, script, or artifact JSON and press Run. +
+ `; + if (runStatus) runStatus.textContent = 'Idle'; + if (evidenceStatus) evidenceStatus.textContent = 'No run yet'; + return; + } + + const currentId = + this.selection?.type === 'gallery' || this.selection?.type === 'red' + ? this.selection.id + : null; + const evidence = + currentId && this.data + ? this.data.evidence.evidence[currentId] + : undefined; + const match = compareAgainstEvidence(this.runResult, evidence); + if (runStatus) + runStatus.textContent = this.runResult.ok ? 'Success' : 'Failure'; + if (evidenceStatus) { + evidenceStatus.textContent = !match.available + ? 'No certified evidence' + : match.matches + ? 'Matches certified snapshot' + : 'Differs from certified snapshot'; + } + + mount.innerHTML = [ + metricCard('Stage', this.runResult.snapshot.stage), + metricCard('Gas used', formatGas(this.runResult.snapshot.gasUsed)), + metricCard( + 'Gas remaining', + formatGas(this.runResult.snapshot.gasRemaining), + ), + metricCard('Tape length', String(this.runResult.snapshot.tapeLength)), + metricCard( + 'Result hash', + shortenHash(this.runResult.snapshot.resultHash), + ), + metricCard('Tape hash', shortenHash(this.runResult.snapshot.tapeHash)), + metricCard( + 'engineBuildHash', + shortenHash(this.runResult.runtimeMetadata.engineBuildHash), + ), + metricCard( + 'gasVersion', + this.runResult.runtimeMetadata.gasVersion?.toString() ?? '—', + ), + ].join(''); + } + + private renderTabPanel(): void { + const mount = this.root.querySelector('[data-tab-panel]'); + if (!mount || !this.data) { + return; + } + + const selection = this.currentGalleryEntry(); + const redFixture = this.currentRedFixture(); + const evidenceKey = + this.selection?.type === 'gallery' || this.selection?.type === 'red' + ? this.selection.id + : ''; + const evidence = this.data.evidence.evidence[evidenceKey]; + const boundary = + this.boundaryOverride ?? + (evidenceKey ? this.data.oog.boundaries[evidenceKey] : undefined); + + if (this.activeTab === 'help') { + const links = selection?.docsLinks ?? redFixture?.docsLinks ?? []; + mount.innerHTML = ` +
+ `; + return; + } + + if (this.activeTab === 'metadata') { + const runtimeMetadata = this.runResult?.runtimeMetadata; + mount.innerHTML = ` +
+
${toPrettyJson({
+            selection: selection ??
+              redFixture ?? {
+                mode: this.mode,
+                scriptProfile: this.scriptProfile,
+              },
+            runtimeMetadata,
+            certifiedBoundary: boundary ?? null,
+          })}
+
+ `; + return; + } + + if (this.activeTab === 'host') { + mount.innerHTML = ` +
+

${ + selection?.hostSummary.description ?? + 'Host activity is captured through wrapped mock handlers plus tape hashes.' + }

+
${toPrettyJson(this.runResult?.hostEvents ?? [])}
+
+ `; + return; + } + + if (this.activeTab === 'evidence') { + if (redFixture) { + mount.innerHTML = ` +
+

Red fixtures teach deterministic failures instead of hiding them.

+
${toPrettyJson({
+              failureStage: redFixture.failureStage,
+              errorCode: redFixture.errorCode,
+              errorTag: redFixture.errorTag,
+              diagnostics: redFixture.diagnostics,
+            })}
+
+ `; + return; + } + + const comparison = this.runResult + ? compareAgainstEvidence(this.runResult, evidence) + : null; + mount.innerHTML = ` +
+
${toPrettyJson({
+            certifiedEvidence: evidence ?? null,
+            currentRun: this.runResult?.snapshot ?? null,
+            comparison,
+            certifiedBoundary: boundary ?? null,
+          })}
+
+ `; + return; + } + + mount.innerHTML = ` +
+
${toPrettyJson({
+          ok: this.runResult?.ok ?? null,
+          snapshot: this.runResult?.snapshot ?? null,
+          value: this.runResult?.value ?? null,
+          errorMessage: this.runResult?.errorMessage ?? null,
+        })}
+
+ `; + } + + private async runCurrentSelection(): Promise { + if (!this.data) { + return; + } + + try { + let artifact; + let manifest; + const gasLimit = BigInt( + this.root.querySelector('[data-gas-limit]')?.value ?? + '1000000', + ); + const selection = this.currentGalleryEntry(); + const redFixture = this.currentRedFixture(); + + if (this.mode === 'script') { + artifact = createScriptArtifact( + this.editor?.getValue() ?? '', + this.scriptProfile, + this.data.examples.metadata, + ); + manifest = defaultManifestForArtifact(artifact); + } else if (this.mode === 'artifact') { + this.artifactJson = this.editor?.getValue() ?? '{}'; + artifact = parseArtifactJson(this.artifactJson); + manifest = defaultManifestForArtifact(artifact); + } else if (selection) { + artifact = selection.program; + manifest = selection.manifest; + } else if (redFixture?.runtimeArtifact) { + artifact = redFixture.runtimeArtifact; + manifest = defaultManifestForArtifact(artifact); + } else { + return; + } + + this.runResult = await runArtifact({ + artifact, + manifest, + gasLimit, + hostPreset: this.hostPreset, + }); + this.activeTab = this.runResult.ok ? 'result' : 'evidence'; + this.updatePanels(); + } catch (error) { + this.runResult = { + ok: false, + snapshot: { + stage: 'artifact_validation', + resultHash: null, + errorCode: 'PROGRAM_ARTIFACT_INVALID', + errorTag: 'vm/module_pack', + gasUsed: '0', + gasRemaining: '0', + tapeHash: null, + tapeLength: 0, + }, + value: null, + errorMessage: error instanceof Error ? error.message : String(error), + hostEvents: [], + tape: [], + runtimeMetadata: { + engineBuildHash: this.data.examples.metadata.engineBuildHash, + gasVersion: this.data.examples.metadata.gasVersion, + executionProfile: this.scriptProfile, + sourceKind: 'script', + abiId: this.hostPreset === 'certification' ? 'Host.v2' : 'Host.v1', + moduleGraphHash: null, + }, + }; + this.activeTab = 'evidence'; + this.updatePanels(); + } + } + + private async findBoundary(): Promise { + if (!this.data) { + return; + } + + let artifact; + let manifest; + const initialGasLimit = BigInt( + this.root.querySelector('[data-gas-limit]')?.value ?? + '1000000', + ); + const selection = this.currentGalleryEntry(); + const redFixture = this.currentRedFixture(); + + if (this.mode === 'script') { + artifact = createScriptArtifact( + this.editor?.getValue() ?? '', + this.scriptProfile, + this.data.examples.metadata, + ); + manifest = defaultManifestForArtifact(artifact); + } else if (this.mode === 'artifact') { + artifact = parseArtifactJson(this.editor?.getValue() ?? '{}'); + manifest = defaultManifestForArtifact(artifact); + } else if (selection) { + artifact = selection.program; + manifest = selection.manifest; + } else if (redFixture?.runtimeArtifact) { + artifact = redFixture.runtimeArtifact; + manifest = defaultManifestForArtifact(artifact); + } else { + return; + } + + this.boundaryOverride = await findOogBoundary({ + artifact, + manifest, + hostPreset: this.hostPreset, + initialGasLimit, + }); + this.activeTab = 'evidence'; + this.updatePanels(); + } + + private exportArtifact(): void { + if (!this.data) { + return; + } + const selection = this.currentGalleryEntry(); + const redFixture = this.currentRedFixture(); + let artifactContent = '{}\n'; + if (this.mode === 'artifact') { + artifactContent = this.editor?.getValue() ?? '{}\n'; + } else if (this.mode === 'script') { + artifactContent = toPrettyJson( + createScriptArtifact( + this.editor?.getValue() ?? '', + this.scriptProfile, + this.data.examples.metadata, + ), + ); + } else if (selection) { + artifactContent = toPrettyJson(selection.program); + } else if (redFixture?.runtimeArtifact) { + artifactContent = toPrettyJson(redFixture.runtimeArtifact); + } + downloadFile('bluequickjs-artifact.json', artifactContent); + } + + private exportEvidence(): void { + const payload = toPrettyJson({ + selection: this.selection, + runResult: this.runResult, + boundary: this.boundaryOverride, + }); + downloadFile('bluequickjs-run-evidence.json', payload); + } +} + +function metricCard(label: string, value: string): string { + return ` +
+ ${label} + ${value} +
+ `; +} + +function downloadFile(filename: string, contents: string): void { + const blob = new Blob([contents], { type: 'application/json' }); + const url = URL.createObjectURL(blob); + const anchor = document.createElement('a'); + anchor.href = url; + anchor.download = filename; + anchor.click(); + URL.revokeObjectURL(url); +} diff --git a/apps/bluequickjs-playground/src/app/runtime.spec.ts b/apps/bluequickjs-playground/src/app/runtime.spec.ts new file mode 100644 index 0000000..c081fb5 --- /dev/null +++ b/apps/bluequickjs-playground/src/app/runtime.spec.ts @@ -0,0 +1,93 @@ +import { HOST_V1_HASH, HOST_V2_HASH } from '@blue-quickjs/abi-manifest'; +import { + compareAgainstEvidence, + createScriptArtifact, + defaultManifestForArtifact, + parseArtifactJson, +} from './runtime.js'; + +describe('playground runtime helpers', () => { + const metadata = { + engineBuildHash: 'a'.repeat(64), + gasVersion: 8, + wasmVariant: 'wasm32', + wasmBuildType: 'release', + }; + + it('creates baseline script artifacts against Host.v1', () => { + const artifact = createScriptArtifact( + '(() => 1)();', + 'baseline-v1', + metadata, + ); + expect(artifact.abiId).toBe('Host.v1'); + expect(artifact.abiManifestHash).toBe(HOST_V1_HASH); + expect(artifact.engineBuildHash).toBe(metadata.engineBuildHash); + }); + + it('creates binary script artifacts against Host.v2', () => { + const artifact = createScriptArtifact( + '(() => Host.v2.document.get("bytes/payload"))();', + 'compat-binary-v1', + metadata, + ); + expect(artifact.abiId).toBe('Host.v2'); + expect(artifact.abiManifestHash).toBe(HOST_V2_HASH); + expect(defaultManifestForArtifact(artifact).abi_id).toBe('Host.v2'); + }); + + it('parses artifact json through runtime validation', () => { + const artifact = createScriptArtifact( + '(() => 1)();', + 'baseline-v1', + metadata, + ); + expect(parseArtifactJson(JSON.stringify(artifact))).toEqual(artifact); + }); + + it('compares run snapshots against certified evidence', () => { + const result = compareAgainstEvidence( + { + ok: true, + snapshot: { + stage: 'success', + resultHash: 'a', + errorCode: null, + errorTag: null, + gasUsed: '10', + gasRemaining: '90', + tapeHash: null, + tapeLength: 0, + }, + value: 1, + errorMessage: null, + hostEvents: [], + tape: [], + runtimeMetadata: { + engineBuildHash: metadata.engineBuildHash, + gasVersion: 8, + executionProfile: 'baseline-v1', + sourceKind: 'script', + abiId: 'Host.v1', + moduleGraphHash: null, + }, + }, + { + stage: 'success', + resultHash: 'a', + errorCode: null, + errorTag: null, + gasUsed: '10', + gasRemaining: '90', + tapeHash: null, + tapeLength: 0, + certified: true, + reportSource: 'fixture', + fixtureCoverage: [], + }, + ); + + expect(result.matches).toBe(true); + expect(result.differences).toEqual([]); + }); +}); diff --git a/apps/bluequickjs-playground/src/app/runtime.ts b/apps/bluequickjs-playground/src/app/runtime.ts new file mode 100644 index 0000000..41d2c58 --- /dev/null +++ b/apps/bluequickjs-playground/src/app/runtime.ts @@ -0,0 +1,497 @@ +import { + HOST_V1_HASH, + HOST_V1_MANIFEST, + HOST_V2_HASH, + HOST_V2_MANIFEST, + type AbiManifest, +} from '@blue-quickjs/abi-manifest'; +import { type DV2, encodeDv2 } from '@blue-quickjs/dv'; +import type { + HostCallResult, + HostDispatcherHandlers, + ProgramArtifactV2, +} from '@blue-quickjs/quickjs-runtime'; +import { + evaluate, + validateProgramArtifactV2, +} from '@blue-quickjs/quickjs-runtime'; +import { + loadQuickjsWasmBinary, + loadQuickjsWasmMetadata, +} from '@blue-quickjs/quickjs-wasm'; +import { + DETERMINISM_INPUT, + createDeterminismHost, + serializeHostTape, +} from '@blue-quickjs/test-harness'; +import type { + EvidencePayload, + HostEvent, + HostPresetId, + LoadedPlaygroundData, + OogPayload, + PlaygroundRunResult, + RunSnapshot, +} from './types.js'; + +const CERTIFICATION_INPUT = { + event: { type: 'ecosystem-certifier' }, + eventCanonical: { type: 'ecosystem-certifier' }, + steps: [], + currentContract: { id: 'ecosystem-certifier' }, + currentContractCanonical: { id: { value: 'ecosystem-certifier' } }, +}; + +const CERT_TEXT_DOCUMENTS = new Map([ + [ + 'pack/metadata.json', + JSON.stringify( + { + packId: 'kp-2026-rc', + release: '1.2.3', + requires: ['>=1.2.0 <2.0.0', '^1.2.0'], + links: ['docs/a.md', 'docs/b.md', 'docs/c.md', 'docs/d.md'], + }, + null, + 2, + ), + ], + [ + 'pack/metadata.yaml', + [ + 'packId: kp-2026-rc', + 'release: 1.2.3', + 'requires:', + ' - ">=1.2.0 <2.0.0"', + ' - "^1.2.0"', + 'links:', + ' - docs/a.md', + ' - docs/b.md', + '', + ].join('\n'), + ], + ['docs/a.md', '# Alpha\n\nSee [Beta](docs/b.md).\n'], + ['docs/b.md', '# Beta\n\nBacklink to [Alpha](docs/a.md).\n'], + ['docs/c.md', '# Gamma\n\nCross-link to [Delta](docs/d.md).\n'], + ['docs/d.md', '# Delta\n\nBack to [Alpha](docs/a.md).\n'], + ['text/semver-case', '1.2.3'], +]); + +const CERT_BINARY_DOCUMENTS = new Map([ + [ + 'bytes/payload', + Uint8Array.from( + Array.from({ length: 64 }, (_, index) => (index * 17) % 251), + ), + ], + [ + 'bytes/flagship-extra', + Uint8Array.from( + Array.from({ length: 192 }, (_, index) => (index * 29 + 11) % 251), + ), + ], +]); + +let runtimeAssetsPromise: + | Promise<{ + metadata: Awaited>; + wasmBinary: Uint8Array; + }> + | undefined; + +export async function loadPlaygroundData(): Promise { + const [examples, evidence, oog, red] = await Promise.all([ + loadJson('/generated/playground-examples.json'), + loadJson('/generated/playground-evidence.json'), + loadJson('/generated/playground-oog-boundaries.json'), + loadJson('/generated/playground-red-fixtures.json'), + ]); + + return { + examples, + evidence, + oog, + red, + } as LoadedPlaygroundData; +} + +export async function getRuntimeAssets() { + if (!runtimeAssetsPromise) { + runtimeAssetsPromise = (async () => { + const metadata = await loadQuickjsWasmMetadata(); + const wasmBinary = await loadQuickjsWasmBinary( + 'wasm32', + 'release', + metadata, + ); + return { metadata, wasmBinary }; + })(); + } + return runtimeAssetsPromise; +} + +export async function runArtifact(options: { + artifact: ProgramArtifactV2; + manifest: AbiManifest; + gasLimit: bigint; + hostPreset: HostPresetId; +}): Promise { + const { metadata, wasmBinary } = await getRuntimeAssets(); + const host = createWrappedHost(options.hostPreset); + const result = await evaluate({ + program: options.artifact, + input: + options.hostPreset === 'certification' + ? CERTIFICATION_INPUT + : DETERMINISM_INPUT, + gasLimit: options.gasLimit, + manifest: options.manifest, + handlers: host.handlers, + tape: { capacity: 128 }, + metadata, + wasmBinary, + releaseMode: true, + expectedExecutionProfile: options.artifact.executionProfile, + }); + + return { + ok: result.ok, + snapshot: await toSnapshot(result), + value: result.ok ? result.value : null, + errorMessage: result.ok ? null : result.message, + hostEvents: host.events, + tape: result.tape ?? [], + runtimeMetadata: { + engineBuildHash: + metadata.variants?.wasm32?.release?.engineBuildHash ?? + metadata.engineBuildHash ?? + null, + gasVersion: metadata.gasVersion ?? null, + executionProfile: options.artifact.executionProfile, + sourceKind: options.artifact.sourceKind, + abiId: options.artifact.abiId, + moduleGraphHash: getModuleGraphHash(options.artifact), + }, + }; +} + +export async function findOogBoundary(options: { + artifact: ProgramArtifactV2; + manifest: AbiManifest; + hostPreset: HostPresetId; + initialGasLimit: bigint; +}): Promise { + let upperGas = options.initialGasLimit; + let upper = await runArtifact({ + artifact: options.artifact, + manifest: options.manifest, + gasLimit: upperGas, + hostPreset: options.hostPreset, + }); + + while (!upper.ok) { + upperGas *= 2n; + upper = await runArtifact({ + artifact: options.artifact, + manifest: options.manifest, + gasLimit: upperGas, + hostPreset: options.hostPreset, + }); + } + + let lowerGas = 0n; + let lower = await runArtifact({ + artifact: options.artifact, + manifest: options.manifest, + gasLimit: lowerGas, + hostPreset: options.hostPreset, + }); + + while (lowerGas + 1n < upperGas) { + const mid = (lowerGas + upperGas) >> 1n; + const current = await runArtifact({ + artifact: options.artifact, + manifest: options.manifest, + gasLimit: mid, + hostPreset: options.hostPreset, + }); + if (current.ok) { + upperGas = mid; + upper = current; + } else { + lowerGas = mid; + lower = current; + } + } + + return { + firstSuccessGas: upperGas.toString(), + lastFailureGas: lowerGas.toString(), + successGasUsed: upper.snapshot.gasUsed, + successGasRemaining: upper.snapshot.gasRemaining, + failureGasUsed: lower.snapshot.gasUsed, + failureGasRemaining: lower.snapshot.gasRemaining, + failureCode: lower.snapshot.errorCode, + failureTag: lower.snapshot.errorTag, + }; +} + +export function createScriptArtifact( + code: string, + profile: ProgramArtifactV2['executionProfile'], + metadata: LoadedPlaygroundData['examples']['metadata'], +): ProgramArtifactV2 { + const binary = profile === 'compat-binary-v1'; + return { + version: 2, + abiId: binary ? 'Host.v2' : 'Host.v1', + abiVersion: binary ? 2 : 1, + abiManifestHash: binary ? HOST_V2_HASH : HOST_V1_HASH, + ...(metadata.engineBuildHash + ? { engineBuildHash: metadata.engineBuildHash } + : {}), + ...(metadata.gasVersion !== null + ? { gasVersion: metadata.gasVersion } + : {}), + executionProfile: profile, + sourceKind: 'script', + source: { code }, + }; +} + +export function defaultManifestForArtifact( + artifact: ProgramArtifactV2, +): AbiManifest { + return artifact.abiId === 'Host.v2' ? HOST_V2_MANIFEST : HOST_V1_MANIFEST; +} + +export function parseArtifactJson(text: string): ProgramArtifactV2 { + return validateProgramArtifactV2(JSON.parse(text)); +} + +export function compareAgainstEvidence( + run: PlaygroundRunResult, + evidence: EvidencePayload['evidence'][string] | undefined, +) { + if (!evidence) { + return { + available: false, + matches: false, + differences: [], + }; + } + + const differences = [ + ['stage', run.snapshot.stage, evidence.stage], + ['resultHash', run.snapshot.resultHash, evidence.resultHash], + ['errorCode', run.snapshot.errorCode, evidence.errorCode], + ['errorTag', run.snapshot.errorTag, evidence.errorTag], + ['gasUsed', run.snapshot.gasUsed, evidence.gasUsed], + ['gasRemaining', run.snapshot.gasRemaining, evidence.gasRemaining], + ['tapeHash', run.snapshot.tapeHash, evidence.tapeHash], + ['tapeLength', run.snapshot.tapeLength, evidence.tapeLength], + ].filter(([, actual, expected]) => actual !== expected); + + return { + available: true, + matches: differences.length === 0, + differences, + }; +} + +function createWrappedHost(hostPreset: HostPresetId): { + handlers: HostDispatcherHandlers; + events: HostEvent[]; +} { + const base = + hostPreset === 'certification' + ? createInlineCertificationHost() + : createDeterminismHost(); + const events: HostEvent[] = []; + + const handlers: HostDispatcherHandlers = { + document: { + get: (docPath: string): HostCallResult => { + const result = base.handlers.document.get(docPath); + events.push({ + fn: 'document.get', + request: docPath, + response: previewHostResult(result), + units: result.units, + }); + return result; + }, + getCanonical: (docPath: string): HostCallResult => { + const result = base.handlers.document.getCanonical(docPath); + events.push({ + fn: 'document.getCanonical', + request: docPath, + response: previewHostResult(result), + units: result.units, + }); + return result; + }, + }, + }; + + const emitHandler = base.handlers.emit; + if (emitHandler) { + handlers.emit = (value: DV2): HostCallResult => { + const result = emitHandler(value); + events.push({ + fn: 'emit', + request: previewValue(value), + response: previewHostResult(result), + units: result.units, + }); + return result; + }; + } + + return { handlers, events }; +} + +function createInlineCertificationHost(): { + handlers: HostDispatcherHandlers; + emitted: DV2[]; +} { + const emitted: DV2[] = []; + return { + emitted, + handlers: { + document: { + get: (docPath: string): HostCallResult => { + const binaryDoc = CERT_BINARY_DOCUMENTS.get(docPath); + if (binaryDoc) { + return { ok: binaryDoc, units: 6 }; + } + const textDoc = CERT_TEXT_DOCUMENTS.get(docPath); + if (textDoc) { + return { ok: textDoc, units: 2 }; + } + return { + err: { code: 'NOT_FOUND', tag: 'host/not_found' }, + units: 1, + }; + }, + getCanonical: (docPath: string): HostCallResult => { + const textDoc = CERT_TEXT_DOCUMENTS.get(docPath); + if (textDoc) { + return { ok: textDoc, units: 2 }; + } + const binaryDoc = CERT_BINARY_DOCUMENTS.get(docPath); + if (binaryDoc) { + return { ok: binaryDoc, units: 6 }; + } + return { + err: { code: 'NOT_FOUND', tag: 'host/not_found' }, + units: 1, + }; + }, + }, + emit: (value: DV2): HostCallResult => { + emitted.push(value); + return { ok: null, units: 1 }; + }, + }, + }; +} + +function previewHostResult(result: HostCallResult): unknown { + if ('ok' in result) { + return { ok: previewValue(result.ok), units: result.units }; + } + return { err: result.err, units: result.units }; +} + +function previewValue(value: unknown): unknown { + if (value instanceof Uint8Array) { + return { + type: 'Uint8Array', + length: value.byteLength, + hexPreview: Array.from(value.slice(0, 16)) + .map((byte) => byte.toString(16).padStart(2, '0')) + .join(''), + }; + } + return value; +} + +async function toSnapshot( + result: Awaited>, +): Promise { + const tape = result.tape ?? []; + const tapeHash = + tape.length > 0 ? await sha256Hex(serializeHostTape(tape)) : null; + if (result.ok) { + return { + stage: 'success', + resultHash: await sha256Hex(encodeDv2(result.value)), + errorCode: null, + errorTag: null, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + tapeHash, + tapeLength: tape.length, + }; + } + return { + stage: normalizeFailureStage(result.error.kind), + resultHash: null, + errorCode: result.error.code, + errorTag: 'tag' in result.error ? result.error.tag : null, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + tapeHash, + tapeLength: tape.length, + }; +} + +function normalizeFailureStage(kind: string): RunSnapshot['stage'] { + if (kind === 'module-pack') { + return 'artifact_validation'; + } + if (kind === 'execution-surface-mismatch') { + return 'pin_enforcement'; + } + return 'runtime_error'; +} + +function getModuleGraphHash(artifact: ProgramArtifactV2): string | null { + if (artifact.sourceKind !== 'module-pack') { + return null; + } + return 'modulePack' in artifact.source + ? artifact.source.modulePack.graphHash + : null; +} + +async function sha256Hex(input: Uint8Array | string): Promise { + const bytes = + typeof input === 'string' ? new TextEncoder().encode(input) : input; + const digest = await crypto.subtle.digest('SHA-256', toArrayBuffer(bytes)); + return Array.from(new Uint8Array(digest)) + .map((byte) => byte.toString(16).padStart(2, '0')) + .join(''); +} + +function toArrayBuffer(bytes: Uint8Array): ArrayBuffer { + if ( + bytes.byteOffset === 0 && + bytes.byteLength === bytes.buffer.byteLength && + bytes.buffer instanceof ArrayBuffer + ) { + return bytes.buffer; + } + return bytes.slice().buffer; +} + +async function loadJson(url: string): Promise { + const response = await fetch(url); + if (!response.ok) { + throw new Error( + `Failed to load ${url}: ${response.status} ${response.statusText}`, + ); + } + return response.json(); +} diff --git a/apps/bluequickjs-playground/src/app/state.spec.ts b/apps/bluequickjs-playground/src/app/state.spec.ts new file mode 100644 index 0000000..27aa518 --- /dev/null +++ b/apps/bluequickjs-playground/src/app/state.spec.ts @@ -0,0 +1,141 @@ +import { + getInitialExample, + getProfileSummary, + groupExamples, +} from './state.js'; +import type { LoadedPlaygroundData } from './types.js'; + +const DATA = { + examples: { + generatedAt: '2026-03-21T00:00:00.000Z', + metadata: { + engineBuildHash: 'a'.repeat(64), + gasVersion: 8, + wasmVariant: 'wasm32', + wasmBuildType: 'release', + }, + examples: [ + { + id: 'example-basic-script', + title: 'Basic deterministic script', + kind: 'example', + badge: 'Example 1', + description: 'Basic deterministic script', + certified: true, + executionProfile: 'baseline-v1', + sourceKind: 'script', + abiId: 'Host.v1', + gasLimit: '1000000', + sourcePaths: ['examples/01-basic-script/program.js'], + sourceText: '(() => 1)();', + hostPreset: 'determinism', + hostSummary: { + label: 'Determinism fixture host', + description: 'stable host', + documents: [], + }, + docsLinks: [], + supportsOogSearch: true, + program: { + version: 2, + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: 'b'.repeat(64), + engineBuildHash: 'a'.repeat(64), + gasVersion: 8, + executionProfile: 'baseline-v1', + sourceKind: 'script', + source: { code: '(() => 1)();' }, + }, + manifest: { + abi_id: 'Host.v1', + abi_version: 1, + functions: [], + }, + }, + { + id: 'green-semver', + title: 'semver', + kind: 'ecosystem-green', + badge: 'Green ecosystem fixture', + description: 'semver fixture', + certified: true, + executionProfile: 'compat-general-v1', + sourceKind: 'module-pack', + abiId: 'Host.v1', + gasLimit: '1000000', + sourcePaths: [ + 'apps/ecosystem-certifier/fixtures/positive/semver-entry.ts', + ], + sourceText: 'export default 1;', + hostPreset: 'certification', + hostSummary: { + label: 'Certification host', + description: 'cert host', + documents: [], + }, + docsLinks: [], + supportsOogSearch: false, + program: { + version: 2, + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: 'b'.repeat(64), + engineBuildHash: 'a'.repeat(64), + gasVersion: 8, + executionProfile: 'compat-general-v1', + sourceKind: 'module-pack', + source: { + modulePack: { + version: 1, + entrySpecifier: './entry.js', + modules: [], + graphHash: 'c'.repeat(64), + builderVersion: 'deterministic-builder-v1', + dependencyIntegrity: 'd'.repeat(64), + }, + }, + }, + manifest: { + abi_id: 'Host.v1', + abi_version: 1, + functions: [], + }, + }, + ], + }, + evidence: { + generatedAt: '', + metadata: { engineBuildHash: 'a'.repeat(64), gasVersion: 8 }, + evidence: {}, + }, + oog: { + generatedAt: '', + metadata: { engineBuildHash: 'a'.repeat(64), gasVersion: 8 }, + boundaries: {}, + }, + red: { + generatedAt: '', + metadata: { engineBuildHash: 'a'.repeat(64), gasVersion: 8 }, + fixtures: [], + }, +} satisfies LoadedPlaygroundData; + +describe('playground state helpers', () => { + it('returns the first example as initial selection', () => { + expect(getInitialExample(DATA).id).toBe('example-basic-script'); + }); + + it('groups gallery entries by kind', () => { + const groups = groupExamples(DATA.examples.examples); + expect(groups.example).toHaveLength(1); + expect(groups['ecosystem-green']).toHaveLength(1); + }); + + it('summarizes profile capabilities', () => { + expect(getProfileSummary('baseline-v1')).toContain( + 'Minimal consensus baseline', + ); + expect(getProfileSummary('compat-general-v1')).toContain('promiseJobs'); + }); +}); diff --git a/apps/bluequickjs-playground/src/app/state.ts b/apps/bluequickjs-playground/src/app/state.ts new file mode 100644 index 0000000..b484cb6 --- /dev/null +++ b/apps/bluequickjs-playground/src/app/state.ts @@ -0,0 +1,42 @@ +import { + getExecutionProfileCapabilities, + type PublicExecutionProfile, +} from '@blue-quickjs/execution-profiles'; +import type { + GalleryEntry, + LoadedPlaygroundData, + RedFixtureRecord, +} from './types.js'; + +export type RunMode = 'gallery' | 'script' | 'artifact'; + +export type ResultTab = 'result' | 'evidence' | 'host' | 'metadata' | 'help'; + +export function getInitialExample(data: LoadedPlaygroundData): GalleryEntry { + return data.examples.examples[0]; +} + +export function groupExamples( + entries: GalleryEntry[], +): Record { + return entries.reduce>((groups, entry) => { + const key = entry.kind; + groups[key] ??= []; + groups[key].push(entry); + return groups; + }, {}); +} + +export function getProfileSummary(profile: PublicExecutionProfile): string { + const capabilities = getExecutionProfileCapabilities(profile); + if (capabilities.length === 0) { + return 'Minimal consensus baseline with no Promise jobs or binary APIs.'; + } + return capabilities.join(', '); +} + +export function getRedFixtureMap( + redFixtures: RedFixtureRecord[], +): Map { + return new Map(redFixtures.map((fixture) => [fixture.id, fixture])); +} diff --git a/apps/bluequickjs-playground/src/app/types.ts b/apps/bluequickjs-playground/src/app/types.ts new file mode 100644 index 0000000..121f2d4 --- /dev/null +++ b/apps/bluequickjs-playground/src/app/types.ts @@ -0,0 +1,161 @@ +import type { AbiManifest } from '@blue-quickjs/abi-manifest'; +import type { PublicExecutionProfile } from '@blue-quickjs/execution-profiles'; +import type { ProgramArtifactV2 } from '@blue-quickjs/quickjs-runtime'; + +export type HostPresetId = 'determinism' | 'certification'; + +export interface DocsLink { + label: string; + href: string; +} + +export interface HostSummary { + label: string; + description: string; + documents: string[]; +} + +export interface GalleryEntry { + id: string; + title: string; + kind: 'example' | 'ecosystem-green' | 'flagship'; + badge: string; + description: string; + certified: boolean; + executionProfile: PublicExecutionProfile; + sourceKind: ProgramArtifactV2['sourceKind']; + abiId: string; + gasLimit: string; + sourcePaths: string[]; + sourceText: string; + hostPreset: HostPresetId; + hostSummary: HostSummary; + docsLinks: DocsLink[]; + supportsOogSearch: boolean; + program: ProgramArtifactV2; + manifest: AbiManifest; +} + +export interface EvidenceRecord { + stage: string; + resultHash: string | null; + errorCode: string | null; + errorTag: string | null; + gasUsed: string; + gasRemaining: string; + tapeHash: string | null; + tapeLength: number; + certified: boolean; + reportSource: string; + fixtureCoverage: Array<{ suite: string; fixtureName: string }>; +} + +export interface OogBoundaryRecord { + firstSuccessGas: string; + lastFailureGas: string; + successGasUsed: string; + successGasRemaining: string; + failureGasUsed: string; + failureGasRemaining: string; + failureCode: string | null; + failureTag: string | null; +} + +export interface RedFixtureRecord { + id: string; + title: string; + kind: string; + executionProfile: PublicExecutionProfile; + failureStage: string; + errorCode: string | null; + errorTag: string | null; + certified: boolean; + docsLinks: DocsLink[]; + diagnostics: Array<{ filePath: string; ruleId: string; message: string }>; + runtimeArtifact: ProgramArtifactV2 | null; + reportSource: string; +} + +export interface ExamplesPayload { + generatedAt: string; + metadata: { + engineBuildHash: string | null; + gasVersion: number | null; + wasmVariant: string; + wasmBuildType: string; + }; + examples: GalleryEntry[]; +} + +export interface EvidencePayload { + generatedAt: string; + metadata: { + engineBuildHash: string | null; + gasVersion: number | null; + }; + evidence: Record; +} + +export interface OogPayload { + generatedAt: string; + metadata: { + engineBuildHash: string | null; + gasVersion: number | null; + }; + boundaries: Record; +} + +export interface RedPayload { + generatedAt: string; + metadata: { + engineBuildHash: string | null; + gasVersion: number | null; + }; + fixtures: RedFixtureRecord[]; +} + +export interface LoadedPlaygroundData { + examples: ExamplesPayload; + evidence: EvidencePayload; + oog: OogPayload; + red: RedPayload; +} + +export interface RunSnapshot { + stage: + | 'success' + | 'artifact_validation' + | 'runtime_error' + | 'pin_enforcement'; + resultHash: string | null; + errorCode: string | null; + errorTag: string | null; + gasUsed: string; + gasRemaining: string; + tapeHash: string | null; + tapeLength: number; +} + +export interface HostEvent { + fn: 'document.get' | 'document.getCanonical' | 'emit'; + request: unknown; + response: unknown; + units: number; +} + +export interface PlaygroundRunResult { + ok: boolean; + snapshot: RunSnapshot; + value: unknown | null; + errorMessage: string | null; + hostEvents: HostEvent[]; + tape: unknown[]; + runtimeMetadata: { + engineBuildHash: string | null; + gasVersion: number | null; + executionProfile: PublicExecutionProfile; + sourceKind: ProgramArtifactV2['sourceKind']; + abiId: string; + moduleGraphHash: string | null; + }; +} diff --git a/apps/bluequickjs-playground/src/design/theme.css b/apps/bluequickjs-playground/src/design/theme.css new file mode 100644 index 0000000..07e8b4e --- /dev/null +++ b/apps/bluequickjs-playground/src/design/theme.css @@ -0,0 +1,33 @@ +:root { + --bq-font-sans: 'Roboto', 'Inter', 'Helvetica Neue', Arial, sans-serif; + --bq-font-mono: 'Roboto Mono', 'SFMono-Regular', Consolas, monospace; + + --bq-color-canvas: #f4f7fb; + --bq-color-surface: #ffffff; + --bq-color-surface-muted: #f8fafc; + --bq-color-border: #d8e1ec; + --bq-color-border-strong: #c1cedc; + --bq-color-text: #14213d; + --bq-color-text-muted: #5c6b80; + --bq-color-accent: #1f6fff; + --bq-color-accent-soft: #e7f0ff; + --bq-color-success: #0f9f65; + --bq-color-warning: #b7791f; + --bq-color-danger: #d14343; + --bq-color-code-bg: #0f172a; + --bq-color-code-text: #e2e8f0; + + --bq-radius-xs: 10px; + --bq-radius-sm: 14px; + --bq-radius-md: 18px; + --bq-radius-pill: 999px; + + --bq-shadow-sm: 0 8px 24px rgba(20, 33, 61, 0.06); + --bq-shadow-md: 0 18px 48px rgba(20, 33, 61, 0.08); + + --bq-space-xs: 8px; + --bq-space-sm: 12px; + --bq-space-md: 16px; + --bq-space-lg: 24px; + --bq-space-xl: 32px; +} diff --git a/apps/bluequickjs-playground/src/design/tokens.ts b/apps/bluequickjs-playground/src/design/tokens.ts new file mode 100644 index 0000000..93a7c4e --- /dev/null +++ b/apps/bluequickjs-playground/src/design/tokens.ts @@ -0,0 +1,35 @@ +export const TOKENS = { + colors: { + canvas: '#f4f7fb', + surface: '#ffffff', + surfaceMuted: '#f8fafc', + border: '#d8e1ec', + borderStrong: '#c1cedc', + text: '#14213d', + textMuted: '#5c6b80', + accent: '#1f6fff', + accentSoft: '#e7f0ff', + success: '#0f9f65', + warning: '#b7791f', + danger: '#d14343', + codeBg: '#0f172a', + codeText: '#e2e8f0', + }, + radius: { + xs: '10px', + sm: '14px', + md: '18px', + pill: '999px', + }, + shadow: { + sm: '0 8px 24px rgba(20, 33, 61, 0.06)', + md: '0 18px 48px rgba(20, 33, 61, 0.08)', + }, + spacing: { + xs: '8px', + sm: '12px', + md: '16px', + lg: '24px', + xl: '32px', + }, +} as const; diff --git a/apps/bluequickjs-playground/src/main.ts b/apps/bluequickjs-playground/src/main.ts new file mode 100644 index 0000000..1419b1d --- /dev/null +++ b/apps/bluequickjs-playground/src/main.ts @@ -0,0 +1,11 @@ +import './styles.css'; +import { PlaygroundApp } from './app/playground-app.js'; + +const root = document.getElementById('app'); + +if (!root) { + throw new Error('Missing #app root for BlueQuickjs Playground'); +} + +const app = new PlaygroundApp(root); +void app.init(); diff --git a/apps/bluequickjs-playground/src/styles.css b/apps/bluequickjs-playground/src/styles.css new file mode 100644 index 0000000..78d9b91 --- /dev/null +++ b/apps/bluequickjs-playground/src/styles.css @@ -0,0 +1,421 @@ +@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&family=Roboto+Mono:wght@400;500&display=swap'); +@import './design/theme.css'; + +* { + box-sizing: border-box; +} + +html, +body { + margin: 0; + min-height: 100%; + background: var(--bq-color-canvas); + color: var(--bq-color-text); + font-family: var(--bq-font-sans); +} + +body { + min-height: 100vh; +} + +a { + color: var(--bq-color-accent); +} + +button, +input, +select, +textarea { + font: inherit; +} + +#app { + min-height: 100vh; +} + +.bq-loading { + display: grid; + min-height: 100vh; + place-items: center; + color: var(--bq-color-text-muted); +} + +.bq-shell { + max-width: 1480px; + margin: 0 auto; + padding: var(--bq-space-xl); + display: grid; + gap: var(--bq-space-lg); +} + +.card { + background: var(--bq-color-surface); + border: 1px solid var(--bq-color-border); + border-radius: var(--bq-radius-md); + box-shadow: var(--bq-shadow-sm); +} + +.bq-hero { + padding: var(--bq-space-xl); + display: grid; + gap: var(--bq-space-md); +} + +.bq-brand { + display: flex; + align-items: center; + gap: var(--bq-space-md); +} + +.bq-logo { + width: 44px; + height: 44px; + border-radius: 14px; + display: grid; + place-items: center; + background: linear-gradient(135deg, var(--bq-color-accent), #2f8cff); + color: white; + font-weight: 700; + font-size: 22px; +} + +.eyebrow { + margin: 0; + font-size: 12px; + letter-spacing: 0.08em; + text-transform: uppercase; + color: var(--bq-color-text-muted); +} + +h1, +h2, +h3, +p { + margin: 0; +} + +h1 { + font-size: 36px; + line-height: 1.1; +} + +h2 { + font-size: 20px; + line-height: 1.2; +} + +h3 { + font-size: 15px; +} + +.lede, +.section-heading p, +.panel-note, +.field-help, +.gallery-item span, +.meta-strip, +.stack { + color: var(--bq-color-text-muted); +} + +.hero-chips, +.chip-row, +.preset-row, +.button-row, +.meta-strip, +.tab-row { + display: flex; + flex-wrap: wrap; + gap: var(--bq-space-sm); +} + +.chip { + display: inline-flex; + align-items: center; + min-height: 34px; + padding: 0 12px; + border-radius: var(--bq-radius-pill); + border: 1px solid var(--bq-color-border); + background: var(--bq-color-surface-muted); + color: var(--bq-color-text); + font-size: 13px; +} + +.chip.accent { + background: var(--bq-color-accent-soft); + border-color: #c6dafd; + color: var(--bq-color-accent); +} + +.chip.status { + font-weight: 600; +} + +.bq-layout { + display: grid; + grid-template-columns: minmax(320px, 380px) minmax(0, 1fr); + gap: var(--bq-space-lg); +} + +.bq-sidebar, +.bq-main { + display: grid; + gap: var(--bq-space-lg); +} + +.controls-card, +.gallery-card, +.editor-card, +.results-card { + padding: var(--bq-space-lg); +} + +.section-heading { + display: grid; + gap: 6px; + margin-bottom: var(--bq-space-md); +} + +.section-heading.inline { + display: flex; + justify-content: space-between; + align-items: flex-start; + gap: var(--bq-space-md); +} + +.section-heading.tight { + margin-bottom: var(--bq-space-sm); +} + +.segmented { + display: inline-flex; + padding: 4px; + border-radius: var(--bq-radius-pill); + border: 1px solid var(--bq-color-border); + background: var(--bq-color-surface-muted); +} + +.segmented-button, +.tab-button, +.ghost-button, +.primary-button, +.gallery-item { + border: 1px solid transparent; + border-radius: var(--bq-radius-sm); + cursor: pointer; + transition: + background 120ms ease, + border-color 120ms ease, + box-shadow 120ms ease, + transform 120ms ease; +} + +.segmented-button, +.tab-button { + background: transparent; + color: var(--bq-color-text-muted); + padding: 10px 14px; +} + +.segmented-button[data-active='true'], +.tab-button[data-active='true'] { + background: var(--bq-color-surface); + color: var(--bq-color-text); + border-color: var(--bq-color-border); + box-shadow: var(--bq-shadow-sm); +} + +.field { + display: grid; + gap: 8px; + margin-top: var(--bq-space-md); +} + +.field span { + font-size: 13px; + font-weight: 500; +} + +.field input, +.field select { + min-height: 44px; + border-radius: var(--bq-radius-sm); + border: 1px solid var(--bq-color-border); + background: var(--bq-color-surface); + padding: 0 14px; + color: var(--bq-color-text); +} + +.ghost-button, +.primary-button { + min-height: 42px; + padding: 0 14px; +} + +.ghost-button { + background: var(--bq-color-surface-muted); + border-color: var(--bq-color-border); + color: var(--bq-color-text); +} + +.primary-button { + background: linear-gradient(135deg, var(--bq-color-accent), #2f8cff); + color: white; +} + +.gallery-group { + display: grid; + gap: var(--bq-space-sm); + margin-bottom: var(--bq-space-md); +} + +.gallery-list { + display: grid; + gap: var(--bq-space-sm); +} + +.gallery-item { + width: 100%; + text-align: left; + padding: var(--bq-space-md); + background: var(--bq-color-surface-muted); + border-color: var(--bq-color-border); + display: grid; + gap: 6px; +} + +.gallery-item.danger { + border-color: #f3c5c5; + background: #fff7f7; +} + +.divider { + height: 1px; + background: var(--bq-color-border); + margin: var(--bq-space-md) 0; +} + +.editor-toolbar { + display: flex; + justify-content: space-between; + gap: var(--bq-space-md); + margin-bottom: var(--bq-space-md); +} + +.editor-frame { + overflow: hidden; + min-height: 520px; + border-radius: var(--bq-radius-md); + border: 1px solid var(--bq-color-border); +} + +.meta-strip { + margin-bottom: var(--bq-space-md); +} + +.meta-strip span { + background: var(--bq-color-surface-muted); + border: 1px solid var(--bq-color-border); + padding: 8px 12px; + border-radius: var(--bq-radius-pill); + font-size: 13px; +} + +.metrics-grid { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: var(--bq-space-sm); + margin-bottom: var(--bq-space-md); +} + +.metric-card { + min-height: 90px; + padding: var(--bq-space-md); + border-radius: var(--bq-radius-sm); + border: 1px solid var(--bq-color-border); + background: var(--bq-color-surface-muted); + display: grid; + gap: 8px; +} + +.metric-card.empty { + grid-column: 1 / -1; +} + +.metric-label { + font-size: 12px; + text-transform: uppercase; + letter-spacing: 0.08em; + color: var(--bq-color-text-muted); +} + +.tab-row { + margin-bottom: var(--bq-space-md); +} + +.tab-panel pre { + margin: 0; + padding: var(--bq-space-md); + border-radius: var(--bq-radius-sm); + background: var(--bq-color-code-bg); + color: var(--bq-color-code-text); + font-family: var(--bq-font-mono); + font-size: 13px; + line-height: 1.5; + overflow: auto; + white-space: pre-wrap; + word-break: break-word; +} + +.stack { + display: grid; + gap: var(--bq-space-md); +} + +.link-list { + display: grid; + gap: var(--bq-space-sm); + padding-left: 18px; + margin: 0; +} + +button:hover, +select:hover, +input:hover { + border-color: var(--bq-color-border-strong); +} + +button:focus-visible, +select:focus-visible, +input:focus-visible { + outline: 3px solid rgba(31, 111, 255, 0.18); + outline-offset: 2px; +} + +@media (max-width: 1180px) { + .bq-layout { + grid-template-columns: 1fr; + } + + .metrics-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} + +@media (max-width: 760px) { + .bq-shell { + padding: var(--bq-space-md); + } + + .section-heading.inline { + flex-direction: column; + } + + .metrics-grid { + grid-template-columns: 1fr; + } + + .editor-frame { + min-height: 380px; + } +} diff --git a/apps/bluequickjs-playground/src/typings.d.ts b/apps/bluequickjs-playground/src/typings.d.ts new file mode 100644 index 0000000..d7dcc54 --- /dev/null +++ b/apps/bluequickjs-playground/src/typings.d.ts @@ -0,0 +1,9 @@ +declare global { + interface Window { + MonacoEnvironment?: { + getWorker(_: unknown, label: string): Worker; + }; + } +} + +export {}; diff --git a/apps/bluequickjs-playground/tests/playground.spec.ts b/apps/bluequickjs-playground/tests/playground.spec.ts new file mode 100644 index 0000000..21efa03 --- /dev/null +++ b/apps/bluequickjs-playground/tests/playground.spec.ts @@ -0,0 +1,151 @@ +import { expect, test } from '@playwright/test'; + +const screenshotOptions = { + fullPage: true, + maxDiffPixels: 5000, +}; + +async function selectGalleryItem( + page: import('@playwright/test').Page, + text: string, +) { + await page + .locator('button.gallery-item') + .filter({ hasText: text }) + .first() + .click(); +} + +test('renders the landing state', async ({ page, browserName }) => { + await page.goto('/'); + await expect( + page.getByRole('heading', { name: 'BlueQuickjs Playground' }), + ).toBeVisible(); + await expect(page.locator('[data-selection-title]')).toContainText( + 'Basic deterministic script', + ); + + if (browserName === 'chromium') { + await expect(page).toHaveScreenshot( + 'playground-landing.png', + screenshotOptions, + ); + } +}); + +test('runs the baseline example and matches certified evidence', async ({ + page, + browserName, +}) => { + await page.goto('/'); + await page.getByRole('button', { name: 'Run current selection' }).click(); + + await expect(page.locator('[data-run-status]')).toContainText('Success'); + await expect(page.locator('[data-evidence-status]')).toContainText( + 'Matches certified snapshot', + ); + await expect(page.locator('[data-tab-panel]')).toContainText( + '"gasUsed": "74"', + ); + + if (browserName === 'chromium') { + await expect(page).toHaveScreenshot( + 'playground-success.png', + screenshotOptions, + ); + } +}); + +test('runs promise and binary examples through their profile-gated flows', async ({ + page, + browserName, +}) => { + await page.goto('/'); + + await selectGalleryItem(page, 'Promises / async / microtasks'); + await page.getByRole('button', { name: 'Run current selection' }).click(); + await expect(page.locator('[data-run-status]')).toContainText('Success'); + await expect(page.locator('[data-evidence-status]')).toContainText( + 'Matches certified snapshot', + ); + + await selectGalleryItem(page, 'Binary / typed arrays / Host.v2 DV2'); + await page.getByRole('button', { name: 'Run current selection' }).click(); + await expect(page.locator('[data-run-status]')).toContainText('Success'); + await expect(page.locator('[data-evidence-status]')).toContainText( + 'Matches certified snapshot', + ); + + if (browserName === 'chromium') { + await expect(page).toHaveScreenshot( + 'playground-binary.png', + screenshotOptions, + ); + } +}); + +test('shows deterministic failure messaging for red fixtures', async ({ + page, + browserName, +}) => { + await page.goto('/'); + await selectGalleryItem( + page, + 'dynamic import must be rejected at build stage', + ); + + await expect(page.locator('[data-selection-title]')).toContainText( + 'dynamic import must be rejected at build stage', + ); + await expect( + page.getByRole('button', { name: 'Run current selection' }), + ).toBeDisabled(); + await page.getByRole('button', { name: 'Determinism evidence' }).click(); + await expect(page.locator('[data-tab-panel]')).toContainText( + 'builder_reject', + ); + + if (browserName === 'chromium') { + await expect(page).toHaveScreenshot( + 'playground-failure.png', + screenshotOptions, + ); + } +}); + +test('supports exact OOG boundary inspection and artifact-json roundtrips', async ({ + page, + browserName, +}) => { + await page.goto('/'); + await selectGalleryItem(page, 'Max-gas policy / OOG boundary'); + await page.getByRole('button', { name: 'Find OOG boundary' }).click(); + await page.getByRole('button', { name: 'Determinism evidence' }).click(); + await expect(page.locator('[data-tab-panel]')).toContainText( + '"firstSuccessGas": "170099"', + ); + await expect(page.locator('[data-tab-panel]')).toContainText( + '"lastFailureGas": "170098"', + ); + + if (browserName === 'chromium') { + await expect(page).toHaveScreenshot( + 'playground-oog.png', + screenshotOptions, + ); + } + + await selectGalleryItem(page, 'Standard ESM module-pack'); + await page.getByRole('button', { name: 'Artifact JSON' }).click(); + await page.getByRole('button', { name: 'Run current selection' }).click(); + await expect(page.locator('[data-run-status]')).toContainText('Success'); + await expect(page.locator('[data-evidence-status]')).toContainText( + 'Matches certified snapshot', + ); + + const [download] = await Promise.all([ + page.waitForEvent('download'), + page.getByRole('button', { name: 'Export artifact' }).click(), + ]); + expect(download.suggestedFilename()).toContain('bluequickjs-artifact'); +}); diff --git a/apps/bluequickjs-playground/tests/playground.spec.ts-snapshots/playground-binary-chromium-linux.png b/apps/bluequickjs-playground/tests/playground.spec.ts-snapshots/playground-binary-chromium-linux.png new file mode 100644 index 0000000..e6bd5a5 Binary files /dev/null and b/apps/bluequickjs-playground/tests/playground.spec.ts-snapshots/playground-binary-chromium-linux.png differ diff --git a/apps/bluequickjs-playground/tests/playground.spec.ts-snapshots/playground-failure-chromium-linux.png b/apps/bluequickjs-playground/tests/playground.spec.ts-snapshots/playground-failure-chromium-linux.png new file mode 100644 index 0000000..7929b5c Binary files /dev/null and b/apps/bluequickjs-playground/tests/playground.spec.ts-snapshots/playground-failure-chromium-linux.png differ diff --git a/apps/bluequickjs-playground/tests/playground.spec.ts-snapshots/playground-landing-chromium-linux.png b/apps/bluequickjs-playground/tests/playground.spec.ts-snapshots/playground-landing-chromium-linux.png new file mode 100644 index 0000000..4c69947 Binary files /dev/null and b/apps/bluequickjs-playground/tests/playground.spec.ts-snapshots/playground-landing-chromium-linux.png differ diff --git a/apps/bluequickjs-playground/tests/playground.spec.ts-snapshots/playground-oog-chromium-linux.png b/apps/bluequickjs-playground/tests/playground.spec.ts-snapshots/playground-oog-chromium-linux.png new file mode 100644 index 0000000..a2e305a Binary files /dev/null and b/apps/bluequickjs-playground/tests/playground.spec.ts-snapshots/playground-oog-chromium-linux.png differ diff --git a/apps/bluequickjs-playground/tests/playground.spec.ts-snapshots/playground-success-chromium-linux.png b/apps/bluequickjs-playground/tests/playground.spec.ts-snapshots/playground-success-chromium-linux.png new file mode 100644 index 0000000..363d9d2 Binary files /dev/null and b/apps/bluequickjs-playground/tests/playground.spec.ts-snapshots/playground-success-chromium-linux.png differ diff --git a/apps/bluequickjs-playground/tsconfig.app.json b/apps/bluequickjs-playground/tsconfig.app.json new file mode 100644 index 0000000..c5a9d61 --- /dev/null +++ b/apps/bluequickjs-playground/tsconfig.app.json @@ -0,0 +1,58 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "dist", + "lib": ["es2022", "dom", "dom.iterable"], + "types": ["node", "vite/client"], + "rootDir": "src", + "module": "esnext", + "moduleResolution": "bundler", + "tsBuildInfoFile": "dist/tsconfig.app.tsbuildinfo" + }, + "exclude": [ + "out-tsc", + "dist", + "src/**/*.spec.ts", + "src/**/*.test.ts", + "vite.config.ts", + "vite.config.mts", + "vitest.config.ts", + "vitest.config.mts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx", + "eslint.config.js", + "eslint.config.cjs", + "eslint.config.mjs" + ], + "include": ["src/**/*.ts", "src/**/*.d.ts"], + "references": [ + { + "path": "../ecosystem-certifier/tsconfig.app.json" + }, + { + "path": "../../libs/test-harness/tsconfig.lib.json" + }, + { + "path": "../../libs/quickjs-wasm/tsconfig.lib.json" + }, + { + "path": "../../libs/quickjs-runtime/tsconfig.lib.json" + }, + { + "path": "../../libs/execution-profiles/tsconfig.lib.json" + }, + { + "path": "../../libs/dv/tsconfig.lib.json" + }, + { + "path": "../../libs/deterministic-builder/tsconfig.lib.json" + }, + { + "path": "../../libs/abi-manifest/tsconfig.lib.json" + } + ] +} diff --git a/apps/bluequickjs-playground/tsconfig.json b/apps/bluequickjs-playground/tsconfig.json new file mode 100644 index 0000000..63dbe35 --- /dev/null +++ b/apps/bluequickjs-playground/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../tsconfig.base.json", + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/apps/bluequickjs-playground/tsconfig.spec.json b/apps/bluequickjs-playground/tsconfig.spec.json new file mode 100644 index 0000000..feb6ad3 --- /dev/null +++ b/apps/bluequickjs-playground/tsconfig.spec.json @@ -0,0 +1,36 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "./out-tsc/vitest", + "lib": ["es2022", "dom", "dom.iterable"], + "types": [ + "vitest/globals", + "vitest/importMeta", + "vite/client", + "node", + "vitest" + ], + "module": "esnext", + "moduleResolution": "bundler" + }, + "include": [ + "vite.config.ts", + "vite.config.mts", + "vitest.config.ts", + "vitest.config.mts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx", + "src/**/*.d.ts" + ], + "references": [ + { + "path": "./tsconfig.app.json" + } + ] +} diff --git a/apps/bluequickjs-playground/vite.config.mts b/apps/bluequickjs-playground/vite.config.mts new file mode 100644 index 0000000..eca94d9 --- /dev/null +++ b/apps/bluequickjs-playground/vite.config.mts @@ -0,0 +1,40 @@ +/// +import path from 'node:path'; +import { defineConfig } from 'vite'; + +export default defineConfig(() => ({ + root: import.meta.dirname, + cacheDir: '../../node_modules/.vite/apps/bluequickjs-playground', + server: { + port: 4325, + host: 'localhost', + fs: { + allow: [path.resolve(import.meta.dirname, '..', '..', '..')], + }, + }, + preview: { + port: 4325, + host: 'localhost', + }, + build: { + outDir: './dist', + emptyOutDir: true, + reportCompressedSize: true, + commonjsOptions: { + transformMixedEsModules: true, + }, + }, + test: { + name: 'bluequickjs-playground', + watch: false, + globals: true, + environment: 'jsdom', + include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], + exclude: ['tests/**'], + reporters: ['default'], + coverage: { + reportsDirectory: './test-output/vitest/coverage', + provider: 'v8' as const, + }, + }, +})); diff --git a/apps/ecosystem-certifier/README.md b/apps/ecosystem-certifier/README.md new file mode 100644 index 0000000..12064fe --- /dev/null +++ b/apps/ecosystem-certifier/README.md @@ -0,0 +1,29 @@ +# ecosystem-certifier + +Workload and ecosystem certification app for deterministic `blue-quickjs`. + +## What it runs + +- Flagship knowledge/compliance pack workload. +- Positive third-party compatibility fixtures. +- Negative deterministic-boundary fixtures. +- Node vs browser parity comparisons (result/error, gas, tape). + +## Commands + +- Unit tests: `pnpm nx test ecosystem-certifier` +- Browser e2e: `pnpm nx run ecosystem-certifier:e2e` +- Generate certification report: + `pnpm nx run ecosystem-certifier:certify -- --out-dir artifacts/workload-certification --browser chromium` +- Builder path-determinism check: + `node apps/ecosystem-certifier/scripts/check-builder-determinism.mjs` +- OOG boundary parity report: + `node apps/ecosystem-certifier/scripts/run-oog-boundary-certification.mjs --out-dir artifacts/workload-certification --browser chromium` +- Repeatability / soak report: + `node apps/ecosystem-certifier/scripts/run-repeatability-certification.mjs --out-dir artifacts/workload-certification --iterations 100 --flagship-iterations 40 --browser chromium` +- Seeded property corpus parity report: + `node apps/ecosystem-certifier/scripts/run-seeded-property-corpus.mjs --out-dir artifacts/workload-certification --seed-count 80 --browser chromium` +- Compatibility delta report: + `node apps/ecosystem-certifier/scripts/generate-compatibility-delta-report.mjs --current-dir artifacts/workload-certification --out-dir artifacts/workload-certification` +- Regenerate deterministic stress corpus: + `node apps/ecosystem-certifier/scripts/generate-stress-corpus.mjs` diff --git a/apps/ecosystem-certifier/fixtures/flagship/knowledge-pack-entry.ts b/apps/ecosystem-certifier/fixtures/flagship/knowledge-pack-entry.ts new file mode 100644 index 0000000..3743a2a --- /dev/null +++ b/apps/ecosystem-certifier/fixtures/flagship/knowledge-pack-entry.ts @@ -0,0 +1,139 @@ +import { toByteArray, fromByteArray } from 'base64-js'; +import { inflateSync } from 'fflate'; +import deepEqual from 'fast-deep-equal'; +import stableStringify from 'fast-json-stable-stringify'; +import he from 'he'; +import jsonLogic from 'json-logic-js'; +import LinkifyIt from 'linkify-it'; +import MarkdownIt from 'markdown-it'; +import { sha256 } from '@noble/hashes/sha256'; +import { bytesToHex } from '@noble/hashes/utils'; +import { match as pathMatch } from 'path-to-regexp'; +import semver from 'semver'; +import TinyQueue from 'tinyqueue'; +import CRC32 from 'crc-32'; + +let summary; +try { + const metadataText = Host.v2.document.get('pack/metadata.json'); + const ruleText = Host.v2.document.get('rules/findings.json'); + const compressedAttachment = Host.v2.document.get('pack/attachment.deflated'); + const payload = Host.v2.document.get('bytes/payload'); + const extraPayload = Host.v2.document.get('bytes/flagship-extra'); + + const metadata = JSON.parse(metadataText); + const docPaths = metadata.links ?? ['docs/a.md', 'docs/b.md']; + const docs = docPaths.map((docPath) => ({ + docPath, + text: Host.v2.document.get(docPath), + })); + const markdown = new MarkdownIt({ linkify: true }); + const linkify = new LinkifyIt(); + const markdownSource = docs.map((doc) => doc.text).join('\n'); + const markdownTokens = markdown.parse(markdownSource, {}); + const linkMatches = docs + .flatMap((doc) => linkify.match(doc.text) ?? []) + .map((item) => item.url); + + const releaseChecks = (metadata.requires ?? []).map((range) => + semver.satisfies(metadata.release, range), + ); + const rules = JSON.parse(ruleText); + const findingInput = { + linkCount: linkMatches.length, + releaseOk: releaseChecks.every(Boolean), + }; + const ruleInputStable = deepEqual( + findingInput, + JSON.parse(stableStringify(findingInput)), + ); + const rulePasses = Boolean(jsonLogic.apply(rules, findingInput)); + + const queue = new TinyQueue( + [], + (left, right) => left.priority - right.priority, + ); + for (const link of linkMatches) { + queue.push({ link, priority: link.length }); + } + const orderedLinks = []; + while (queue.length > 0) { + orderedLinks.push(queue.pop().link); + } + + const decompressed = inflateSync(compressedAttachment); + const attachmentRoundTrip = toByteArray(fromByteArray(decompressed)); + const mergedBinary = new Uint8Array( + attachmentRoundTrip.length + payload.length + extraPayload.length, + ); + mergedBinary.set(attachmentRoundTrip, 0); + mergedBinary.set(payload, attachmentRoundTrip.length); + mergedBinary.set(extraPayload, attachmentRoundTrip.length + payload.length); + const digestHex = bytesToHex(sha256(mergedBinary)); + const crc32 = (CRC32.buf(mergedBinary) >>> 0).toString(16).padStart(8, '0'); + + const decodedEntities = he.decode('<b>safe</b>'); + const versionCapture = pathMatch('/document/:id/version/:version')( + '/document/42/version/1.2.3', + ); + const orderedFindings = [ + { id: 'links', value: linkMatches.length }, + { id: 'rules', value: Number(rulePasses) }, + { id: 'tokens', value: markdownTokens.length }, + ].sort((left, right) => left.id.localeCompare(right.id)); + + Promise.resolve('scheduled').then(() => undefined); + queueMicrotask(() => undefined); + + for (const doc of docs) { + Host.v2.emit({ + type: 'knowledge-pack-doc', + docPath: doc.docPath, + length: doc.text.length, + }); + } + + summary = { + status: 'ok', + packId: metadata.packId, + release: metadata.release, + checks: releaseChecks, + docTokenCount: markdownTokens.length, + linkCount: linkMatches.length, + uniqueLinks: [...new Set(orderedLinks)], + binary: { + byteLength: mergedBinary.length, + digestHex, + crc32, + }, + decodedEntities, + versionCapture, + findings: orderedFindings, + ruleInputStable, + rulePasses, + }; +} catch (error) { + summary = { + status: 'error', + message: String(error instanceof Error ? error.message : error), + }; +} + +Host.v2.emit({ + type: 'knowledge-pack-summary', + summaryHash: bytesToHex( + sha256( + toByteArray( + fromByteArray( + new Uint8Array([ + ...Host.v2.document.get('bytes/payload'), + ...Host.v2.document.get('bytes/flagship-extra'), + ]), + ), + ), + ), + ), + status: summary.status, +}); + +export default summary; diff --git a/apps/ecosystem-certifier/fixtures/negative/dynamic-import-entry.ts b/apps/ecosystem-certifier/fixtures/negative/dynamic-import-entry.ts new file mode 100644 index 0000000..68c949c --- /dev/null +++ b/apps/ecosystem-certifier/fixtures/negative/dynamic-import-entry.ts @@ -0,0 +1,4 @@ +export default async () => { + const loaded = await import('./dynamic-local'); + return loaded.value; +}; diff --git a/apps/ecosystem-certifier/fixtures/negative/dynamic-local.ts b/apps/ecosystem-certifier/fixtures/negative/dynamic-local.ts new file mode 100644 index 0000000..5f45ec8 --- /dev/null +++ b/apps/ecosystem-certifier/fixtures/negative/dynamic-local.ts @@ -0,0 +1 @@ +export const value = 7; diff --git a/apps/ecosystem-certifier/fixtures/negative/function-constructor-entry.ts b/apps/ecosystem-certifier/fixtures/negative/function-constructor-entry.ts new file mode 100644 index 0000000..796ee22 --- /dev/null +++ b/apps/ecosystem-certifier/fixtures/negative/function-constructor-entry.ts @@ -0,0 +1,3 @@ +const make = new Function('return 41 + 1;'); + +export default make(); diff --git a/apps/ecosystem-certifier/fixtures/negative/graphlib-entry.ts b/apps/ecosystem-certifier/fixtures/negative/graphlib-entry.ts new file mode 100644 index 0000000..9a5f98f --- /dev/null +++ b/apps/ecosystem-certifier/fixtures/negative/graphlib-entry.ts @@ -0,0 +1,8 @@ +import { Graph } from 'graphlib'; + +const graph = new Graph({ directed: true }); +graph.setNode('a'); +graph.setNode('b'); +graph.setEdge('a', 'b'); + +export default graph.edgeCount(); diff --git a/apps/ecosystem-certifier/fixtures/negative/math-random-entry.ts b/apps/ecosystem-certifier/fixtures/negative/math-random-entry.ts new file mode 100644 index 0000000..b6daef7 --- /dev/null +++ b/apps/ecosystem-certifier/fixtures/negative/math-random-entry.ts @@ -0,0 +1 @@ +export default Math.random(); diff --git a/apps/ecosystem-certifier/fixtures/negative/proxy-entry.ts b/apps/ecosystem-certifier/fixtures/negative/proxy-entry.ts new file mode 100644 index 0000000..900409d --- /dev/null +++ b/apps/ecosystem-certifier/fixtures/negative/proxy-entry.ts @@ -0,0 +1,8 @@ +const target = { value: 1 }; +const proxy = new Proxy(target, { + get(obj, prop) { + return obj[prop]; + }, +}); + +export default proxy.value; diff --git a/apps/ecosystem-certifier/fixtures/positive/array-move-entry.ts b/apps/ecosystem-certifier/fixtures/positive/array-move-entry.ts new file mode 100644 index 0000000..b043416 --- /dev/null +++ b/apps/ecosystem-certifier/fixtures/positive/array-move-entry.ts @@ -0,0 +1,9 @@ +import { arrayMoveImmutable } from 'array-move'; + +const values = ['wasm-node', 'chromium', 'firefox', 'webk-it']; +const reordered = arrayMoveImmutable(values, 3, 1); + +export default { + reordered, + original: values, +}; diff --git a/apps/ecosystem-certifier/fixtures/positive/camelcase-entry.ts b/apps/ecosystem-certifier/fixtures/positive/camelcase-entry.ts new file mode 100644 index 0000000..f03d8db --- /dev/null +++ b/apps/ecosystem-certifier/fixtures/positive/camelcase-entry.ts @@ -0,0 +1,7 @@ +import camelCase from 'camelcase'; + +const samples = ['hello-world', 'blue_quickjs', 'deterministic vm']; + +export default { + values: samples.map((sample) => camelCase(sample)), +}; diff --git a/apps/ecosystem-certifier/fixtures/positive/crc32-entry.ts b/apps/ecosystem-certifier/fixtures/positive/crc32-entry.ts new file mode 100644 index 0000000..574c3e0 --- /dev/null +++ b/apps/ecosystem-certifier/fixtures/positive/crc32-entry.ts @@ -0,0 +1,9 @@ +import CRC32 from 'crc-32'; + +const value = Host.v1.document.get('text/markdown-case'); +const checksum = (CRC32.str(value) >>> 0).toString(16).padStart(8, '0'); + +export default { + checksum, + length: value.length, +}; diff --git a/apps/ecosystem-certifier/fixtures/positive/decamelize-entry.ts b/apps/ecosystem-certifier/fixtures/positive/decamelize-entry.ts new file mode 100644 index 0000000..ace54aa --- /dev/null +++ b/apps/ecosystem-certifier/fixtures/positive/decamelize-entry.ts @@ -0,0 +1,7 @@ +import decamelize from 'decamelize'; + +const samples = ['deterministicRuntime', 'gasVersionPin', 'hostCallTape']; + +export default { + values: samples.map((sample) => decamelize(sample)), +}; diff --git a/apps/ecosystem-certifier/fixtures/positive/deepmerge-entry.ts b/apps/ecosystem-certifier/fixtures/positive/deepmerge-entry.ts new file mode 100644 index 0000000..fe7df0f --- /dev/null +++ b/apps/ecosystem-certifier/fixtures/positive/deepmerge-entry.ts @@ -0,0 +1,16 @@ +import merge from 'deepmerge'; + +const left = { + release: { + consensus: true, + executors: ['wasm-node'], + }, +}; +const right = { + release: { + executors: ['wasm-browser'], + profiles: ['compat-general-v1'], + }, +}; + +export default merge(left, right); diff --git a/apps/ecosystem-certifier/fixtures/positive/diff-entry.ts b/apps/ecosystem-certifier/fixtures/positive/diff-entry.ts new file mode 100644 index 0000000..3b6447f --- /dev/null +++ b/apps/ecosystem-certifier/fixtures/positive/diff-entry.ts @@ -0,0 +1,11 @@ +import { diffLines } from 'diff'; + +const left = Host.v1.document.get('text/diff-left'); +const right = Host.v1.document.get('text/diff-right'); +const chunks = diffLines(left, right); + +export default { + chunkCount: chunks.length, + added: chunks.filter((chunk) => chunk.added).length, + removed: chunks.filter((chunk) => chunk.removed).length, +}; diff --git a/apps/ecosystem-certifier/fixtures/positive/dijkstrajs-entry.ts b/apps/ecosystem-certifier/fixtures/positive/dijkstrajs-entry.ts new file mode 100644 index 0000000..b38fe34 --- /dev/null +++ b/apps/ecosystem-certifier/fixtures/positive/dijkstrajs-entry.ts @@ -0,0 +1,13 @@ +import dijkstra from 'dijkstrajs'; + +const graph = { + start: { parse: 2, hash: 5 }, + parse: { graph: 1, hash: 2 }, + hash: { graph: 2, done: 3 }, + graph: { done: 1 }, + done: {}, +}; + +export default { + route: dijkstra.find_path(graph, 'start', 'done'), +}; diff --git a/apps/ecosystem-certifier/fixtures/positive/escape-string-regexp-entry.ts b/apps/ecosystem-certifier/fixtures/positive/escape-string-regexp-entry.ts new file mode 100644 index 0000000..9e9e0c1 --- /dev/null +++ b/apps/ecosystem-certifier/fixtures/positive/escape-string-regexp-entry.ts @@ -0,0 +1,7 @@ +import escapeStringRegexp from 'escape-string-regexp'; + +const raw = Host.v1.document.get('text/path-case'); + +export default { + escaped: escapeStringRegexp(raw), +}; diff --git a/apps/ecosystem-certifier/fixtures/positive/fast-deep-equal-entry.ts b/apps/ecosystem-certifier/fixtures/positive/fast-deep-equal-entry.ts new file mode 100644 index 0000000..4cfb203 --- /dev/null +++ b/apps/ecosystem-certifier/fixtures/positive/fast-deep-equal-entry.ts @@ -0,0 +1,12 @@ +import deepEqual from 'fast-deep-equal'; + +const left = { + id: 'deterministic', + values: [1, 2, 3], + nested: { ok: true }, +}; +const right = JSON.parse(JSON.stringify(left)); + +export default { + equal: deepEqual(left, right), +}; diff --git a/apps/ecosystem-certifier/fixtures/positive/fast-json-stable-stringify-entry.ts b/apps/ecosystem-certifier/fixtures/positive/fast-json-stable-stringify-entry.ts new file mode 100644 index 0000000..c19b625 --- /dev/null +++ b/apps/ecosystem-certifier/fixtures/positive/fast-json-stable-stringify-entry.ts @@ -0,0 +1,14 @@ +import stableStringify from 'fast-json-stable-stringify'; + +const payload = { + zebra: 1, + alpha: 2, + nested: { + gamma: 3, + beta: 4, + }, +}; + +export default { + serialized: stableStringify(payload), +}; diff --git a/apps/ecosystem-certifier/fixtures/positive/fastest-levenshtein-entry.ts b/apps/ecosystem-certifier/fixtures/positive/fastest-levenshtein-entry.ts new file mode 100644 index 0000000..23e3531 --- /dev/null +++ b/apps/ecosystem-certifier/fixtures/positive/fastest-levenshtein-entry.ts @@ -0,0 +1,18 @@ +import { closest, distance } from 'fastest-levenshtein'; + +const dictionary = [ + 'consensus', + 'determinism', + 'compatibility', + 'gas-metering', +]; +const target = 'deterministic'; + +export default { + target, + closest: closest(target, dictionary), + distances: dictionary.map((entry) => ({ + entry, + value: distance(target, entry), + })), +}; diff --git a/apps/ecosystem-certifier/fixtures/positive/fflate-entry.ts b/apps/ecosystem-certifier/fixtures/positive/fflate-entry.ts new file mode 100644 index 0000000..033b624 --- /dev/null +++ b/apps/ecosystem-certifier/fixtures/positive/fflate-entry.ts @@ -0,0 +1,10 @@ +import { strToU8, zlibSync, unzlibSync } from 'fflate'; + +const text = Host.v1.document.get('text/markdown-case'); +const compressed = zlibSync(strToU8(text)); +const roundTrip = unzlibSync(compressed); + +export default { + compressedLength: compressed.length, + restoredLength: roundTrip.length, +}; diff --git a/apps/ecosystem-certifier/fixtures/positive/he-entry.ts b/apps/ecosystem-certifier/fixtures/positive/he-entry.ts new file mode 100644 index 0000000..a39b4a4 --- /dev/null +++ b/apps/ecosystem-certifier/fixtures/positive/he-entry.ts @@ -0,0 +1,8 @@ +import he from 'he'; + +const encoded = Host.v1.document.get('text/he-case'); + +export default { + encoded, + decoded: he.decode(encoded), +}; diff --git a/apps/ecosystem-certifier/fixtures/positive/json-logic-entry.ts b/apps/ecosystem-certifier/fixtures/positive/json-logic-entry.ts new file mode 100644 index 0000000..3bbbb96 --- /dev/null +++ b/apps/ecosystem-certifier/fixtures/positive/json-logic-entry.ts @@ -0,0 +1,14 @@ +import jsonLogic from 'json-logic-js'; + +const payload = JSON.parse(Host.v1.document.get('text/json-logic-case')); +const rule = { + and: [ + { '>': [{ var: 'score' }, { var: 'threshold' }] }, + { '<=': [{ var: 'threshold' }, 10] }, + ], +}; + +export default { + payload, + passes: Boolean(jsonLogic.apply(rule, payload)), +}; diff --git a/apps/ecosystem-certifier/fixtures/positive/linkify-it-entry.ts b/apps/ecosystem-certifier/fixtures/positive/linkify-it-entry.ts new file mode 100644 index 0000000..f6e07e2 --- /dev/null +++ b/apps/ecosystem-certifier/fixtures/positive/linkify-it-entry.ts @@ -0,0 +1,10 @@ +import LinkifyIt from 'linkify-it'; + +const parser = new LinkifyIt(); +const value = Host.v1.document.get('text/markdown-case'); +const links = parser.match(value) ?? []; + +export default { + linkCount: links.length, + urls: links.map((item) => item.url), +}; diff --git a/apps/ecosystem-certifier/fixtures/positive/lodash-es-entry.ts b/apps/ecosystem-certifier/fixtures/positive/lodash-es-entry.ts new file mode 100644 index 0000000..042daea --- /dev/null +++ b/apps/ecosystem-certifier/fixtures/positive/lodash-es-entry.ts @@ -0,0 +1,11 @@ +import sortBy from 'lodash-es/sortBy.js'; + +const findings = [ + { id: 'b', score: 2 }, + { id: 'a', score: 1 }, + { id: 'c', score: 2 }, +]; + +export default { + orderedIds: sortBy(findings, ['score', 'id']).map((item) => item.id), +}; diff --git a/apps/ecosystem-certifier/fixtures/positive/markdown-it-entry.ts b/apps/ecosystem-certifier/fixtures/positive/markdown-it-entry.ts new file mode 100644 index 0000000..e728a47 --- /dev/null +++ b/apps/ecosystem-certifier/fixtures/positive/markdown-it-entry.ts @@ -0,0 +1,14 @@ +import MarkdownIt from 'markdown-it'; + +const md = new MarkdownIt({ + linkify: true, +}); +const source = Host.v1.document.get('text/markdown-case'); +const tokens = md.parse(source, {}); +const links = md.render(source).match(/ token.type), + tokenCount: tokens.length, + linkCount: links, +}; diff --git a/apps/ecosystem-certifier/fixtures/positive/path-to-regexp-entry.ts b/apps/ecosystem-certifier/fixtures/positive/path-to-regexp-entry.ts new file mode 100644 index 0000000..9ab2954 --- /dev/null +++ b/apps/ecosystem-certifier/fixtures/positive/path-to-regexp-entry.ts @@ -0,0 +1,10 @@ +import { match } from 'path-to-regexp'; + +const pattern = Host.v1.document.get('text/path-case'); +const matcher = match(pattern); +const matched = matcher('/document/42/version/1.2.3'); + +export default { + matched: Boolean(matched), + params: matched?.params ?? null, +}; diff --git a/apps/ecosystem-certifier/fixtures/positive/query-string-entry.ts b/apps/ecosystem-certifier/fixtures/positive/query-string-entry.ts new file mode 100644 index 0000000..e33341c --- /dev/null +++ b/apps/ecosystem-certifier/fixtures/positive/query-string-entry.ts @@ -0,0 +1,10 @@ +import queryString from 'query-string'; + +const query = 'profile=compat-general-v1&gasVersion=8&checks=parity&checks=oog'; +const parsed = queryString.parse(query); +const stringified = queryString.stringify(parsed, { arrayFormat: 'none' }); + +export default { + parsed, + stringified, +}; diff --git a/apps/ecosystem-certifier/fixtures/positive/semver-entry.ts b/apps/ecosystem-certifier/fixtures/positive/semver-entry.ts new file mode 100644 index 0000000..e9aed02 --- /dev/null +++ b/apps/ecosystem-certifier/fixtures/positive/semver-entry.ts @@ -0,0 +1,10 @@ +import { satisfies, valid } from 'semver'; + +const version = Host.v1.document.get('text/semver-case'); +const ranges = ['>=1.2.0 <2.0.0', '^1.2.0', '~1.2.3']; + +export default { + version, + valid: valid(version) !== null, + checks: ranges.map((range) => ({ range, ok: satisfies(version, range) })), +}; diff --git a/apps/ecosystem-certifier/fixtures/positive/sort-keys-entry.ts b/apps/ecosystem-certifier/fixtures/positive/sort-keys-entry.ts new file mode 100644 index 0000000..4f6b88e --- /dev/null +++ b/apps/ecosystem-certifier/fixtures/positive/sort-keys-entry.ts @@ -0,0 +1,13 @@ +import sortKeys from 'sort-keys'; + +const payload = { + zeta: 4, + alpha: 1, + gamma: 3, + beta: 2, +}; + +export default { + sorted: sortKeys(payload), + keys: Object.keys(sortKeys(payload)), +}; diff --git a/apps/ecosystem-certifier/fixtures/positive/spark-md5-entry.ts b/apps/ecosystem-certifier/fixtures/positive/spark-md5-entry.ts new file mode 100644 index 0000000..b469d5b --- /dev/null +++ b/apps/ecosystem-certifier/fixtures/positive/spark-md5-entry.ts @@ -0,0 +1,8 @@ +import SparkMD5 from 'spark-md5'; + +const payload = Host.v1.document.get('text/markdown-case'); + +export default { + digest: SparkMD5.hash(payload), + digestPrefix: SparkMD5.hash(payload).slice(0, 8), +}; diff --git a/apps/ecosystem-certifier/fixtures/positive/stress-corpus-entry.ts b/apps/ecosystem-certifier/fixtures/positive/stress-corpus-entry.ts new file mode 100644 index 0000000..0c1ca65 --- /dev/null +++ b/apps/ecosystem-certifier/fixtures/positive/stress-corpus-entry.ts @@ -0,0 +1,20 @@ +import { satisfies } from 'semver'; +import corpus from '../../src/shared/fixtures/stress-corpus.generated.json'; + +const firstDoc = corpus.markdownDocs[0]?.id ?? null; +const semverPasses = corpus.semverChecks.filter((entry) => + satisfies(entry.version, entry.range), +).length; +const sortedNumeric = [...corpus.numericWork].sort( + (left, right) => left - right, +); + +export default { + seed: corpus.seed, + docs: corpus.markdownDocs.length, + firstDoc, + semverPasses, + numericMin: sortedNumeric[0], + numericMax: sortedNumeric[sortedNumeric.length - 1], + numericMedian: sortedNumeric[Math.floor(sortedNumeric.length / 2)], +}; diff --git a/apps/ecosystem-certifier/fixtures/positive/tinyqueue-entry.ts b/apps/ecosystem-certifier/fixtures/positive/tinyqueue-entry.ts new file mode 100644 index 0000000..ab136f0 --- /dev/null +++ b/apps/ecosystem-certifier/fixtures/positive/tinyqueue-entry.ts @@ -0,0 +1,18 @@ +import TinyQueue from 'tinyqueue'; + +const queue = new TinyQueue( + [], + (left, right) => left.priority - right.priority, +); +queue.push({ id: 'b', priority: 2 }); +queue.push({ id: 'a', priority: 1 }); +queue.push({ id: 'c', priority: 3 }); + +const ordered = []; +while (queue.length > 0) { + ordered.push(queue.pop().id); +} + +export default { + ordered, +}; diff --git a/apps/ecosystem-certifier/fixtures/positive/yaml-entry.ts b/apps/ecosystem-certifier/fixtures/positive/yaml-entry.ts new file mode 100644 index 0000000..13844ff --- /dev/null +++ b/apps/ecosystem-certifier/fixtures/positive/yaml-entry.ts @@ -0,0 +1,10 @@ +import { parse } from 'yaml'; + +const text = Host.v1.document.get('text/yaml-case'); +const parsed = parse(text) as { name: string; value: number }; + +export default { + keys: Object.keys(parsed).sort(), + name: parsed.name, + value: parsed.value, +}; diff --git a/apps/ecosystem-certifier/index.html b/apps/ecosystem-certifier/index.html new file mode 100644 index 0000000..48310ff --- /dev/null +++ b/apps/ecosystem-certifier/index.html @@ -0,0 +1,12 @@ + + + + + + Ecosystem Certifier + + +
Loading ecosystem certifier…
+ + + diff --git a/apps/ecosystem-certifier/package.json b/apps/ecosystem-certifier/package.json new file mode 100644 index 0000000..681cb55 --- /dev/null +++ b/apps/ecosystem-certifier/package.json @@ -0,0 +1,65 @@ +{ + "name": "@blue-quickjs/ecosystem-certifier", + "version": "0.0.1", + "private": true, + "type": "module", + "dependencies": { + "@blue-quickjs/abi-manifest": "workspace:*", + "@blue-quickjs/deterministic-builder": "workspace:*", + "@blue-quickjs/dv": "workspace:*", + "@blue-quickjs/quickjs-runtime": "workspace:*", + "@blue-quickjs/quickjs-wasm": "workspace:*", + "@blue-quickjs/test-harness": "workspace:*", + "@noble/hashes": "^1.8.0", + "array-move": "^4.0.0", + "base64-js": "^1.5.1", + "camelcase": "^9.0.0", + "chess.js": "^1.4.0", + "crc-32": "^1.2.2", + "decamelize": "^6.0.1", + "deepmerge": "^4.3.1", + "diff": "^8.0.2", + "dijkstrajs": "^1.0.3", + "escape-string-regexp": "^5.0.0", + "fast-deep-equal": "^3.1.3", + "fast-json-stable-stringify": "^2.1.0", + "fastest-levenshtein": "^1.0.16", + "fflate": "^0.8.2", + "graphlib": "^2.1.8", + "he": "^1.2.0", + "json-logic-js": "^2.0.5", + "linkify-it": "^5.0.0", + "lodash-es": "^4.17.21", + "markdown-it": "^14.1.0", + "path-to-regexp": "^8.2.0", + "query-string": "^9.3.1", + "semver": "^7.7.3", + "sort-keys": "^6.0.0", + "spark-md5": "^3.0.2", + "tinyqueue": "^3.0.0", + "tslib": "^2.3.0", + "yaml": "^2.8.2" + }, + "nx": { + "name": "ecosystem-certifier", + "targets": { + "e2e": { + "dependsOn": [ + "^build" + ], + "executor": "nx:run-commands", + "options": { + "command": "pnpm playwright test apps/ecosystem-certifier/tests --config apps/ecosystem-certifier/playwright.config.cts", + "cwd": "." + } + }, + "certify": { + "executor": "nx:run-commands", + "options": { + "command": "node apps/ecosystem-certifier/scripts/archive-workload-certification-report.mjs", + "cwd": "." + } + } + } + } +} diff --git a/apps/ecosystem-certifier/playwright.config.cts b/apps/ecosystem-certifier/playwright.config.cts new file mode 100644 index 0000000..a6abf8c --- /dev/null +++ b/apps/ecosystem-certifier/playwright.config.cts @@ -0,0 +1,25 @@ +import { defineConfig } from '@playwright/test'; + +const projectRoot = __dirname; +type SupportedBrowserName = 'chromium' | 'firefox' | 'webkit'; + +const browserName = (process.env.PLAYWRIGHT_BROWSER ?? + 'chromium') as SupportedBrowserName; + +export default defineConfig({ + testDir: './tests', + fullyParallel: false, + timeout: 120000, + use: { + headless: true, + baseURL: 'http://localhost:4310', + browserName, + }, + webServer: { + command: 'pnpm vite --host --port 4310 --config vite.config.mts', + cwd: projectRoot, + url: 'http://localhost:4310', + reuseExistingServer: !process.env.CI, + timeout: 120000, + }, +}); diff --git a/apps/ecosystem-certifier/scripts/_certifier-eval-helpers.mjs b/apps/ecosystem-certifier/scripts/_certifier-eval-helpers.mjs new file mode 100644 index 0000000..3a4daa1 --- /dev/null +++ b/apps/ecosystem-certifier/scripts/_certifier-eval-helpers.mjs @@ -0,0 +1,198 @@ +import { chromium, firefox, webkit } from '@playwright/test'; +import { createHash } from 'node:crypto'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { createServer } from 'vite'; +import jiti from 'jiti'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +export const repoRoot = path.resolve(__dirname, '..', '..', '..'); +export const appRoot = path.resolve(repoRoot, 'apps/ecosystem-certifier'); +const require = jiti(import.meta.url, { interopDefault: true }); + +const { + buildDeterministicModulePack, + DeterministicBundlerError: DeterministicBuilderError, +} = require('../../../libs/deterministic-bundler/src/index.ts'); +const { evaluate } = require('../../../libs/quickjs-runtime/src/index.ts'); +const { encodeDv } = require('../../../libs/dv/src/index.ts'); +const { + serializeHostTape, +} = require('../../../libs/test-harness/src/index.ts'); +const { + CERTIFIER_FIXTURES, + manifestForFixture, +} = require('../src/shared/fixtures.ts'); +const { createCertificationHost } = require('../src/shared/host.ts'); + +export async function buildRunnableCasesByIds(ids) { + const fixtures = CERTIFIER_FIXTURES.filter( + (fixture) => ids.includes(fixture.id) && fixture.expect.stage === 'success', + ); + const cases = []; + for (const fixture of fixtures) { + try { + const built = await buildDeterministicModulePack({ + absWorkingDir: repoRoot, + entryPath: fixture.entryPath, + profile: fixture.profile, + emitProgramArtifact: true, + abiId: fixture.abiId, + abiVersion: fixture.abiVersion, + abiManifestHash: fixture.abiManifestHash, + }); + if (!built.programArtifact) { + throw new Error(`missing ProgramArtifact.v2 for ${fixture.id}`); + } + cases.push({ + id: fixture.id, + title: fixture.title, + kind: fixture.kind, + gasLimit: fixture.gasLimit.toString(), + manifest: manifestForFixture(fixture), + program: built.programArtifact, + }); + } catch (error) { + if (error instanceof DeterministicBuilderError) { + throw new Error( + `fixture ${fixture.id} unexpectedly failed builder compatibility: ${JSON.stringify( + error.diagnostics, + )}`, + ); + } + throw error; + } + } + return cases; +} + +export async function evaluateCaseNode(certCase, gasLimit) { + const host = createCertificationHost(); + const result = await evaluate({ + program: certCase.program, + input: { + event: { type: 'ecosystem-certifier' }, + eventCanonical: { type: 'ecosystem-certifier' }, + steps: [], + currentContract: { id: 'ecosystem-certifier' }, + currentContractCanonical: { id: { value: 'ecosystem-certifier' } }, + }, + gasLimit: BigInt(gasLimit ?? certCase.gasLimit), + manifest: certCase.manifest, + handlers: host.handlers, + tape: { capacity: 128 }, + }); + return snapshotFromEvaluateResult(result); +} + +export async function launchBrowserCertifier( + baseUrlOverride, + browserName = 'chromium', +) { + const viteServer = await createServer({ + configFile: path.join(appRoot, 'vite.config.mts'), + server: { + host: '127.0.0.1', + port: 4310, + strictPort: true, + }, + clearScreen: false, + }); + await viteServer.listen(); + + const baseUrl = baseUrlOverride ?? 'http://127.0.0.1:4310'; + const browserType = resolveBrowserType(browserName); + const browser = await browserType.launch({ headless: true }); + const context = await browser.newContext({ baseURL: baseUrl }); + const page = await context.newPage(); + await page.goto('/'); + await page.waitForFunction( + () => typeof window.__ECOSYSTEM_CERT_RUN_CASE__ === 'function', + undefined, + { + timeout: 120000, + }, + ); + + return { + async evaluateCaseSnapshot(certCase, gasLimit) { + return page.evaluate( + async ({ certCasePayload, gasLimitValue }) => { + if (!window.__ECOSYSTEM_CERT_RUN_CASE__) { + throw new Error('window.__ECOSYSTEM_CERT_RUN_CASE__ unavailable'); + } + return window.__ECOSYSTEM_CERT_RUN_CASE__( + certCasePayload, + gasLimitValue, + ); + }, + { + certCasePayload: certCase, + gasLimitValue: gasLimit ?? certCase.gasLimit, + }, + ); + }, + async close() { + await context.close(); + await browser.close(); + await viteServer.close(); + }, + }; +} + +export function snapshotFromEvaluateResult(result) { + const tape = result.tape ?? []; + if (result.ok) { + return { + stage: 'success', + resultHash: sha256Hex(Buffer.from(encodeDv(result.value))), + errorCode: null, + errorTag: null, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + tapeHash: + tape.length > 0 + ? sha256Hex(Buffer.from(serializeHostTape(tape))) + : null, + tapeLength: tape.length, + }; + } + return { + stage: normalizeFailureStage(result.error.kind), + resultHash: null, + errorCode: result.error.code, + errorTag: 'tag' in result.error ? result.error.tag : null, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + tapeHash: + tape.length > 0 ? sha256Hex(Buffer.from(serializeHostTape(tape))) : null, + tapeLength: tape.length, + }; +} + +export function sha256Hex(input) { + return createHash('sha256').update(input).digest('hex'); +} + +function normalizeFailureStage(kind) { + if (kind === 'module-pack') { + return 'artifact_validation'; + } + if (kind === 'execution-surface-mismatch') { + return 'pin_enforcement'; + } + return 'runtime_error'; +} + +function resolveBrowserType(browserName) { + if (browserName === 'chromium') { + return chromium; + } + if (browserName === 'firefox') { + return firefox; + } + if (browserName === 'webkit') { + return webkit; + } + throw new Error(`unsupported browser: ${browserName}`); +} diff --git a/apps/ecosystem-certifier/scripts/archive-workload-certification-report.mjs b/apps/ecosystem-certifier/scripts/archive-workload-certification-report.mjs new file mode 100644 index 0000000..8072932 --- /dev/null +++ b/apps/ecosystem-certifier/scripts/archive-workload-certification-report.mjs @@ -0,0 +1,409 @@ +#!/usr/bin/env node + +import { chromium, firefox, webkit } from '@playwright/test'; +import { createHash } from 'node:crypto'; +import { mkdir, writeFile } from 'node:fs/promises'; +import path from 'node:path'; +import process from 'node:process'; +import { fileURLToPath } from 'node:url'; +import { createServer } from 'vite'; +import jiti from 'jiti'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const repoRoot = path.resolve(__dirname, '..', '..', '..'); +const appRoot = path.resolve(repoRoot, 'apps/ecosystem-certifier'); +const require = jiti(import.meta.url, { interopDefault: true }); + +const { + buildDeterministicModulePack, + DeterministicBundlerError: DeterministicBuilderError, +} = require('../../../libs/deterministic-bundler/src/index.ts'); +const { evaluate } = require('../../../libs/quickjs-runtime/src/index.ts'); +const { encodeDv } = require('../../../libs/dv/src/index.ts'); +const { + serializeHostTape, +} = require('../../../libs/test-harness/src/index.ts'); +const { + CERTIFIER_FIXTURES, + manifestForFixture, +} = require('../src/shared/fixtures.ts'); +const { createCertificationHost } = require('../src/shared/host.ts'); + +const args = parseArgs(process.argv.slice(2)); +const now = new Date(); +const timestamp = now.toISOString().replace(/[:.]/g, '-'); +const outDir = path.resolve(repoRoot, args.outDir); +const jsonPath = path.join(outDir, `workload-certification-${timestamp}.json`); +const mdPath = path.join(outDir, `workload-certification-${timestamp}.md`); +const checksumPath = `${jsonPath}.sha256`; +const matrixPath = path.join(outDir, `compatibility-matrix-${timestamp}.json`); + +await mkdir(outDir, { recursive: true }); + +const nodeRecords = []; +const browserCases = []; + +for (const fixture of CERTIFIER_FIXTURES) { + const manifest = manifestForFixture(fixture); + const entry = { + id: fixture.id, + title: fixture.title, + kind: fixture.kind, + profile: fixture.profile, + expected: fixture.expect, + node: null, + browser: null, + builder: { + ok: false, + diagnostics: [], + graphHash: null, + }, + }; + + try { + const built = await buildDeterministicModulePack({ + absWorkingDir: repoRoot, + entryPath: fixture.entryPath, + profile: fixture.profile, + emitProgramArtifact: true, + abiId: fixture.abiId, + abiVersion: fixture.abiVersion, + abiManifestHash: fixture.abiManifestHash, + }); + entry.builder = { + ok: true, + diagnostics: built.compatibility.diagnostics, + graphHash: built.modulePack.graphHash, + }; + + if (!built.programArtifact) { + throw new Error( + `builder did not return ProgramArtifact.v2 (${fixture.id})`, + ); + } + + const host = createCertificationHost(); + const nodeResult = await evaluate({ + program: built.programArtifact, + input: { + event: { type: 'ecosystem-certifier' }, + eventCanonical: { type: 'ecosystem-certifier' }, + steps: [], + currentContract: { id: 'ecosystem-certifier' }, + currentContractCanonical: { id: { value: 'ecosystem-certifier' } }, + }, + gasLimit: fixture.gasLimit, + manifest, + handlers: host.handlers, + tape: { capacity: 64 }, + }); + + entry.node = snapshotFromEvaluateResult(nodeResult); + browserCases.push({ + id: fixture.id, + title: fixture.title, + kind: fixture.kind, + gasLimit: fixture.gasLimit.toString(), + manifest, + program: built.programArtifact, + }); + } catch (error) { + if (error instanceof DeterministicBuilderError) { + entry.node = { + stage: 'builder_reject', + resultHash: null, + errorCode: null, + errorTag: null, + gasUsed: '0', + gasRemaining: fixture.gasLimit.toString(), + tapeHash: null, + tapeLength: 0, + }; + entry.builder = { + ok: false, + diagnostics: error.diagnostics, + graphHash: null, + }; + } else { + throw error; + } + } + + nodeRecords.push(entry); +} + +const browserSnapshotsById = await runBrowserCases( + browserCases, + args.baseUrl, + args.browser, +); + +for (const record of nodeRecords) { + record.browser = browserSnapshotsById.get(record.id) ?? null; + record.match = determineFixtureMatch(record); +} + +const mismatches = nodeRecords.filter((record) => !record.match); +const positiveRecords = nodeRecords.filter( + (record) => record.kind === 'positive', +); +const negativeRecords = nodeRecords.filter( + (record) => record.kind === 'negative', +); +const flagshipRecords = nodeRecords.filter( + (record) => record.kind === 'flagship', +); +const compatibilityMatrix = nodeRecords.map((record) => ({ + id: record.id, + title: record.title, + kind: record.kind, + profile: record.profile, + expectedStage: record.expected.stage, + nodeStage: record.node?.stage ?? null, + browserStage: record.browser?.stage ?? null, + match: record.match, + diagnostics: record.builder?.diagnostics ?? [], +})); +const report = { + generatedAt: now.toISOString(), + browser: args.browser, + summary: { + total: nodeRecords.length, + withBrowserRuns: browserCases.length, + mismatches: mismatches.length, + greenCount: positiveRecords.length, + redCount: negativeRecords.length, + flagshipCount: flagshipRecords.length, + }, + compatibilityMatrix, + records: nodeRecords, + signature: { + algorithm: 'sha256', + digest: sha256Hex(JSON.stringify(nodeRecords)), + }, +}; + +const reportText = `${JSON.stringify(report, null, 2)}\n`; +await writeFile(jsonPath, reportText, 'utf8'); +await writeFile( + checksumPath, + `${sha256Hex(reportText)} ${path.basename(jsonPath)}\n`, + 'utf8', +); +await writeFile(mdPath, renderMarkdownReport(report), 'utf8'); +await writeFile( + matrixPath, + `${JSON.stringify( + { + generatedAt: now.toISOString(), + summary: report.summary, + compatibilityMatrix, + }, + null, + 2, + )}\n`, + 'utf8', +); + +console.log( + JSON.stringify( + { + jsonPath, + mdPath, + checksumPath, + matrixPath, + mismatches: mismatches.length, + }, + null, + 2, + ), +); + +if (mismatches.length > 0) { + process.exitCode = 1; +} + +function snapshotFromEvaluateResult(result) { + const tape = result.tape ?? []; + if (result.ok) { + return { + stage: 'success', + resultHash: sha256Hex(Buffer.from(encodeDv(result.value))), + errorCode: null, + errorTag: null, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + tapeHash: + tape.length > 0 + ? sha256Hex(Buffer.from(serializeHostTape(tape))) + : null, + tapeLength: tape.length, + }; + } + + return { + stage: normalizeFailureStage(result.error.kind), + resultHash: null, + errorCode: result.error.code, + errorTag: 'tag' in result.error ? result.error.tag : null, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + tapeHash: + tape.length > 0 ? sha256Hex(Buffer.from(serializeHostTape(tape))) : null, + tapeLength: tape.length, + }; +} + +function normalizeFailureStage(kind) { + if (kind === 'module-pack') { + return 'artifact_validation'; + } + if (kind === 'execution-surface-mismatch') { + return 'pin_enforcement'; + } + return 'runtime_error'; +} + +async function runBrowserCases(cases, baseUrlOverride, browserName) { + if (cases.length === 0) { + return new Map(); + } + + const viteServer = await createServer({ + configFile: path.join(appRoot, 'vite.config.mts'), + server: { + host: '127.0.0.1', + port: 4310, + strictPort: true, + }, + clearScreen: false, + }); + await viteServer.listen(); + + const baseUrl = baseUrlOverride ?? 'http://127.0.0.1:4310'; + const browserType = resolveBrowserType(browserName); + const browser = await browserType.launch({ headless: true }); + const context = await browser.newContext({ baseURL: baseUrl }); + + try { + const page = await context.newPage(); + await page.addInitScript((payload) => { + window.__ECOSYSTEM_CERT_CASES__ = payload; + }, cases); + await page.goto('/'); + await page.waitForSelector('[data-runstate="done"]', { timeout: 120000 }); + + const records = await page.evaluate( + () => window.__ECOSYSTEM_CERT_RESULTS__ ?? [], + ); + return new Map(records.map((record) => [record.id, record.browser])); + } finally { + await context.close(); + await browser.close(); + await viteServer.close(); + } +} + +function determineFixtureMatch(record) { + const expected = record.expected; + const node = record.node; + const browser = record.browser; + + if (expected.stage === 'builder_reject') { + return node.stage === 'builder_reject' && browser === null; + } + + if (expected.stage === 'success') { + return ( + node.stage === 'success' && + browser !== null && + JSON.stringify(node) === JSON.stringify(browser) + ); + } + + if (expected.stage === 'runtime_error') { + if (node.stage !== 'runtime_error' || browser === null) { + return false; + } + if (expected.errorCode && node.errorCode !== expected.errorCode) { + return false; + } + if (expected.errorTag && node.errorTag !== expected.errorTag) { + return false; + } + return JSON.stringify(node) === JSON.stringify(browser); + } + + return node.stage === expected.stage; +} + +function renderMarkdownReport(report) { + const lines = [ + '# Workload Certification Report (Generated)', + '', + `Generated: ${report.generatedAt}`, + '', + `- Total fixtures: ${report.summary.total}`, + `- Browser-evaluated fixtures: ${report.summary.withBrowserRuns}`, + `- Mismatches: ${report.summary.mismatches}`, + `- Green fixtures: ${report.summary.greenCount}`, + `- Red fixtures: ${report.summary.redCount}`, + '', + '| Fixture | Kind | Expected stage | Node stage | Browser stage | Match |', + '| --- | --- | --- | --- | --- | --- |', + ]; + + for (const record of report.records) { + lines.push( + `| ${record.id} | ${record.kind} | ${record.expected.stage} | ${record.node?.stage ?? 'n/a'} | ${record.browser?.stage ?? 'n/a'} | ${record.match ? 'yes' : 'no'} |`, + ); + } + + return `${lines.join('\n')}\n`; +} + +function parseArgs(argv) { + let outDir = 'artifacts/workload-certification'; + let baseUrl = null; + let browser = 'chromium'; + for (let i = 0; i < argv.length; i += 1) { + const arg = argv[i]; + if (arg === '--') { + continue; + } + if (arg === '--out-dir') { + outDir = argv[i + 1] ?? outDir; + i += 1; + continue; + } + if (arg === '--base-url') { + baseUrl = argv[i + 1] ?? baseUrl; + i += 1; + continue; + } + if (arg === '--browser') { + browser = argv[i + 1] ?? browser; + i += 1; + continue; + } + throw new Error(`unknown argument: ${arg}`); + } + return { outDir, baseUrl, browser }; +} + +function sha256Hex(input) { + return createHash('sha256').update(input).digest('hex'); +} + +function resolveBrowserType(browserName) { + if (browserName === 'chromium') { + return chromium; + } + if (browserName === 'firefox') { + return firefox; + } + if (browserName === 'webkit') { + return webkit; + } + throw new Error(`unsupported browser: ${browserName}`); +} diff --git a/apps/ecosystem-certifier/scripts/check-builder-determinism.mjs b/apps/ecosystem-certifier/scripts/check-builder-determinism.mjs new file mode 100644 index 0000000..28caa9a --- /dev/null +++ b/apps/ecosystem-certifier/scripts/check-builder-determinism.mjs @@ -0,0 +1,120 @@ +#!/usr/bin/env node + +import { createHash } from 'node:crypto'; +import fs from 'node:fs'; +import path from 'node:path'; +import { mkdir, writeFile } from 'node:fs/promises'; +import jiti from 'jiti'; +import { fileURLToPath } from 'node:url'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const repoRoot = path.resolve(__dirname, '..', '..', '..'); +const require = jiti(import.meta.url, { interopDefault: true }); +const { + buildDeterministicModulePack, +} = require('../../../libs/deterministic-bundler/src/index.ts'); +const { HOST_V1_HASH } = require('../../../libs/abi-manifest/src/index.ts'); + +const args = parseArgs(process.argv.slice(2)); +const outDir = path.resolve(repoRoot, args.outDir); +await mkdir(outDir, { recursive: true }); + +const fixtureSource = [ + 'const values = [3, 1, 2];', + 'values.sort((a, b) => a - b);', + 'export default {', + ' values,', + " joined: values.join(',')", + '};', + '', +].join('\n'); + +const tmpRoot = path.join(repoRoot, 'tmp', 'workload-certifier'); +await mkdir(tmpRoot, { recursive: true }); +const dirA = fs.mkdtempSync(path.join(tmpRoot, 'builder-det-a-')); +const dirB = fs.mkdtempSync(path.join(tmpRoot, 'builder-det-b-')); +await writeFixture(dirA, fixtureSource); +await writeFixture(dirB, fixtureSource); + +const builtA = await buildDeterministicModulePack({ + absWorkingDir: dirA, + entryPath: 'entry.ts', + profile: 'compat-general-v1', + emitProgramArtifact: true, + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, +}); +const builtB = await buildDeterministicModulePack({ + absWorkingDir: dirB, + entryPath: 'entry.ts', + profile: 'compat-general-v1', + emitProgramArtifact: true, + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, +}); + +const canonicalA = canonicalHash(builtA.modulePack); +const canonicalB = canonicalHash(builtB.modulePack); +const report = { + generatedAt: new Date().toISOString(), + fixtures: [ + { + workingDir: dirA, + graphHash: builtA.modulePack.graphHash, + canonicalHash: canonicalA, + moduleCount: builtA.modulePack.modules.length, + }, + { + workingDir: dirB, + graphHash: builtB.modulePack.graphHash, + canonicalHash: canonicalB, + moduleCount: builtB.modulePack.modules.length, + }, + ], + checks: { + graphHashEqual: builtA.modulePack.graphHash === builtB.modulePack.graphHash, + canonicalHashEqual: canonicalA === canonicalB, + }, +}; + +const outputPath = path.join(outDir, 'builder-determinism-report.json'); +await writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`, 'utf8'); + +console.log(JSON.stringify({ outputPath, checks: report.checks }, null, 2)); + +if (!report.checks.graphHashEqual || !report.checks.canonicalHashEqual) { + process.exitCode = 1; +} + +async function writeFixture(targetDir, source) { + await writeFile(path.join(targetDir, 'entry.ts'), source, 'utf8'); +} + +function canonicalHash(modulePack) { + const payload = JSON.stringify({ + entrySpecifier: modulePack.entrySpecifier, + entryExport: modulePack.entryExport, + modules: modulePack.modules.map((module) => ({ + specifier: module.specifier, + source: module.source, + sourceMap: module.sourceMap ?? null, + })), + }); + return createHash('sha256').update(payload).digest('hex'); +} + +function parseArgs(argv) { + let outDir = 'artifacts/workload-certification'; + for (let i = 0; i < argv.length; i += 1) { + const arg = argv[i]; + if (arg === '--out-dir') { + outDir = argv[i + 1] ?? outDir; + i += 1; + continue; + } + throw new Error(`unknown argument: ${arg}`); + } + return { outDir }; +} diff --git a/apps/ecosystem-certifier/scripts/generate-compatibility-delta-report.mjs b/apps/ecosystem-certifier/scripts/generate-compatibility-delta-report.mjs new file mode 100644 index 0000000..85d8fcb --- /dev/null +++ b/apps/ecosystem-certifier/scripts/generate-compatibility-delta-report.mjs @@ -0,0 +1,208 @@ +#!/usr/bin/env node + +import { mkdir, readFile, readdir, stat, writeFile } from 'node:fs/promises'; +import path from 'node:path'; +import process from 'node:process'; +import { fileURLToPath } from 'node:url'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const repoRoot = path.resolve(__dirname, '..', '..', '..'); +const args = parseArgs(process.argv.slice(2)); +const currentDir = path.resolve(repoRoot, args.currentDir); +const outDir = path.resolve(repoRoot, args.outDir); +const baselinePath = path.resolve(repoRoot, args.baselinePath); + +await mkdir(outDir, { recursive: true }); + +const baseline = JSON.parse(await readFile(baselinePath, 'utf8')); +const currentReportPath = + args.currentReport ?? + (await findNewestFile(currentDir, (entry) => + /^workload-certification-.*\.json$/.test(entry.name), + )); +const currentReport = JSON.parse(await readFile(currentReportPath, 'utf8')); + +const baselineFixtures = new Map( + baseline.fixtures.map((fixture) => [fixture.id, fixture]), +); +const currentFixturesRaw = + currentReport.compatibilityMatrix ?? + currentReport.records?.map((record) => ({ + id: record.id, + kind: record.kind, + expectedStage: record.expected?.stage ?? null, + nodeStage: record.node?.stage ?? null, + browserStage: record.browser?.stage ?? null, + profile: record.profile ?? null, + })) ?? + []; +const currentFixtures = new Map( + currentFixturesRaw.map((fixture) => [fixture.id, fixture]), +); + +const added = []; +const removed = []; +const stageChanges = []; +const profileCounts = new Map(); + +for (const [id, current] of currentFixtures.entries()) { + if (!baselineFixtures.has(id)) { + added.push({ + id, + kind: current.kind, + expectedStage: current.expectedStage, + profile: current.profile ?? null, + }); + } else { + const previous = baselineFixtures.get(id); + if (previous.expectedStage !== current.expectedStage) { + stageChanges.push({ + id, + kind: current.kind, + from: previous.expectedStage, + to: current.expectedStage, + }); + } + } + if (current.kind === 'positive') { + const profile = current.profile ?? 'unknown'; + profileCounts.set(profile, (profileCounts.get(profile) ?? 0) + 1); + } +} + +for (const [id, previous] of baselineFixtures.entries()) { + if (!currentFixtures.has(id)) { + removed.push({ + id, + kind: previous.kind, + expectedStage: previous.expectedStage, + }); + } +} + +const currentSummary = currentReport.summary ?? { + greenCount: currentFixturesRaw.filter( + (fixture) => fixture.kind === 'positive', + ).length, + redCount: currentFixturesRaw.filter((fixture) => fixture.kind === 'negative') + .length, + flagshipCount: currentFixturesRaw.filter( + (fixture) => fixture.kind === 'flagship', + ).length, +}; + +const delta = { + generatedAt: new Date().toISOString(), + baseline: { + release: baseline.release ?? 'unknown', + path: path.relative(repoRoot, baselinePath), + summary: baseline.summary ?? null, + }, + current: { + reportPath: path.relative(repoRoot, currentReportPath), + summary: currentSummary, + }, + deltas: { + greenDelta: + (currentSummary.greenCount ?? 0) - (baseline.summary?.greenCount ?? 0), + redDelta: + (currentSummary.redCount ?? 0) - (baseline.summary?.redCount ?? 0), + flagshipDelta: + (currentSummary.flagshipCount ?? 0) - + (baseline.summary?.flagshipCount ?? 0), + }, + added, + removed, + stageChanges, + positiveProfileCounts: Object.fromEntries( + [...profileCounts.entries()].sort((left, right) => + left[0].localeCompare(right[0]), + ), + ), +}; + +const outputPath = path.join(outDir, 'compatibility-delta-report.json'); +await writeFile(outputPath, `${JSON.stringify(delta, null, 2)}\n`, 'utf8'); + +process.stdout.write( + `${JSON.stringify( + { + outputPath: path.relative(repoRoot, outputPath), + greenDelta: delta.deltas.greenDelta, + addedCount: added.length, + removedCount: removed.length, + }, + null, + 2, + )}\n`, +); + +async function findNewestFile(rootDir, predicate) { + const files = await walk(rootDir); + let latest = null; + for (const filePath of files) { + const entry = { name: path.basename(filePath), path: filePath }; + if (!predicate(entry)) { + continue; + } + const fileStat = await stat(filePath); + if (!latest || fileStat.mtimeMs > latest.mtimeMs) { + latest = { filePath, mtimeMs: fileStat.mtimeMs }; + } + } + if (!latest) { + throw new Error(`no current report files found under ${rootDir}`); + } + return latest.filePath; +} + +async function walk(dirPath) { + const entries = await readdir(dirPath, { withFileTypes: true }); + const files = []; + for (const entry of entries) { + const fullPath = path.join(dirPath, entry.name); + if (entry.isDirectory()) { + files.push(...(await walk(fullPath))); + } else { + files.push(fullPath); + } + } + return files; +} + +function parseArgs(argv) { + const parsed = { + currentDir: 'artifacts/workload-certification', + outDir: 'artifacts/workload-certification', + baselinePath: 'docs/ecosystem-compatibility-baseline-0.4.1.json', + currentReport: null, + }; + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--') { + continue; + } + if (arg === '--current-dir') { + parsed.currentDir = argv[index + 1] ?? parsed.currentDir; + index += 1; + continue; + } + if (arg === '--out-dir') { + parsed.outDir = argv[index + 1] ?? parsed.outDir; + index += 1; + continue; + } + if (arg === '--baseline-path') { + parsed.baselinePath = argv[index + 1] ?? parsed.baselinePath; + index += 1; + continue; + } + if (arg === '--current-report') { + parsed.currentReport = argv[index + 1] ?? parsed.currentReport; + index += 1; + continue; + } + throw new Error(`unknown argument: ${arg}`); + } + return parsed; +} diff --git a/apps/ecosystem-certifier/scripts/generate-stress-corpus.mjs b/apps/ecosystem-certifier/scripts/generate-stress-corpus.mjs new file mode 100644 index 0000000..45baa90 --- /dev/null +++ b/apps/ecosystem-certifier/scripts/generate-stress-corpus.mjs @@ -0,0 +1,66 @@ +#!/usr/bin/env node + +import { mkdir, writeFile } from 'node:fs/promises'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const outputPath = path.resolve( + __dirname, + '../src/shared/fixtures/stress-corpus.generated.json', +); +const seed = 0x6d2b79f5; + +const rng = createXorShift(seed); +const markdownDocs = []; +const semverChecks = []; +const numericWork = []; + +for (let i = 0; i < 32; i += 1) { + const id = `doc-${i.toString().padStart(2, '0')}`; + const links = [ + `https://example.com/${Math.floor(rng() * 5000)}`, + `https://example.org/${Math.floor(rng() * 5000)}`, + ]; + markdownDocs.push({ + id, + markdown: `# ${id}\n\nLink A: ${links[0]}\n\nLink B: ${links[1]}\n`, + }); +} + +for (let i = 0; i < 128; i += 1) { + const major = 1 + Math.floor(rng() * 3); + const minor = Math.floor(rng() * 10); + const patch = Math.floor(rng() * 20); + const version = `${major}.${minor}.${patch}`; + semverChecks.push({ + version, + range: `>=${major}.${Math.max(0, minor - 1)}.0 <${major + 1}.0.0`, + }); +} + +for (let i = 0; i < 256; i += 1) { + numericWork.push(Math.floor(rng() * 100_000)); +} + +const payload = { + version: 1, + seed, + markdownDocs, + semverChecks, + numericWork, +}; + +await mkdir(path.dirname(outputPath), { recursive: true }); +await writeFile(outputPath, `${JSON.stringify(payload, null, 2)}\n`, 'utf8'); +console.log(JSON.stringify({ outputPath, docs: markdownDocs.length }, null, 2)); + +function createXorShift(initialSeed) { + let state = initialSeed >>> 0; + return () => { + state ^= state << 13; + state ^= state >>> 17; + state ^= state << 5; + return (state >>> 0) / 0xffffffff; + }; +} diff --git a/apps/ecosystem-certifier/scripts/run-oog-boundary-certification.mjs b/apps/ecosystem-certifier/scripts/run-oog-boundary-certification.mjs new file mode 100644 index 0000000..23d8d33 --- /dev/null +++ b/apps/ecosystem-certifier/scripts/run-oog-boundary-certification.mjs @@ -0,0 +1,158 @@ +#!/usr/bin/env node + +import { mkdir, writeFile } from 'node:fs/promises'; +import path from 'node:path'; +import process from 'node:process'; +import { + buildRunnableCasesByIds, + launchBrowserCertifier, + evaluateCaseNode, + repoRoot, +} from './_certifier-eval-helpers.mjs'; + +const args = parseArgs(process.argv.slice(2)); +const outDir = path.resolve(repoRoot, args.outDir); +await mkdir(outDir, { recursive: true }); + +const fixtureIds = args.fixtureIds ?? [ + 'flagship-knowledge-pack', + 'green-chess', + 'green-semver', + 'green-markdown-it', + 'green-stress-corpus', +]; + +const cases = await buildRunnableCasesByIds(fixtureIds); +const browser = await launchBrowserCertifier(args.baseUrl, args.browser); +const boundaries = []; + +try { + for (const certCase of cases) { + const maxGas = BigInt(certCase.gasLimit); + const nodeBoundary = await searchBoundary({ + low: 1n, + high: maxGas, + runSuccess: async (gasLimit) => { + const snapshot = await evaluateCaseNode(certCase, gasLimit.toString()); + return snapshot.stage === 'success'; + }, + }); + + const browserBoundary = await searchBoundary({ + low: 1n, + high: maxGas, + runSuccess: async (gasLimit) => { + const snapshot = await browser.evaluateCaseSnapshot( + certCase, + gasLimit.toString(), + ); + return snapshot.stage === 'success'; + }, + }); + + boundaries.push({ + id: certCase.id, + title: certCase.title, + node: { + firstSuccessGas: nodeBoundary.firstSuccessGas.toString(), + lastFailureGas: nodeBoundary.lastFailureGas.toString(), + }, + browser: { + firstSuccessGas: browserBoundary.firstSuccessGas.toString(), + lastFailureGas: browserBoundary.lastFailureGas.toString(), + }, + parity: { + firstSuccessEqual: + nodeBoundary.firstSuccessGas.toString() === + browserBoundary.firstSuccessGas.toString(), + lastFailureEqual: + nodeBoundary.lastFailureGas.toString() === + browserBoundary.lastFailureGas.toString(), + }, + }); + } +} finally { + await browser.close(); +} + +const mismatchCount = boundaries.filter( + (entry) => !entry.parity.firstSuccessEqual || !entry.parity.lastFailureEqual, +).length; +const output = { + generatedAt: new Date().toISOString(), + browser: args.browser, + fixtureCount: boundaries.length, + mismatchCount, + boundaries, +}; +const outputPath = path.join(outDir, 'oog-boundaries.json'); +await writeFile(outputPath, `${JSON.stringify(output, null, 2)}\n`, 'utf8'); + +console.log(JSON.stringify({ outputPath, mismatchCount }, null, 2)); +if (mismatchCount > 0) { + process.exitCode = 1; +} + +async function searchBoundary({ low, high, runSuccess }) { + let left = low; + let right = high; + const highSuccess = await runSuccess(right); + if (!highSuccess) { + throw new Error( + `upper bound ${high.toString()} failed; increase gas limit in fixture`, + ); + } + + while (left + 1n < right) { + const mid = (left + right) / 2n; + const ok = await runSuccess(mid); + if (ok) { + right = mid; + } else { + left = mid; + } + } + + return { + lastFailureGas: left, + firstSuccessGas: right, + }; +} + +function parseArgs(argv) { + let outDir = 'artifacts/workload-certification'; + let baseUrl = null; + let fixtureIds = null; + let browser = 'chromium'; + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--') { + continue; + } + if (arg === '--out-dir') { + outDir = argv[index + 1] ?? outDir; + index += 1; + continue; + } + if (arg === '--base-url') { + baseUrl = argv[index + 1] ?? baseUrl; + index += 1; + continue; + } + if (arg === '--fixtures') { + fixtureIds = (argv[index + 1] ?? '') + .split(',') + .map((value) => value.trim()) + .filter(Boolean); + index += 1; + continue; + } + if (arg === '--browser') { + browser = argv[index + 1] ?? browser; + index += 1; + continue; + } + throw new Error(`unknown argument: ${arg}`); + } + return { outDir, baseUrl, fixtureIds, browser }; +} diff --git a/apps/ecosystem-certifier/scripts/run-repeatability-certification.mjs b/apps/ecosystem-certifier/scripts/run-repeatability-certification.mjs new file mode 100644 index 0000000..eac8598 --- /dev/null +++ b/apps/ecosystem-certifier/scripts/run-repeatability-certification.mjs @@ -0,0 +1,156 @@ +#!/usr/bin/env node + +import { mkdir, writeFile } from 'node:fs/promises'; +import path from 'node:path'; +import process from 'node:process'; +import { + buildRunnableCasesByIds, + evaluateCaseNode, + launchBrowserCertifier, + repoRoot, +} from './_certifier-eval-helpers.mjs'; + +const args = parseArgs(process.argv.slice(2)); +const outDir = path.resolve(repoRoot, args.outDir); +await mkdir(outDir, { recursive: true }); + +const fixtures = args.fixtureIds ?? [ + 'flagship-knowledge-pack', + 'green-semver', + 'green-markdown-it', + 'green-stress-corpus', +]; +const runnableCases = await buildRunnableCasesByIds(fixtures); +const browser = await launchBrowserCertifier(args.baseUrl, args.browser); + +const records = []; +try { + for (const certCase of runnableCases) { + const iterations = + certCase.id === 'flagship-knowledge-pack' + ? args.flagshipIterations + : args.iterations; + + const nodeBaseline = await evaluateCaseNode(certCase, certCase.gasLimit); + const browserBaseline = await browser.evaluateCaseSnapshot( + certCase, + certCase.gasLimit, + ); + + let nodeDriftCount = 0; + let browserDriftCount = 0; + let crossParityDriftCount = + JSON.stringify(nodeBaseline) === JSON.stringify(browserBaseline) ? 0 : 1; + + for (let run = 1; run < iterations; run += 1) { + const nodeSnapshot = await evaluateCaseNode(certCase, certCase.gasLimit); + const browserSnapshot = await browser.evaluateCaseSnapshot( + certCase, + certCase.gasLimit, + ); + if (JSON.stringify(nodeSnapshot) !== JSON.stringify(nodeBaseline)) { + nodeDriftCount += 1; + } + if (JSON.stringify(browserSnapshot) !== JSON.stringify(browserBaseline)) { + browserDriftCount += 1; + } + if (JSON.stringify(nodeSnapshot) !== JSON.stringify(browserSnapshot)) { + crossParityDriftCount += 1; + } + } + + records.push({ + id: certCase.id, + title: certCase.title, + iterations, + baseline: { + node: nodeBaseline, + browser: browserBaseline, + }, + drift: { + nodeDriftCount, + browserDriftCount, + crossParityDriftCount, + }, + stable: + nodeDriftCount === 0 && + browserDriftCount === 0 && + crossParityDriftCount === 0, + }); + } +} finally { + await browser.close(); +} + +const unstableCount = records.filter((record) => !record.stable).length; +const output = { + generatedAt: new Date().toISOString(), + browser: args.browser, + fixtureCount: records.length, + unstableCount, + records, +}; +const outputPath = path.join(outDir, 'repeatability-report.json'); +await writeFile(outputPath, `${JSON.stringify(output, null, 2)}\n`, 'utf8'); + +console.log(JSON.stringify({ outputPath, unstableCount }, null, 2)); +if (unstableCount > 0) { + process.exitCode = 1; +} + +function parseArgs(argv) { + let outDir = 'artifacts/workload-certification'; + let baseUrl = null; + let iterations = 100; + let flagshipIterations = 40; + let fixtureIds = null; + let browser = 'chromium'; + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--') { + continue; + } + if (arg === '--out-dir') { + outDir = argv[index + 1] ?? outDir; + index += 1; + continue; + } + if (arg === '--base-url') { + baseUrl = argv[index + 1] ?? baseUrl; + index += 1; + continue; + } + if (arg === '--iterations') { + iterations = Number(argv[index + 1] ?? iterations); + index += 1; + continue; + } + if (arg === '--flagship-iterations') { + flagshipIterations = Number(argv[index + 1] ?? flagshipIterations); + index += 1; + continue; + } + if (arg === '--fixtures') { + fixtureIds = (argv[index + 1] ?? '') + .split(',') + .map((value) => value.trim()) + .filter(Boolean); + index += 1; + continue; + } + if (arg === '--browser') { + browser = argv[index + 1] ?? browser; + index += 1; + continue; + } + throw new Error(`unknown argument: ${arg}`); + } + return { + outDir, + baseUrl, + iterations, + flagshipIterations, + fixtureIds, + browser, + }; +} diff --git a/apps/ecosystem-certifier/scripts/run-seeded-property-corpus.mjs b/apps/ecosystem-certifier/scripts/run-seeded-property-corpus.mjs new file mode 100644 index 0000000..44774d4 --- /dev/null +++ b/apps/ecosystem-certifier/scripts/run-seeded-property-corpus.mjs @@ -0,0 +1,175 @@ +#!/usr/bin/env node + +import { mkdir, readFile, writeFile } from 'node:fs/promises'; +import path from 'node:path'; +import process from 'node:process'; +import jiti from 'jiti'; +import { + launchBrowserCertifier, + repoRoot, + snapshotFromEvaluateResult, +} from './_certifier-eval-helpers.mjs'; + +const require = jiti(import.meta.url, { interopDefault: true }); +const { + HOST_V1_HASH, + HOST_V1_MANIFEST, +} = require('../../../libs/abi-manifest/src/index.ts'); +const { evaluate } = require('../../../libs/quickjs-runtime/src/index.ts'); +const { createCertificationHost } = require('../src/shared/host.ts'); + +const propertySeedConfigPath = path.resolve( + repoRoot, + 'apps/ecosystem-certifier/src/shared/fixtures/property-seed-config.json', +); +const defaultConfig = JSON.parse( + await readFile(propertySeedConfigPath, 'utf8'), +); + +const args = parseArgs(process.argv.slice(2)); +const outDir = path.resolve(repoRoot, args.outDir); +await mkdir(outDir, { recursive: true }); + +const browser = await launchBrowserCertifier(args.baseUrl, args.browser); +const records = []; + +try { + for ( + let seed = args.seedStart; + seed < args.seedStart + args.seedCount; + seed += 1 + ) { + const certCase = createSeededCase(seed, args.gasLimit); + const host = createCertificationHost(); + const nodeResult = await evaluate({ + program: certCase.program, + input: { + event: { type: 'ecosystem-certifier' }, + eventCanonical: { type: 'ecosystem-certifier' }, + steps: [], + currentContract: { id: 'ecosystem-certifier' }, + currentContractCanonical: { id: { value: 'ecosystem-certifier' } }, + }, + gasLimit: BigInt(certCase.gasLimit), + manifest: HOST_V1_MANIFEST, + handlers: host.handlers, + tape: { capacity: 16 }, + }); + const nodeSnapshot = snapshotFromEvaluateResult(nodeResult); + const browserSnapshot = await browser.evaluateCaseSnapshot( + certCase, + certCase.gasLimit, + ); + const match = + JSON.stringify(nodeSnapshot) === JSON.stringify(browserSnapshot); + records.push({ + seed, + node: nodeSnapshot, + browser: browserSnapshot, + match, + }); + } +} finally { + await browser.close(); +} + +const mismatchCount = records.filter((record) => !record.match).length; +const output = { + generatedAt: new Date().toISOString(), + browser: args.browser, + seedStart: args.seedStart, + seedCount: args.seedCount, + mismatchCount, + records, +}; +const outputPath = path.join(outDir, 'seeded-property-corpus-report.json'); +await writeFile(outputPath, `${JSON.stringify(output, null, 2)}\n`, 'utf8'); + +console.log(JSON.stringify({ outputPath, mismatchCount }, null, 2)); +if (mismatchCount > 0) { + process.exitCode = 1; +} + +function createSeededCase(seed, gasLimit) { + const code = [ + `let x = ${seed} >>> 0;`, + 'function rnd() {', + ' x = ((x * 1664525) + 1013904223) >>> 0;', + ' return x;', + '}', + 'const values = [];', + 'for (let i = 0; i < 64; i += 1) values.push(rnd() % 10000);', + 'values.sort((a, b) => a - b);', + '({', + ` seed: ${seed},`, + ' sum: values.reduce((total, value) => total + value, 0),', + ' min: values[0],', + ' max: values[values.length - 1],', + ' checksum: values[3] ^ values[15] ^ values[31] ^ values[63],', + '});', + ].join('\n'); + + return { + id: `seed-${seed}`, + title: `seed-${seed}`, + kind: 'positive', + gasLimit: String(gasLimit), + manifest: HOST_V1_MANIFEST, + program: { + version: 2, + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + executionProfile: 'compat-general-v1', + sourceKind: 'script', + source: { code }, + }, + }; +} + +function parseArgs(argv) { + let outDir = 'artifacts/workload-certification'; + let baseUrl = null; + let seedStart = defaultConfig.seedStart; + let seedCount = defaultConfig.seedCount; + let gasLimit = defaultConfig.gasLimit; + let browser = 'chromium'; + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--') { + continue; + } + if (arg === '--out-dir') { + outDir = argv[index + 1] ?? outDir; + index += 1; + continue; + } + if (arg === '--base-url') { + baseUrl = argv[index + 1] ?? baseUrl; + index += 1; + continue; + } + if (arg === '--seed-start') { + seedStart = Number(argv[index + 1] ?? seedStart); + index += 1; + continue; + } + if (arg === '--seed-count') { + seedCount = Number(argv[index + 1] ?? seedCount); + index += 1; + continue; + } + if (arg === '--gas-limit') { + gasLimit = Number(argv[index + 1] ?? gasLimit); + index += 1; + continue; + } + if (arg === '--browser') { + browser = argv[index + 1] ?? browser; + index += 1; + continue; + } + throw new Error(`unknown argument: ${arg}`); + } + return { outDir, baseUrl, seedStart, seedCount, gasLimit, browser }; +} diff --git a/apps/ecosystem-certifier/src/browser/certifier.ts b/apps/ecosystem-certifier/src/browser/certifier.ts new file mode 100644 index 0000000..bcb9c0e --- /dev/null +++ b/apps/ecosystem-certifier/src/browser/certifier.ts @@ -0,0 +1,172 @@ +import { encodeDv } from '@blue-quickjs/dv'; +import { + type HostTapeRecord, + evaluate, + type EvaluateResult, +} from '@blue-quickjs/quickjs-runtime'; +import { serializeHostTape } from '@blue-quickjs/test-harness'; +import { createCertificationHost } from '../shared/host.js'; +import type { + BrowserEvaluationCase, + FailureStage, + FixtureParityRecord, + FixtureSnapshot, +} from '../shared/types.js'; + +declare global { + interface Window { + __ECOSYSTEM_CERT_CASES__?: BrowserEvaluationCase[]; + __ECOSYSTEM_CERT_RESULTS__?: FixtureParityRecord[]; + __ECOSYSTEM_CERT_RUNSTATE__?: 'idle' | 'running' | 'done' | 'error'; + __ECOSYSTEM_CERT_RUN_CASE__?: ( + certCase: BrowserEvaluationCase, + gasLimit?: string, + ) => Promise; + } +} + +export async function runBrowserCertifier(): Promise { + renderShell(); + const runstate = document.querySelector('[data-runstate]'); + const resultEl = document.querySelector('[data-results]'); + + try { + const cases = window.__ECOSYSTEM_CERT_CASES__ ?? []; + window.__ECOSYSTEM_CERT_RUN_CASE__ = evaluateCaseInBrowser; + window.__ECOSYSTEM_CERT_RUNSTATE__ = 'running'; + if (runstate) { + runstate.dataset.runstate = 'running'; + runstate.textContent = `Running ${cases.length} cases…`; + } + + const records: FixtureParityRecord[] = []; + for (const certCase of cases) { + const snapshot = await evaluateCaseInBrowser(certCase, certCase.gasLimit); + records.push({ + id: certCase.id, + title: certCase.title, + kind: certCase.kind, + node: snapshot, + browser: snapshot, + match: true, + }); + } + + window.__ECOSYSTEM_CERT_RESULTS__ = records; + window.__ECOSYSTEM_CERT_RUNSTATE__ = 'done'; + if (runstate) { + runstate.dataset.runstate = 'done'; + runstate.textContent = 'Done'; + } + if (resultEl) { + resultEl.textContent = JSON.stringify(records, null, 2); + } + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + window.__ECOSYSTEM_CERT_RESULTS__ = []; + window.__ECOSYSTEM_CERT_RUNSTATE__ = 'error'; + if (runstate) { + runstate.dataset.runstate = 'error'; + runstate.textContent = `Error: ${message}`; + } + if (resultEl) { + resultEl.textContent = message; + } + } +} + +function renderShell(): void { + const app = document.querySelector('[data-app]'); + if (!app) { + return; + } + app.innerHTML = ` +

Ecosystem Certifier (Browser Runner)

+

Idle

+
Waiting…
+ `; +} + +async function toSnapshot(result: EvaluateResult): Promise { + const tape = result.tape ?? []; + const tapeHash = await hashTape(tape); + if (result.ok) { + return { + stage: 'success', + resultHash: await hashDv(result.value), + errorCode: null, + errorTag: null, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + tapeHash, + tapeLength: tape.length, + }; + } + + return { + stage: normalizeFailureStage(result.error.kind), + resultHash: null, + errorCode: result.error.code, + errorTag: 'tag' in result.error ? result.error.tag : null, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + tapeHash, + tapeLength: tape.length, + }; +} + +async function evaluateCaseInBrowser( + certCase: BrowserEvaluationCase, + gasLimit?: string, +): Promise { + const host = createCertificationHost(); + const result = await evaluate({ + program: certCase.program, + input: { + event: { type: 'ecosystem-certifier' }, + eventCanonical: { type: 'ecosystem-certifier' }, + steps: [], + currentContract: { id: 'ecosystem-certifier' }, + currentContractCanonical: { id: { value: 'ecosystem-certifier' } }, + }, + gasLimit: BigInt(gasLimit ?? certCase.gasLimit), + manifest: certCase.manifest, + handlers: host.handlers, + tape: { capacity: 64 }, + }); + return toSnapshot(result); +} + +function normalizeFailureStage(kind: string): FailureStage { + if (kind === 'module-pack') { + return 'artifact_validation'; + } + if (kind === 'execution-surface-mismatch') { + return 'pin_enforcement'; + } + return 'runtime_error'; +} + +async function hashDv(value: unknown): Promise { + return sha256Hex(encodeDv(value)); +} + +async function hashTape(tape: HostTapeRecord[]): Promise { + if (tape.length === 0) { + return null; + } + return sha256Hex(new TextEncoder().encode(serializeHostTape(tape))); +} + +async function sha256Hex(data: Uint8Array): Promise { + const digest = await crypto.subtle.digest('SHA-256', toArrayBuffer(data)); + const bytes = new Uint8Array(digest); + return [...bytes].map((byte) => byte.toString(16).padStart(2, '0')).join(''); +} + +function toArrayBuffer(data: Uint8Array): ArrayBuffer { + if (data.byteOffset === 0 && data.byteLength === data.buffer.byteLength) { + return data.buffer as ArrayBuffer; + } + return data.slice().buffer; +} diff --git a/apps/ecosystem-certifier/src/main.ts b/apps/ecosystem-certifier/src/main.ts new file mode 100644 index 0000000..7600e16 --- /dev/null +++ b/apps/ecosystem-certifier/src/main.ts @@ -0,0 +1,3 @@ +import { runBrowserCertifier } from './browser/certifier.js'; + +void runBrowserCertifier(); diff --git a/apps/ecosystem-certifier/src/shared/builder-determinism.spec.ts b/apps/ecosystem-certifier/src/shared/builder-determinism.spec.ts new file mode 100644 index 0000000..fa36128 --- /dev/null +++ b/apps/ecosystem-certifier/src/shared/builder-determinism.spec.ts @@ -0,0 +1,25 @@ +import { compareBuilderReports } from './builder-determinism.js'; + +describe('builder determinism helpers', () => { + it('detects hash mismatches between reports', () => { + const result = compareBuilderReports( + { + checks: { graphHashEqual: true, canonicalHashEqual: true }, + fixtures: [ + { graphHash: 'a', canonicalHash: 'b' }, + { graphHash: 'c', canonicalHash: 'd' }, + ], + }, + { + checks: { graphHashEqual: false, canonicalHashEqual: false }, + fixtures: [ + { graphHash: 'a', canonicalHash: 'x' }, + { graphHash: 'z', canonicalHash: 'd' }, + ], + }, + ); + + expect(result.graphHashMismatchCount).toBe(1); + expect(result.canonicalHashMismatchCount).toBe(1); + }); +}); diff --git a/apps/ecosystem-certifier/src/shared/builder-determinism.ts b/apps/ecosystem-certifier/src/shared/builder-determinism.ts new file mode 100644 index 0000000..63fccdd --- /dev/null +++ b/apps/ecosystem-certifier/src/shared/builder-determinism.ts @@ -0,0 +1,43 @@ +export interface BuilderDeterminismFixture { + graphHash: string; + canonicalHash: string; +} + +export interface BuilderDeterminismReport { + checks: { + graphHashEqual: boolean; + canonicalHashEqual: boolean; + }; + fixtures: BuilderDeterminismFixture[]; +} + +export function compareBuilderReports( + baseline: BuilderDeterminismReport, + candidate: BuilderDeterminismReport, +): { graphHashMismatchCount: number; canonicalHashMismatchCount: number } { + let graphHashMismatchCount = 0; + let canonicalHashMismatchCount = 0; + + const fixtureCount = Math.min( + baseline.fixtures.length, + candidate.fixtures.length, + ); + for (let index = 0; index < fixtureCount; index += 1) { + if ( + baseline.fixtures[index].graphHash !== candidate.fixtures[index].graphHash + ) { + graphHashMismatchCount += 1; + } + if ( + baseline.fixtures[index].canonicalHash !== + candidate.fixtures[index].canonicalHash + ) { + canonicalHashMismatchCount += 1; + } + } + + return { + graphHashMismatchCount, + canonicalHashMismatchCount, + }; +} diff --git a/apps/ecosystem-certifier/src/shared/fixtures.spec.ts b/apps/ecosystem-certifier/src/shared/fixtures.spec.ts new file mode 100644 index 0000000..f61b245 --- /dev/null +++ b/apps/ecosystem-certifier/src/shared/fixtures.spec.ts @@ -0,0 +1,15 @@ +import { CERTIFIER_FIXTURES } from './fixtures.js'; + +describe('ecosystem certifier fixture catalog', () => { + it('includes flagship, positive, and negative fixtures', () => { + const kinds = new Set(CERTIFIER_FIXTURES.map((fixture) => fixture.kind)); + expect(kinds.has('flagship')).toBe(true); + expect(kinds.has('positive')).toBe(true); + expect(kinds.has('negative')).toBe(true); + }); + + it('uses unique ids', () => { + const ids = CERTIFIER_FIXTURES.map((fixture) => fixture.id); + expect(new Set(ids).size).toBe(ids.length); + }); +}); diff --git a/apps/ecosystem-certifier/src/shared/fixtures.ts b/apps/ecosystem-certifier/src/shared/fixtures.ts new file mode 100644 index 0000000..64b65f9 --- /dev/null +++ b/apps/ecosystem-certifier/src/shared/fixtures.ts @@ -0,0 +1,448 @@ +import { + HOST_V1_HASH, + HOST_V1_MANIFEST, + HOST_V2_HASH, + HOST_V2_MANIFEST, +} from '@blue-quickjs/abi-manifest'; +import type { AbiManifest } from '@blue-quickjs/abi-manifest'; +import type { BuildFixtureDefinition } from './types.js'; + +export const CERTIFIER_FIXTURES: BuildFixtureDefinition[] = [ + { + id: 'flagship-knowledge-pack', + title: 'Flagship knowledge/compliance pack processor', + kind: 'flagship', + entryPath: + 'apps/ecosystem-certifier/fixtures/flagship/knowledge-pack-entry.ts', + profile: 'compat-binary-v1', + abiId: 'Host.v2', + abiVersion: 2, + abiManifestHash: HOST_V2_HASH, + gasLimit: 8_000_000n, + expect: { stage: 'success' }, + }, + { + id: 'green-chess', + title: 'chess.js deterministic move legality', + kind: 'positive', + entryPath: 'libs/test-harness/fixtures/library-reuse/chess-entry.ts', + profile: 'compat-general-v1', + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + gasLimit: 5_000_000n, + expect: { stage: 'success' }, + }, + { + id: 'green-base64', + title: 'base64-js deterministic roundtrip', + kind: 'positive', + entryPath: + 'libs/test-harness/fixtures/library-reuse/binary-base64-entry.ts', + profile: 'compat-binary-v1', + abiId: 'Host.v2', + abiVersion: 2, + abiManifestHash: HOST_V2_HASH, + gasLimit: 5_000_000n, + expect: { stage: 'success' }, + }, + { + id: 'green-noble-sha', + title: '@noble/hashes deterministic digest', + kind: 'positive', + entryPath: + 'libs/test-harness/fixtures/library-reuse/binary-sha256-entry.ts', + profile: 'compat-binary-v1', + abiId: 'Host.v2', + abiVersion: 2, + abiManifestHash: HOST_V2_HASH, + gasLimit: 5_000_000n, + expect: { stage: 'success' }, + }, + { + id: 'green-semver', + title: 'semver constraint evaluation', + kind: 'positive', + entryPath: 'apps/ecosystem-certifier/fixtures/positive/semver-entry.ts', + profile: 'compat-general-v1', + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + gasLimit: 1_000_000n, + expect: { stage: 'success' }, + }, + { + id: 'green-he', + title: 'he deterministic HTML entity decode', + kind: 'positive', + entryPath: 'apps/ecosystem-certifier/fixtures/positive/he-entry.ts', + profile: 'compat-general-v1', + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + gasLimit: 1_000_000n, + expect: { stage: 'success' }, + }, + { + id: 'green-path-to-regexp', + title: 'path-to-regexp deterministic path match', + kind: 'positive', + entryPath: + 'apps/ecosystem-certifier/fixtures/positive/path-to-regexp-entry.ts', + profile: 'compat-general-v1', + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + gasLimit: 1_000_000n, + expect: { stage: 'success' }, + }, + { + id: 'green-fast-json-stable-stringify', + title: 'fast-json-stable-stringify canonical output', + kind: 'positive', + entryPath: + 'apps/ecosystem-certifier/fixtures/positive/fast-json-stable-stringify-entry.ts', + profile: 'compat-general-v1', + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + gasLimit: 1_000_000n, + expect: { stage: 'success' }, + }, + { + id: 'green-json-logic-js', + title: 'json-logic-js deterministic rule application', + kind: 'positive', + entryPath: 'apps/ecosystem-certifier/fixtures/positive/json-logic-entry.ts', + profile: 'compat-general-v1', + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + gasLimit: 1_000_000n, + expect: { stage: 'success' }, + }, + { + id: 'green-crc32', + title: 'crc-32 deterministic checksum calculation', + kind: 'positive', + entryPath: 'apps/ecosystem-certifier/fixtures/positive/crc32-entry.ts', + profile: 'compat-binary-v1', + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + gasLimit: 1_000_000n, + expect: { stage: 'success' }, + }, + { + id: 'green-tinyqueue', + title: 'tinyqueue deterministic priority ordering', + kind: 'positive', + entryPath: 'apps/ecosystem-certifier/fixtures/positive/tinyqueue-entry.ts', + profile: 'compat-general-v1', + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + gasLimit: 1_000_000n, + expect: { stage: 'success' }, + }, + { + id: 'green-fflate', + title: 'fflate deterministic compression roundtrip', + kind: 'positive', + entryPath: 'apps/ecosystem-certifier/fixtures/positive/fflate-entry.ts', + profile: 'compat-binary-v1', + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + gasLimit: 5_000_000n, + expect: { stage: 'success' }, + }, + { + id: 'green-linkify-it', + title: 'linkify-it deterministic URL extraction', + kind: 'positive', + entryPath: 'apps/ecosystem-certifier/fixtures/positive/linkify-it-entry.ts', + profile: 'compat-general-v1', + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + gasLimit: 1_000_000n, + expect: { stage: 'success' }, + }, + { + id: 'green-markdown-it', + title: 'markdown-it deterministic tokenization', + kind: 'positive', + entryPath: + 'apps/ecosystem-certifier/fixtures/positive/markdown-it-entry.ts', + profile: 'compat-binary-v1', + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + gasLimit: 1_000_000n, + expect: { stage: 'success' }, + }, + { + id: 'green-escape-string-regexp', + title: 'escape-string-regexp deterministic escaping', + kind: 'positive', + entryPath: + 'apps/ecosystem-certifier/fixtures/positive/escape-string-regexp-entry.ts', + profile: 'compat-general-v1', + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + gasLimit: 1_000_000n, + expect: { stage: 'success' }, + }, + { + id: 'green-fast-deep-equal', + title: 'fast-deep-equal deterministic structure comparison', + kind: 'positive', + entryPath: + 'apps/ecosystem-certifier/fixtures/positive/fast-deep-equal-entry.ts', + profile: 'compat-general-v1', + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + gasLimit: 1_000_000n, + expect: { stage: 'success' }, + }, + { + id: 'green-stress-corpus', + title: 'seeded stress corpus deterministic summary', + kind: 'positive', + entryPath: + 'apps/ecosystem-certifier/fixtures/positive/stress-corpus-entry.ts', + profile: 'compat-general-v1', + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + gasLimit: 1_000_000n, + expect: { stage: 'success' }, + }, + { + id: 'green-camelcase', + title: 'camelcase deterministic normalization', + kind: 'positive', + entryPath: 'apps/ecosystem-certifier/fixtures/positive/camelcase-entry.ts', + profile: 'compat-general-v1', + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + gasLimit: 1_000_000n, + expect: { stage: 'success' }, + }, + { + id: 'green-decamelize', + title: 'decamelize deterministic token splitting', + kind: 'positive', + entryPath: 'apps/ecosystem-certifier/fixtures/positive/decamelize-entry.ts', + profile: 'compat-general-v1', + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + gasLimit: 1_000_000n, + expect: { stage: 'success' }, + }, + { + id: 'green-fastest-levenshtein', + title: 'fastest-levenshtein deterministic edit distance', + kind: 'positive', + entryPath: + 'apps/ecosystem-certifier/fixtures/positive/fastest-levenshtein-entry.ts', + profile: 'compat-binary-v1', + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + gasLimit: 1_000_000n, + expect: { stage: 'success' }, + }, + { + id: 'green-dijkstrajs', + title: 'dijkstrajs deterministic shortest path', + kind: 'positive', + entryPath: 'apps/ecosystem-certifier/fixtures/positive/dijkstrajs-entry.ts', + profile: 'compat-general-v1', + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + gasLimit: 1_000_000n, + expect: { stage: 'success' }, + }, + { + id: 'green-spark-md5', + title: 'spark-md5 deterministic hash digest', + kind: 'positive', + entryPath: 'apps/ecosystem-certifier/fixtures/positive/spark-md5-entry.ts', + profile: 'compat-binary-v1', + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + gasLimit: 1_000_000n, + expect: { stage: 'success' }, + }, + { + id: 'green-query-string', + title: 'query-string deterministic parse/stringify', + kind: 'positive', + entryPath: + 'apps/ecosystem-certifier/fixtures/positive/query-string-entry.ts', + profile: 'compat-general-v1', + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + gasLimit: 1_000_000n, + expect: { stage: 'success' }, + }, + { + id: 'green-deepmerge', + title: 'deepmerge deterministic object merge', + kind: 'positive', + entryPath: 'apps/ecosystem-certifier/fixtures/positive/deepmerge-entry.ts', + profile: 'compat-general-v1', + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + gasLimit: 1_000_000n, + expect: { stage: 'success' }, + }, + { + id: 'green-sort-keys', + title: 'sort-keys deterministic object ordering', + kind: 'positive', + entryPath: 'apps/ecosystem-certifier/fixtures/positive/sort-keys-entry.ts', + profile: 'compat-general-v1', + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + gasLimit: 1_000_000n, + expect: { stage: 'success' }, + }, + { + id: 'green-array-move', + title: 'array-move deterministic list reordering', + kind: 'positive', + entryPath: 'apps/ecosystem-certifier/fixtures/positive/array-move-entry.ts', + profile: 'compat-general-v1', + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + gasLimit: 1_000_000n, + expect: { stage: 'success' }, + }, + { + id: 'red-diff-timers', + title: 'diff package timer references are deterministically rejected', + kind: 'negative', + entryPath: 'apps/ecosystem-certifier/fixtures/positive/diff-entry.ts', + profile: 'compat-general-v1', + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + gasLimit: 1_000_000n, + expect: { stage: 'builder_reject' }, + }, + { + id: 'red-yaml-date', + title: 'yaml package date usage is deterministically rejected', + kind: 'negative', + entryPath: 'apps/ecosystem-certifier/fixtures/positive/yaml-entry.ts', + profile: 'compat-binary-v1', + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + gasLimit: 1_000_000n, + expect: { stage: 'builder_reject' }, + }, + { + id: 'red-graphlib-proxy', + title: 'graphlib proxy usage is deterministically rejected', + kind: 'negative', + entryPath: 'apps/ecosystem-certifier/fixtures/negative/graphlib-entry.ts', + profile: 'compat-binary-v1', + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + gasLimit: 1_000_000n, + expect: { stage: 'builder_reject' }, + }, + { + id: 'red-dynamic-import', + title: 'dynamic import must be rejected at build stage', + kind: 'negative', + entryPath: + 'apps/ecosystem-certifier/fixtures/negative/dynamic-import-entry.ts', + profile: 'compat-general-v1', + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + gasLimit: 1_000_000n, + expect: { stage: 'builder_reject' }, + }, + { + id: 'red-proxy', + title: 'Proxy usage must be rejected at build stage', + kind: 'negative', + entryPath: 'apps/ecosystem-certifier/fixtures/negative/proxy-entry.ts', + profile: 'compat-general-v1', + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + gasLimit: 1_000_000n, + expect: { stage: 'builder_reject' }, + }, + { + id: 'red-math-random', + title: 'Math.random usage must be rejected at build stage', + kind: 'negative', + entryPath: + 'apps/ecosystem-certifier/fixtures/negative/math-random-entry.ts', + profile: 'compat-general-v1', + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + gasLimit: 1_000_000n, + expect: { stage: 'builder_reject' }, + }, + { + id: 'red-lodash-function-constructor', + title: 'lodash-es root detection hits Function constructor in runtime', + kind: 'negative', + entryPath: 'apps/ecosystem-certifier/fixtures/positive/lodash-es-entry.ts', + profile: 'compat-binary-v1', + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + gasLimit: 1_000_000n, + expect: { + stage: 'artifact_validation', + errorCode: 'MODULE_EXPORT_MISSING', + errorTag: 'vm/module_pack', + }, + }, + { + id: 'red-function-constructor', + title: + 'Function constructor must fail deterministically in module-pack flow', + kind: 'negative', + entryPath: + 'apps/ecosystem-certifier/fixtures/negative/function-constructor-entry.ts', + profile: 'compat-general-v1', + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + gasLimit: 1_000_000n, + expect: { + stage: 'artifact_validation', + errorCode: 'MODULE_EXPORT_MISSING', + errorTag: 'vm/module_pack', + }, + }, +]; + +export function manifestForFixture( + fixture: BuildFixtureDefinition, +): AbiManifest { + return fixture.abiId === 'Host.v2' ? HOST_V2_MANIFEST : HOST_V1_MANIFEST; +} diff --git a/apps/ecosystem-certifier/src/shared/fixtures/compat-negative.ts b/apps/ecosystem-certifier/src/shared/fixtures/compat-negative.ts new file mode 100644 index 0000000..5bf5035 --- /dev/null +++ b/apps/ecosystem-certifier/src/shared/fixtures/compat-negative.ts @@ -0,0 +1,5 @@ +import { CERTIFIER_FIXTURES } from '../fixtures.js'; + +export const NEGATIVE_COMPAT_FIXTURES = CERTIFIER_FIXTURES.filter( + (fixture) => fixture.kind === 'negative', +); diff --git a/apps/ecosystem-certifier/src/shared/fixtures/compat-positive.ts b/apps/ecosystem-certifier/src/shared/fixtures/compat-positive.ts new file mode 100644 index 0000000..8a53e02 --- /dev/null +++ b/apps/ecosystem-certifier/src/shared/fixtures/compat-positive.ts @@ -0,0 +1,5 @@ +import { CERTIFIER_FIXTURES } from '../fixtures.js'; + +export const POSITIVE_COMPAT_FIXTURES = CERTIFIER_FIXTURES.filter( + (fixture) => fixture.kind === 'positive', +); diff --git a/apps/ecosystem-certifier/src/shared/fixtures/flagship-pack.ts b/apps/ecosystem-certifier/src/shared/fixtures/flagship-pack.ts new file mode 100644 index 0000000..f9e9f62 --- /dev/null +++ b/apps/ecosystem-certifier/src/shared/fixtures/flagship-pack.ts @@ -0,0 +1,9 @@ +import { CERTIFIER_FIXTURES } from '../fixtures.js'; + +export const FLAGSHIP_FIXTURE_IDS = ['flagship-knowledge-pack'] as const; + +export const FLAGSHIP_FIXTURES = CERTIFIER_FIXTURES.filter((fixture) => + FLAGSHIP_FIXTURE_IDS.includes( + fixture.id as (typeof FLAGSHIP_FIXTURE_IDS)[number], + ), +); diff --git a/apps/ecosystem-certifier/src/shared/fixtures/property-seed-config.json b/apps/ecosystem-certifier/src/shared/fixtures/property-seed-config.json new file mode 100644 index 0000000..6631adb --- /dev/null +++ b/apps/ecosystem-certifier/src/shared/fixtures/property-seed-config.json @@ -0,0 +1,5 @@ +{ + "seedStart": 1, + "seedCount": 80, + "gasLimit": 600000 +} diff --git a/apps/ecosystem-certifier/src/shared/fixtures/stress-corpus.generated.json b/apps/ecosystem-certifier/src/shared/fixtures/stress-corpus.generated.json new file mode 100644 index 0000000..992fc4b --- /dev/null +++ b/apps/ecosystem-certifier/src/shared/fixtures/stress-corpus.generated.json @@ -0,0 +1,674 @@ +{ + "version": 1, + "seed": 1831565813, + "markdownDocs": [ + { + "id": "doc-00", + "markdown": "# doc-00\n\nLink A: https://example.com/1263\n\nLink B: https://example.org/2849\n" + }, + { + "id": "doc-01", + "markdown": "# doc-01\n\nLink A: https://example.com/3048\n\nLink B: https://example.org/1981\n" + }, + { + "id": "doc-02", + "markdown": "# doc-02\n\nLink A: https://example.com/308\n\nLink B: https://example.org/1199\n" + }, + { + "id": "doc-03", + "markdown": "# doc-03\n\nLink A: https://example.com/4670\n\nLink B: https://example.org/2422\n" + }, + { + "id": "doc-04", + "markdown": "# doc-04\n\nLink A: https://example.com/4871\n\nLink B: https://example.org/268\n" + }, + { + "id": "doc-05", + "markdown": "# doc-05\n\nLink A: https://example.com/3122\n\nLink B: https://example.org/1237\n" + }, + { + "id": "doc-06", + "markdown": "# doc-06\n\nLink A: https://example.com/2945\n\nLink B: https://example.org/1419\n" + }, + { + "id": "doc-07", + "markdown": "# doc-07\n\nLink A: https://example.com/4503\n\nLink B: https://example.org/1560\n" + }, + { + "id": "doc-08", + "markdown": "# doc-08\n\nLink A: https://example.com/3780\n\nLink B: https://example.org/2057\n" + }, + { + "id": "doc-09", + "markdown": "# doc-09\n\nLink A: https://example.com/4650\n\nLink B: https://example.org/2696\n" + }, + { + "id": "doc-10", + "markdown": "# doc-10\n\nLink A: https://example.com/2844\n\nLink B: https://example.org/692\n" + }, + { + "id": "doc-11", + "markdown": "# doc-11\n\nLink A: https://example.com/3343\n\nLink B: https://example.org/3032\n" + }, + { + "id": "doc-12", + "markdown": "# doc-12\n\nLink A: https://example.com/4271\n\nLink B: https://example.org/2407\n" + }, + { + "id": "doc-13", + "markdown": "# doc-13\n\nLink A: https://example.com/2243\n\nLink B: https://example.org/1918\n" + }, + { + "id": "doc-14", + "markdown": "# doc-14\n\nLink A: https://example.com/2271\n\nLink B: https://example.org/2538\n" + }, + { + "id": "doc-15", + "markdown": "# doc-15\n\nLink A: https://example.com/3324\n\nLink B: https://example.org/1767\n" + }, + { + "id": "doc-16", + "markdown": "# doc-16\n\nLink A: https://example.com/3532\n\nLink B: https://example.org/2534\n" + }, + { + "id": "doc-17", + "markdown": "# doc-17\n\nLink A: https://example.com/4887\n\nLink B: https://example.org/651\n" + }, + { + "id": "doc-18", + "markdown": "# doc-18\n\nLink A: https://example.com/279\n\nLink B: https://example.org/555\n" + }, + { + "id": "doc-19", + "markdown": "# doc-19\n\nLink A: https://example.com/3411\n\nLink B: https://example.org/3593\n" + }, + { + "id": "doc-20", + "markdown": "# doc-20\n\nLink A: https://example.com/4237\n\nLink B: https://example.org/3182\n" + }, + { + "id": "doc-21", + "markdown": "# doc-21\n\nLink A: https://example.com/360\n\nLink B: https://example.org/2483\n" + }, + { + "id": "doc-22", + "markdown": "# doc-22\n\nLink A: https://example.com/307\n\nLink B: https://example.org/1260\n" + }, + { + "id": "doc-23", + "markdown": "# doc-23\n\nLink A: https://example.com/3394\n\nLink B: https://example.org/2456\n" + }, + { + "id": "doc-24", + "markdown": "# doc-24\n\nLink A: https://example.com/3304\n\nLink B: https://example.org/191\n" + }, + { + "id": "doc-25", + "markdown": "# doc-25\n\nLink A: https://example.com/1370\n\nLink B: https://example.org/675\n" + }, + { + "id": "doc-26", + "markdown": "# doc-26\n\nLink A: https://example.com/3934\n\nLink B: https://example.org/3646\n" + }, + { + "id": "doc-27", + "markdown": "# doc-27\n\nLink A: https://example.com/1102\n\nLink B: https://example.org/84\n" + }, + { + "id": "doc-28", + "markdown": "# doc-28\n\nLink A: https://example.com/2013\n\nLink B: https://example.org/1018\n" + }, + { + "id": "doc-29", + "markdown": "# doc-29\n\nLink A: https://example.com/2449\n\nLink B: https://example.org/2095\n" + }, + { + "id": "doc-30", + "markdown": "# doc-30\n\nLink A: https://example.com/4050\n\nLink B: https://example.org/1412\n" + }, + { + "id": "doc-31", + "markdown": "# doc-31\n\nLink A: https://example.com/4586\n\nLink B: https://example.org/2470\n" + } + ], + "semverChecks": [ + { + "version": "2.8.11", + "range": ">=2.7.0 <3.0.0" + }, + { + "version": "3.9.4", + "range": ">=3.8.0 <4.0.0" + }, + { + "version": "3.3.17", + "range": ">=3.2.0 <4.0.0" + }, + { + "version": "2.6.11", + "range": ">=2.5.0 <3.0.0" + }, + { + "version": "2.3.5", + "range": ">=2.2.0 <3.0.0" + }, + { + "version": "1.2.4", + "range": ">=1.1.0 <2.0.0" + }, + { + "version": "2.0.7", + "range": ">=2.0.0 <3.0.0" + }, + { + "version": "2.3.4", + "range": ">=2.2.0 <3.0.0" + }, + { + "version": "2.7.12", + "range": ">=2.6.0 <3.0.0" + }, + { + "version": "2.0.3", + "range": ">=2.0.0 <3.0.0" + }, + { + "version": "2.8.2", + "range": ">=2.7.0 <3.0.0" + }, + { + "version": "1.7.8", + "range": ">=1.6.0 <2.0.0" + }, + { + "version": "1.0.4", + "range": ">=1.0.0 <2.0.0" + }, + { + "version": "1.1.15", + "range": ">=1.0.0 <2.0.0" + }, + { + "version": "2.9.11", + "range": ">=2.8.0 <3.0.0" + }, + { + "version": "2.0.10", + "range": ">=2.0.0 <3.0.0" + }, + { + "version": "1.8.6", + "range": ">=1.7.0 <2.0.0" + }, + { + "version": "2.6.11", + "range": ">=2.5.0 <3.0.0" + }, + { + "version": "3.7.16", + "range": ">=3.6.0 <4.0.0" + }, + { + "version": "3.7.5", + "range": ">=3.6.0 <4.0.0" + }, + { + "version": "1.4.8", + "range": ">=1.3.0 <2.0.0" + }, + { + "version": "3.5.0", + "range": ">=3.4.0 <4.0.0" + }, + { + "version": "3.4.15", + "range": ">=3.3.0 <4.0.0" + }, + { + "version": "3.3.16", + "range": ">=3.2.0 <4.0.0" + }, + { + "version": "3.9.16", + "range": ">=3.8.0 <4.0.0" + }, + { + "version": "2.6.3", + "range": ">=2.5.0 <3.0.0" + }, + { + "version": "3.0.6", + "range": ">=3.0.0 <4.0.0" + }, + { + "version": "2.5.8", + "range": ">=2.4.0 <3.0.0" + }, + { + "version": "2.3.17", + "range": ">=2.2.0 <3.0.0" + }, + { + "version": "1.2.11", + "range": ">=1.1.0 <2.0.0" + }, + { + "version": "3.9.17", + "range": ">=3.8.0 <4.0.0" + }, + { + "version": "2.2.5", + "range": ">=2.1.0 <3.0.0" + }, + { + "version": "3.6.14", + "range": ">=3.5.0 <4.0.0" + }, + { + "version": "2.6.15", + "range": ">=2.5.0 <3.0.0" + }, + { + "version": "3.3.10", + "range": ">=3.2.0 <4.0.0" + }, + { + "version": "3.4.4", + "range": ">=3.3.0 <4.0.0" + }, + { + "version": "1.2.16", + "range": ">=1.1.0 <2.0.0" + }, + { + "version": "3.7.17", + "range": ">=3.6.0 <4.0.0" + }, + { + "version": "2.4.8", + "range": ">=2.3.0 <3.0.0" + }, + { + "version": "2.1.10", + "range": ">=2.0.0 <3.0.0" + }, + { + "version": "3.0.10", + "range": ">=3.0.0 <4.0.0" + }, + { + "version": "2.7.1", + "range": ">=2.6.0 <3.0.0" + }, + { + "version": "1.8.5", + "range": ">=1.7.0 <2.0.0" + }, + { + "version": "3.6.15", + "range": ">=3.5.0 <4.0.0" + }, + { + "version": "3.9.5", + "range": ">=3.8.0 <4.0.0" + }, + { + "version": "3.6.12", + "range": ">=3.5.0 <4.0.0" + }, + { + "version": "3.3.4", + "range": ">=3.2.0 <4.0.0" + }, + { + "version": "3.6.1", + "range": ">=3.5.0 <4.0.0" + }, + { + "version": "2.4.19", + "range": ">=2.3.0 <3.0.0" + }, + { + "version": "2.7.15", + "range": ">=2.6.0 <3.0.0" + }, + { + "version": "1.7.4", + "range": ">=1.6.0 <2.0.0" + }, + { + "version": "3.1.2", + "range": ">=3.0.0 <4.0.0" + }, + { + "version": "3.3.4", + "range": ">=3.2.0 <4.0.0" + }, + { + "version": "2.2.0", + "range": ">=2.1.0 <3.0.0" + }, + { + "version": "3.1.7", + "range": ">=3.0.0 <4.0.0" + }, + { + "version": "2.4.8", + "range": ">=2.3.0 <3.0.0" + }, + { + "version": "3.0.2", + "range": ">=3.0.0 <4.0.0" + }, + { + "version": "1.9.17", + "range": ">=1.8.0 <2.0.0" + }, + { + "version": "1.1.3", + "range": ">=1.0.0 <2.0.0" + }, + { + "version": "3.9.10", + "range": ">=3.8.0 <4.0.0" + }, + { + "version": "3.2.17", + "range": ">=3.1.0 <4.0.0" + }, + { + "version": "2.0.6", + "range": ">=2.0.0 <3.0.0" + }, + { + "version": "2.0.6", + "range": ">=2.0.0 <3.0.0" + }, + { + "version": "3.7.12", + "range": ">=3.6.0 <4.0.0" + }, + { + "version": "2.4.17", + "range": ">=2.3.0 <3.0.0" + }, + { + "version": "2.6.15", + "range": ">=2.5.0 <3.0.0" + }, + { + "version": "2.5.4", + "range": ">=2.4.0 <3.0.0" + }, + { + "version": "3.1.2", + "range": ">=3.0.0 <4.0.0" + }, + { + "version": "1.3.14", + "range": ">=1.2.0 <2.0.0" + }, + { + "version": "1.2.17", + "range": ">=1.1.0 <2.0.0" + }, + { + "version": "1.5.14", + "range": ">=1.4.0 <2.0.0" + }, + { + "version": "1.2.7", + "range": ">=1.1.0 <2.0.0" + }, + { + "version": "3.1.16", + "range": ">=3.0.0 <4.0.0" + }, + { + "version": "3.4.16", + "range": ">=3.3.0 <4.0.0" + }, + { + "version": "2.2.14", + "range": ">=2.1.0 <3.0.0" + }, + { + "version": "3.2.0", + "range": ">=3.1.0 <4.0.0" + }, + { + "version": "2.3.6", + "range": ">=2.2.0 <3.0.0" + }, + { + "version": "1.8.8", + "range": ">=1.7.0 <2.0.0" + }, + { + "version": "3.1.3", + "range": ">=3.0.0 <4.0.0" + }, + { + "version": "3.5.1", + "range": ">=3.4.0 <4.0.0" + }, + { + "version": "2.2.16", + "range": ">=2.1.0 <3.0.0" + }, + { + "version": "1.0.13", + "range": ">=1.0.0 <2.0.0" + }, + { + "version": "3.4.14", + "range": ">=3.3.0 <4.0.0" + }, + { + "version": "1.6.10", + "range": ">=1.5.0 <2.0.0" + }, + { + "version": "2.4.17", + "range": ">=2.3.0 <3.0.0" + }, + { + "version": "3.2.3", + "range": ">=3.1.0 <4.0.0" + }, + { + "version": "1.0.12", + "range": ">=1.0.0 <2.0.0" + }, + { + "version": "1.3.18", + "range": ">=1.2.0 <2.0.0" + }, + { + "version": "2.6.7", + "range": ">=2.5.0 <3.0.0" + }, + { + "version": "3.0.16", + "range": ">=3.0.0 <4.0.0" + }, + { + "version": "1.3.15", + "range": ">=1.2.0 <2.0.0" + }, + { + "version": "3.5.13", + "range": ">=3.4.0 <4.0.0" + }, + { + "version": "2.6.18", + "range": ">=2.5.0 <3.0.0" + }, + { + "version": "3.1.19", + "range": ">=3.0.0 <4.0.0" + }, + { + "version": "2.7.6", + "range": ">=2.6.0 <3.0.0" + }, + { + "version": "1.2.11", + "range": ">=1.1.0 <2.0.0" + }, + { + "version": "3.1.7", + "range": ">=3.0.0 <4.0.0" + }, + { + "version": "2.2.1", + "range": ">=2.1.0 <3.0.0" + }, + { + "version": "2.1.10", + "range": ">=2.0.0 <3.0.0" + }, + { + "version": "3.5.4", + "range": ">=3.4.0 <4.0.0" + }, + { + "version": "2.3.18", + "range": ">=2.2.0 <3.0.0" + }, + { + "version": "1.3.3", + "range": ">=1.2.0 <2.0.0" + }, + { + "version": "1.3.7", + "range": ">=1.2.0 <2.0.0" + }, + { + "version": "2.6.1", + "range": ">=2.5.0 <3.0.0" + }, + { + "version": "3.8.19", + "range": ">=3.7.0 <4.0.0" + }, + { + "version": "1.3.4", + "range": ">=1.2.0 <2.0.0" + }, + { + "version": "1.7.9", + "range": ">=1.6.0 <2.0.0" + }, + { + "version": "1.3.14", + "range": ">=1.2.0 <2.0.0" + }, + { + "version": "1.8.7", + "range": ">=1.7.0 <2.0.0" + }, + { + "version": "1.7.13", + "range": ">=1.6.0 <2.0.0" + }, + { + "version": "2.5.5", + "range": ">=2.4.0 <3.0.0" + }, + { + "version": "1.6.5", + "range": ">=1.5.0 <2.0.0" + }, + { + "version": "3.2.18", + "range": ">=3.1.0 <4.0.0" + }, + { + "version": "3.8.19", + "range": ">=3.7.0 <4.0.0" + }, + { + "version": "1.3.17", + "range": ">=1.2.0 <2.0.0" + }, + { + "version": "3.1.12", + "range": ">=3.0.0 <4.0.0" + }, + { + "version": "1.9.13", + "range": ">=1.8.0 <2.0.0" + }, + { + "version": "1.0.11", + "range": ">=1.0.0 <2.0.0" + }, + { + "version": "2.0.11", + "range": ">=2.0.0 <3.0.0" + }, + { + "version": "3.7.10", + "range": ">=3.6.0 <4.0.0" + }, + { + "version": "3.4.14", + "range": ">=3.3.0 <4.0.0" + }, + { + "version": "2.4.2", + "range": ">=2.3.0 <3.0.0" + }, + { + "version": "2.4.5", + "range": ">=2.3.0 <3.0.0" + }, + { + "version": "3.3.4", + "range": ">=3.2.0 <4.0.0" + }, + { + "version": "1.2.1", + "range": ">=1.1.0 <2.0.0" + }, + { + "version": "1.7.13", + "range": ">=1.6.0 <2.0.0" + }, + { + "version": "1.2.6", + "range": ">=1.1.0 <2.0.0" + }, + { + "version": "1.1.11", + "range": ">=1.0.0 <2.0.0" + } + ], + "numericWork": [ + 39309, 60365, 65130, 42142, 32870, 19040, 53421, 73865, 84996, 77736, 5585, + 43615, 19396, 75590, 53132, 68868, 44246, 1375, 11879, 45060, 66024, 22345, + 48441, 63408, 9616, 92799, 97113, 97702, 18434, 88550, 58302, 55808, 92846, + 41344, 37284, 83724, 89336, 86919, 79987, 56379, 68293, 53775, 83343, 92029, + 41088, 85696, 80202, 6242, 13100, 27307, 78277, 30924, 62257, 79002, 43045, + 81102, 74109, 26329, 49762, 47999, 92846, 7898, 74703, 58188, 99053, 74438, + 77158, 94565, 97089, 3160, 79508, 84479, 22151, 49703, 92816, 13619, 7078, + 75158, 51663, 37295, 36944, 56627, 36479, 25408, 62494, 73687, 71676, 49802, + 80373, 42036, 11314, 97490, 22764, 33342, 75380, 67775, 24169, 1159, 73385, + 45404, 10892, 1109, 60139, 20339, 2304, 51989, 68625, 39464, 6910, 11047, + 33819, 31473, 23110, 17189, 58967, 9687, 21284, 40872, 28039, 84079, 87651, + 86698, 73074, 98008, 26761, 29686, 16970, 30861, 85869, 39788, 10523, 45378, + 89050, 3712, 17703, 1947, 48827, 6975, 12574, 66119, 24832, 24082, 15427, + 54665, 14107, 48852, 52152, 25672, 89553, 29049, 27585, 71881, 11712, 36032, + 49294, 77952, 8880, 95433, 84607, 34689, 36712, 76276, 52491, 93196, 80984, + 88348, 46222, 99710, 87258, 22467, 63078, 17328, 63799, 45013, 21209, 78754, + 21924, 55402, 54574, 20733, 53934, 72667, 69174, 30221, 92183, 78796, 15769, + 26946, 77650, 13310, 97718, 63170, 93201, 32580, 22618, 33399, 78012, 69297, + 18456, 21644, 84949, 68497, 45990, 60813, 22737, 66620, 39826, 33767, 32347, + 57207, 63391, 90264, 19988, 55143, 6202, 74038, 54329, 64319, 86702, 98139, + 97628, 65731, 28850, 68795, 20438, 88167, 31627, 46741, 30131, 85602, 28717, + 74013, 31003, 32529, 73656, 87341, 71866, 23622, 97014, 5580, 31513, 55708, + 7357, 15114, 32040, 31710, 7200, 48347, 42327, 65096, 12526, 58349, 2143, + 76932, 83642, 34408 + ] +} diff --git a/apps/ecosystem-certifier/src/shared/hash.ts b/apps/ecosystem-certifier/src/shared/hash.ts new file mode 100644 index 0000000..60ac6e9 --- /dev/null +++ b/apps/ecosystem-certifier/src/shared/hash.ts @@ -0,0 +1,21 @@ +import { createHash } from 'node:crypto'; +import { encodeDv } from '@blue-quickjs/dv'; +import { serializeHostTape } from '@blue-quickjs/test-harness'; +import type { HostTapeRecord } from '@blue-quickjs/quickjs-runtime'; + +export function sha256Hex(input: Uint8Array | string): string { + const bytes = + typeof input === 'string' ? new TextEncoder().encode(input) : input; + return createHash('sha256').update(bytes).digest('hex'); +} + +export function hashDv(value: unknown): string { + return sha256Hex(encodeDv(value)); +} + +export function hashTape(tape: HostTapeRecord[]): string | null { + if (tape.length === 0) { + return null; + } + return sha256Hex(serializeHostTape(tape)); +} diff --git a/apps/ecosystem-certifier/src/shared/host.ts b/apps/ecosystem-certifier/src/shared/host.ts new file mode 100644 index 0000000..06cc9f6 --- /dev/null +++ b/apps/ecosystem-certifier/src/shared/host.ts @@ -0,0 +1,170 @@ +import type { + HostDispatcherHandlers, + HostCallResult, +} from '@blue-quickjs/quickjs-runtime'; + +const TEXT_DOCUMENTS = new Map([ + [ + 'pack/metadata.json', + JSON.stringify( + { + packId: 'kp-2026-rc', + release: '1.2.3', + requires: ['>=1.2.0 <2.0.0', '^1.2.0'], + links: ['docs/a.md', 'docs/b.md', 'docs/c.md', 'docs/d.md'], + }, + null, + 2, + ), + ], + [ + 'pack/metadata.yaml', + [ + 'packId: kp-2026-rc', + 'release: 1.2.3', + 'requires:', + ' - ">=1.2.0 <2.0.0"', + ' - "^1.2.0"', + 'links:', + ' - docs/a.md', + ' - docs/b.md', + '', + ].join('\n'), + ], + [ + 'docs/a.md', + [ + '# Alpha', + '', + 'See [Beta](docs/b.md), [Gamma](docs/c.md), and https://example.com/path.', + '', + 'Encoded value: & deterministic.', + '', + 'Paragraph: Deterministic workloads should remain stable across', + 'wasm-node and wasm-browser executors.', + '', + ].join('\n'), + ], + [ + 'docs/b.md', + [ + '# Beta', + '', + 'Backlink to [Alpha](docs/a.md) and [Delta](docs/d.md).', + '', + 'Extra URL: https://example.net/release-notes.', + '', + ].join('\n'), + ], + [ + 'docs/c.md', + [ + '# Gamma', + '', + 'Cross-link to [Delta](docs/d.md).', + '', + 'Reference URL: https://example.org/matrix.', + '', + ].join('\n'), + ], + [ + 'docs/d.md', + [ + '# Delta', + '', + 'Back to [Alpha](docs/a.md) and [Beta](docs/b.md).', + '', + 'Reference URL: https://example.dev/consensus.', + '', + ].join('\n'), + ], + [ + 'rules/findings.json', + JSON.stringify( + { + and: [ + { '>=': [{ var: 'linkCount' }, 8] }, + { '==': [{ var: 'releaseOk' }, true] }, + ], + }, + null, + 2, + ), + ], + ['text/semver-case', '1.2.3'], + ['text/path-case', '/document/:id/version/:version'], + ['text/yaml-case', 'name: Blue\nvalue: 42\n'], + ['text/markdown-case', '# Heading\n\nA [link](https://example.com).\n'], + ['text/he-case', '<b>safe</b>'], + ['text/diff-left', 'alpha\nbeta\ngamma\n'], + ['text/diff-right', 'alpha\nbeta2\ngamma\n'], + ['text/json-logic-case', JSON.stringify({ score: 7, threshold: 5 })], +]); + +const BINARY_DOCUMENTS = new Map([ + [ + 'bytes/payload', + Uint8Array.from( + Array.from({ length: 64 }, (_, index) => (index * 17) % 251), + ), + ], + [ + 'bytes/flagship-extra', + Uint8Array.from( + Array.from({ length: 192 }, (_, index) => (index * 29 + 11) % 251), + ), + ], + [ + 'pack/attachment.deflated', + Uint8Array.from([ + 120, 156, 179, 73, 77, 206, 79, 73, 45, 86, 112, 46, 41, 202, 204, 75, 87, + 72, 206, 207, 43, 73, 45, 2, 0, 101, 57, 8, 181, + ]), + ], +]); + +export function createCertificationHost(): { + handlers: HostDispatcherHandlers; + emitted: unknown[]; +} { + const emitted: unknown[] = []; + + const handlers: HostDispatcherHandlers = { + document: { + get: (docPath: string): HostCallResult => { + const binaryDocument = BINARY_DOCUMENTS.get(docPath); + if (binaryDocument !== undefined) { + return { ok: binaryDocument, units: 6 }; + } + const textDocument = TEXT_DOCUMENTS.get(docPath); + if (textDocument !== undefined) { + return { ok: textDocument, units: 2 }; + } + return { + err: { code: 'NOT_FOUND', tag: 'host/not_found' }, + units: 1, + }; + }, + getCanonical: (docPath: string): HostCallResult => { + const textDocument = TEXT_DOCUMENTS.get(docPath); + if (textDocument !== undefined) { + return { ok: textDocument, units: 2 }; + } + const binaryDocument = BINARY_DOCUMENTS.get(docPath); + if (binaryDocument !== undefined) { + return { ok: binaryDocument, units: 6 }; + } + return { + err: { code: 'NOT_FOUND', tag: 'host/not_found' }, + units: 1, + }; + }, + }, + emit: (value: unknown) => { + emitted.push(value); + return { ok: null, units: 1 }; + }, + }; + + return { handlers, emitted }; +} diff --git a/apps/ecosystem-certifier/src/shared/oog-boundary.spec.ts b/apps/ecosystem-certifier/src/shared/oog-boundary.spec.ts new file mode 100644 index 0000000..9adbe5a --- /dev/null +++ b/apps/ecosystem-certifier/src/shared/oog-boundary.spec.ts @@ -0,0 +1,22 @@ +import { compareBoundaries, searchOogBoundary } from './oog-boundary.js'; + +describe('OOG boundary search', () => { + it('finds exact boundary with binary search', async () => { + const boundary = await searchOogBoundary({ + low: 1n, + high: 200n, + runSuccess: async (gasLimit) => gasLimit >= 77n, + }); + expect(boundary.lastFailureGas).toBe(76n); + expect(boundary.firstSuccessGas).toBe(77n); + }); + + it('compares boundaries', () => { + const parity = compareBoundaries( + { lastFailureGas: 76n, firstSuccessGas: 77n }, + { lastFailureGas: 76n, firstSuccessGas: 77n }, + ); + expect(parity.firstSuccessEqual).toBe(true); + expect(parity.lastFailureEqual).toBe(true); + }); +}); diff --git a/apps/ecosystem-certifier/src/shared/oog-boundary.ts b/apps/ecosystem-certifier/src/shared/oog-boundary.ts new file mode 100644 index 0000000..affd64d --- /dev/null +++ b/apps/ecosystem-certifier/src/shared/oog-boundary.ts @@ -0,0 +1,44 @@ +export interface OogBoundary { + lastFailureGas: bigint; + firstSuccessGas: bigint; +} + +export async function searchOogBoundary(options: { + low: bigint; + high: bigint; + runSuccess: (gasLimit: bigint) => Promise; +}): Promise { + let left = options.low; + let right = options.high; + const highSuccess = await options.runSuccess(right); + if (!highSuccess) { + throw new Error( + `upper gas bound ${right.toString()} did not succeed during OOG boundary search`, + ); + } + + while (left + 1n < right) { + const mid = (left + right) / 2n; + const success = await options.runSuccess(mid); + if (success) { + right = mid; + } else { + left = mid; + } + } + + return { + lastFailureGas: left, + firstSuccessGas: right, + }; +} + +export function compareBoundaries( + node: OogBoundary, + browser: OogBoundary, +): { firstSuccessEqual: boolean; lastFailureEqual: boolean } { + return { + firstSuccessEqual: node.firstSuccessGas === browser.firstSuccessGas, + lastFailureEqual: node.lastFailureGas === browser.lastFailureGas, + }; +} diff --git a/apps/ecosystem-certifier/src/shared/parity.spec.ts b/apps/ecosystem-certifier/src/shared/parity.spec.ts new file mode 100644 index 0000000..c2847d5 --- /dev/null +++ b/apps/ecosystem-certifier/src/shared/parity.spec.ts @@ -0,0 +1,30 @@ +import type { FixtureSnapshot } from './types.js'; +import { compareSnapshots, isStrictParity } from './parity.js'; + +describe('parity helpers', () => { + const snapshot: FixtureSnapshot = { + stage: 'success', + resultHash: 'abc', + errorCode: null, + errorTag: null, + gasUsed: '10', + gasRemaining: '90', + tapeHash: 'def', + tapeLength: 1, + }; + + it('returns strict parity for equal snapshots', () => { + const parity = compareSnapshots(snapshot, { ...snapshot }); + expect(isStrictParity(parity)).toBe(true); + }); + + it('returns parity mismatch for different gas', () => { + const parity = compareSnapshots(snapshot, { + ...snapshot, + gasUsed: '11', + gasRemaining: '89', + }); + expect(isStrictParity(parity)).toBe(false); + expect(parity.gasUsedEqual).toBe(false); + }); +}); diff --git a/apps/ecosystem-certifier/src/shared/parity.ts b/apps/ecosystem-certifier/src/shared/parity.ts new file mode 100644 index 0000000..9ecab02 --- /dev/null +++ b/apps/ecosystem-certifier/src/shared/parity.ts @@ -0,0 +1,54 @@ +import type { FixtureSnapshot } from './types.js'; + +export interface SnapshotParity { + stageEqual: boolean; + resultHashEqual: boolean; + errorCodeEqual: boolean; + errorTagEqual: boolean; + gasUsedEqual: boolean; + gasRemainingEqual: boolean; + tapeHashEqual: boolean; + tapeLengthEqual: boolean; +} + +export function compareSnapshots( + node: FixtureSnapshot, + browser: FixtureSnapshot | null, +): SnapshotParity { + if (!browser) { + return { + stageEqual: false, + resultHashEqual: false, + errorCodeEqual: false, + errorTagEqual: false, + gasUsedEqual: false, + gasRemainingEqual: false, + tapeHashEqual: false, + tapeLengthEqual: false, + }; + } + + return { + stageEqual: node.stage === browser.stage, + resultHashEqual: node.resultHash === browser.resultHash, + errorCodeEqual: node.errorCode === browser.errorCode, + errorTagEqual: node.errorTag === browser.errorTag, + gasUsedEqual: node.gasUsed === browser.gasUsed, + gasRemainingEqual: node.gasRemaining === browser.gasRemaining, + tapeHashEqual: node.tapeHash === browser.tapeHash, + tapeLengthEqual: node.tapeLength === browser.tapeLength, + }; +} + +export function isStrictParity(parity: SnapshotParity): boolean { + return ( + parity.stageEqual && + parity.resultHashEqual && + parity.errorCodeEqual && + parity.errorTagEqual && + parity.gasUsedEqual && + parity.gasRemainingEqual && + parity.tapeHashEqual && + parity.tapeLengthEqual + ); +} diff --git a/apps/ecosystem-certifier/src/shared/repeatability.spec.ts b/apps/ecosystem-certifier/src/shared/repeatability.spec.ts new file mode 100644 index 0000000..d5683a7 --- /dev/null +++ b/apps/ecosystem-certifier/src/shared/repeatability.spec.ts @@ -0,0 +1,23 @@ +import type { FixtureSnapshot } from './types.js'; +import { runRepeatability } from './repeatability.js'; + +describe('repeatability helper', () => { + it('reports zero drift for stable snapshots', async () => { + const snapshot: FixtureSnapshot = { + stage: 'success', + resultHash: 'stable', + errorCode: null, + errorTag: null, + gasUsed: '10', + gasRemaining: '90', + tapeHash: null, + tapeLength: 0, + }; + const result = await runRepeatability({ + iterations: 5, + runSnapshot: async () => ({ ...snapshot }), + }); + expect(result.driftCount).toBe(0); + expect(result.totalRuns).toBe(5); + }); +}); diff --git a/apps/ecosystem-certifier/src/shared/repeatability.ts b/apps/ecosystem-certifier/src/shared/repeatability.ts new file mode 100644 index 0000000..9d9de8e --- /dev/null +++ b/apps/ecosystem-certifier/src/shared/repeatability.ts @@ -0,0 +1,33 @@ +import type { FixtureSnapshot } from './types.js'; + +export interface RepeatabilityResult { + baseline: FixtureSnapshot; + driftCount: number; + totalRuns: number; +} + +export async function runRepeatability(options: { + iterations: number; + runSnapshot: () => Promise; +}): Promise { + if (options.iterations < 1) { + throw new Error('repeatability iterations must be >= 1'); + } + + const baseline = await options.runSnapshot(); + let driftCount = 0; + const baselineJson = JSON.stringify(baseline); + + for (let index = 1; index < options.iterations; index += 1) { + const snapshot = await options.runSnapshot(); + if (JSON.stringify(snapshot) !== baselineJson) { + driftCount += 1; + } + } + + return { + baseline, + driftCount, + totalRuns: options.iterations, + }; +} diff --git a/apps/ecosystem-certifier/src/shared/types.ts b/apps/ecosystem-certifier/src/shared/types.ts new file mode 100644 index 0000000..b5f16e1 --- /dev/null +++ b/apps/ecosystem-certifier/src/shared/types.ts @@ -0,0 +1,72 @@ +import type { AbiManifest } from '@blue-quickjs/abi-manifest'; +import type { ProgramArtifactV2 } from '@blue-quickjs/quickjs-runtime'; + +export type FixtureKind = 'flagship' | 'positive' | 'negative'; + +export type FailureStage = + | 'builder_reject' + | 'artifact_validation' + | 'runtime_error' + | 'pin_enforcement'; + +export interface BuildFixtureDefinition { + id: string; + title: string; + kind: FixtureKind; + entryPath: string; + profile: 'baseline-v1' | 'compat-general-v1' | 'compat-binary-v1'; + abiId: 'Host.v1' | 'Host.v2'; + abiVersion: 1 | 2; + abiManifestHash: string; + gasLimit: bigint; + expect: + | { + stage: 'success'; + } + | { + stage: FailureStage; + errorCode?: string; + errorTag?: string; + }; +} + +export interface BrowserEvaluationCase { + id: string; + title: string; + kind: FixtureKind; + gasLimit: string; + manifest: AbiManifest; + program: ProgramArtifactV2; +} + +export interface FixtureSnapshot { + stage: 'success' | FailureStage; + resultHash: string | null; + errorCode: string | null; + errorTag: string | null; + gasUsed: string; + gasRemaining: string; + tapeHash: string | null; + tapeLength: number; +} + +export interface FixtureParityRecord { + id: string; + title: string; + kind: FixtureKind; + node: FixtureSnapshot; + browser: FixtureSnapshot | null; + match: boolean; +} + +export interface CertificationReport { + generatedAt: string; + summary: { + total: number; + withBrowserRuns: number; + mismatches: number; + greenCount: number; + redCount: number; + }; + records: FixtureParityRecord[]; +} diff --git a/apps/ecosystem-certifier/src/typings.d.ts b/apps/ecosystem-certifier/src/typings.d.ts new file mode 100644 index 0000000..2a7c652 --- /dev/null +++ b/apps/ecosystem-certifier/src/typings.d.ts @@ -0,0 +1,18 @@ +import type { + BrowserEvaluationCase, + FixtureParityRecord, +} from './shared/types.js'; + +declare global { + interface Window { + __ECOSYSTEM_CERT_CASES__?: BrowserEvaluationCase[]; + __ECOSYSTEM_CERT_RESULTS__?: FixtureParityRecord[]; + __ECOSYSTEM_CERT_RUNSTATE__?: 'idle' | 'running' | 'done' | 'error'; + __ECOSYSTEM_CERT_RUN_CASE__?: ( + certCase: BrowserEvaluationCase, + gasLimit?: string, + ) => Promise; + } +} + +export {}; diff --git a/apps/ecosystem-certifier/tests/builder-determinism.spec.ts b/apps/ecosystem-certifier/tests/builder-determinism.spec.ts new file mode 100644 index 0000000..bcfca52 --- /dev/null +++ b/apps/ecosystem-certifier/tests/builder-determinism.spec.ts @@ -0,0 +1,31 @@ +import { execFile } from 'node:child_process'; +import { readFile } from 'node:fs/promises'; +import path from 'node:path'; +import { promisify } from 'node:util'; +import { expect, test } from '@playwright/test'; +import type { BuilderDeterminismReport } from '../src/shared/builder-determinism.js'; + +const execFileAsync = promisify(execFile); + +test('builder path determinism script reports stable hashes', async () => { + const outDir = path.join( + process.cwd(), + 'artifacts', + 'workload-certification-test', + `builder-${Date.now()}`, + ); + await execFileAsync('node', [ + 'apps/ecosystem-certifier/scripts/check-builder-determinism.mjs', + '--out-dir', + outDir, + ]); + + const reportPath = path.join(outDir, 'builder-determinism-report.json'); + const report = JSON.parse( + await readFile(reportPath, 'utf8'), + ) as BuilderDeterminismReport; + + expect(report.checks.graphHashEqual).toBe(true); + expect(report.checks.canonicalHashEqual).toBe(true); + expect(report.fixtures).toHaveLength(2); +}); diff --git a/apps/ecosystem-certifier/tests/certifier.spec.ts b/apps/ecosystem-certifier/tests/certifier.spec.ts new file mode 100644 index 0000000..7975817 --- /dev/null +++ b/apps/ecosystem-certifier/tests/certifier.spec.ts @@ -0,0 +1,50 @@ +import { HOST_V1_HASH, HOST_V1_MANIFEST } from '@blue-quickjs/abi-manifest'; +import { expect, test } from '@playwright/test'; +import type { + BrowserEvaluationCase, + FixtureParityRecord, +} from '../src/shared/types.js'; + +test('browser certifier executes injected evaluation cases', async ({ + page, +}) => { + const cases: BrowserEvaluationCase[] = [ + { + id: 'sample-script-case', + title: 'sample script', + kind: 'positive', + gasLimit: '100000', + manifest: HOST_V1_MANIFEST, + program: { + version: 2, + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + executionProfile: 'baseline-v1', + sourceKind: 'script', + source: { + code: '42', + }, + }, + }, + ]; + + await page.addInitScript((payload) => { + window.__ECOSYSTEM_CERT_CASES__ = payload; + }, cases); + + await page.goto('/'); + await page.waitForSelector('[data-runstate="done"]', { timeout: 60000 }); + + const results = await page.evaluate( + () => window.__ECOSYSTEM_CERT_RESULTS__ ?? [], + ); + expect(results).toHaveLength(1); + const [firstResult] = results; + if (!firstResult) { + throw new Error('expected one browser certifier result'); + } + expect(firstResult.id).toBe('sample-script-case'); + expect(firstResult.browser?.stage).toBe('success'); + expect(firstResult.browser?.errorCode).toBeNull(); +}); diff --git a/apps/ecosystem-certifier/tests/fixture-helpers.ts b/apps/ecosystem-certifier/tests/fixture-helpers.ts new file mode 100644 index 0000000..2fcc9c9 --- /dev/null +++ b/apps/ecosystem-certifier/tests/fixture-helpers.ts @@ -0,0 +1,147 @@ +import type { Page } from '@playwright/test'; +import { + type BuildDeterministicModulePackResult, + buildDeterministicModulePack, +} from '@blue-quickjs/deterministic-builder'; +import { evaluate } from '@blue-quickjs/quickjs-runtime'; +import { + type BrowserEvaluationCase, + type BuildFixtureDefinition, + type FailureStage, + type FixtureSnapshot, +} from '../src/shared/types.js'; +import { + CERTIFIER_FIXTURES, + manifestForFixture, +} from '../src/shared/fixtures.js'; +import { createCertificationHost } from '../src/shared/host.js'; +import { hashDv, hashTape } from '../src/shared/hash.js'; + +const INPUT = { + event: { type: 'ecosystem-certifier' }, + eventCanonical: { type: 'ecosystem-certifier' }, + steps: [], + currentContract: { id: 'ecosystem-certifier' }, + currentContractCanonical: { id: { value: 'ecosystem-certifier' } }, +}; + +export function getFixtureById(id: string): BuildFixtureDefinition { + const fixture = CERTIFIER_FIXTURES.find((item) => item.id === id); + if (!fixture) { + throw new Error(`fixture not found: ${id}`); + } + return fixture; +} + +export async function buildCaseByFixtureId( + id: string, +): Promise { + const fixture = getFixtureById(id); + const built = await buildDeterministicModulePack({ + absWorkingDir: process.cwd(), + entryPath: fixture.entryPath, + profile: fixture.profile, + emitProgramArtifact: true, + abiId: fixture.abiId, + abiVersion: fixture.abiVersion, + abiManifestHash: fixture.abiManifestHash, + }); + return toBrowserCase(fixture, built); +} + +export async function runNodeSnapshot( + certCase: BrowserEvaluationCase, + gasLimit?: string, +): Promise { + const host = createCertificationHost(); + const result = await evaluate({ + program: certCase.program, + input: INPUT, + gasLimit: BigInt(gasLimit ?? certCase.gasLimit), + manifest: certCase.manifest, + handlers: host.handlers, + tape: { capacity: 64 }, + }); + const tape = result.tape ?? []; + if (result.ok) { + return { + stage: 'success', + resultHash: hashDv(result.value), + errorCode: null, + errorTag: null, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + tapeHash: hashTape(tape), + tapeLength: tape.length, + }; + } + return { + stage: normalizeFailureStage(result.error.kind), + resultHash: null, + errorCode: result.error.code, + errorTag: 'tag' in result.error ? result.error.tag : null, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + tapeHash: hashTape(tape), + tapeLength: tape.length, + }; +} + +export async function runBrowserSnapshot( + page: Page, + certCase: BrowserEvaluationCase, + gasLimit?: string, +): Promise { + await ensureRunnerReady(page); + return page.evaluate( + async ({ certCasePayload, gasLimitValue }) => { + if (!window.__ECOSYSTEM_CERT_RUN_CASE__) { + throw new Error('window.__ECOSYSTEM_CERT_RUN_CASE__ is unavailable'); + } + return window.__ECOSYSTEM_CERT_RUN_CASE__( + certCasePayload, + gasLimitValue ?? certCasePayload.gasLimit, + ); + }, + { + certCasePayload: certCase, + gasLimitValue: gasLimit, + }, + ); +} + +async function ensureRunnerReady(page: Page): Promise { + await page.goto('/'); + await page.waitForFunction( + () => typeof window.__ECOSYSTEM_CERT_RUN_CASE__ === 'function', + undefined, + { timeout: 120000 }, + ); +} + +function toBrowserCase( + fixture: BuildFixtureDefinition, + built: BuildDeterministicModulePackResult, +): BrowserEvaluationCase { + if (!built.programArtifact) { + throw new Error(`missing ProgramArtifact.v2 for ${fixture.id}`); + } + return { + id: fixture.id, + title: fixture.title, + kind: fixture.kind, + gasLimit: fixture.gasLimit.toString(), + manifest: manifestForFixture(fixture), + program: built.programArtifact, + }; +} + +function normalizeFailureStage(kind: string): FailureStage { + if (kind === 'module-pack') { + return 'artifact_validation'; + } + if (kind === 'execution-surface-mismatch') { + return 'pin_enforcement'; + } + return 'runtime_error'; +} diff --git a/apps/ecosystem-certifier/tests/negative-determinism.spec.ts b/apps/ecosystem-certifier/tests/negative-determinism.spec.ts new file mode 100644 index 0000000..16d70f5 --- /dev/null +++ b/apps/ecosystem-certifier/tests/negative-determinism.spec.ts @@ -0,0 +1,49 @@ +import { expect, test } from '@playwright/test'; +import { + DeterministicBuilderError, + buildDeterministicModulePack, +} from '@blue-quickjs/deterministic-builder'; +import { HOST_V1_HASH } from '@blue-quickjs/abi-manifest'; +import { + buildCaseByFixtureId, + getFixtureById, + runBrowserSnapshot, + runNodeSnapshot, +} from './fixture-helpers.js'; + +test('function-constructor fixture fails deterministically in both environments', async ({ + page, +}) => { + const certCase = await buildCaseByFixtureId('red-function-constructor'); + const nodeSnapshot = await runNodeSnapshot(certCase); + const browserSnapshot = await runBrowserSnapshot(page, certCase); + + expect(nodeSnapshot.stage).toBe('artifact_validation'); + expect(nodeSnapshot.errorCode).toBe('MODULE_EXPORT_MISSING'); + expect(nodeSnapshot.errorTag).toBe('vm/module_pack'); + expect(browserSnapshot).toEqual(nodeSnapshot); +}); + +test('proxy fixture is rejected at build stage with deterministic rule', async () => { + const fixture = getFixtureById('red-proxy'); + let thrown: unknown = null; + try { + await buildDeterministicModulePack({ + absWorkingDir: process.cwd(), + entryPath: fixture.entryPath, + profile: fixture.profile, + emitProgramArtifact: true, + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + }); + } catch (error) { + thrown = error; + } + expect(thrown).toBeInstanceOf(DeterministicBuilderError); + if (thrown instanceof DeterministicBuilderError) { + expect( + thrown.diagnostics.some((entry) => entry.ruleId === 'proxy_disabled'), + ).toBe(true); + } +}); diff --git a/apps/ecosystem-certifier/tests/oog-boundary.spec.ts b/apps/ecosystem-certifier/tests/oog-boundary.spec.ts new file mode 100644 index 0000000..c2a28be --- /dev/null +++ b/apps/ecosystem-certifier/tests/oog-boundary.spec.ts @@ -0,0 +1,42 @@ +import { expect, test } from '@playwright/test'; +import { + compareBoundaries, + searchOogBoundary, +} from '../src/shared/oog-boundary.js'; +import { + buildCaseByFixtureId, + runBrowserSnapshot, + runNodeSnapshot, +} from './fixture-helpers.js'; + +test('node and browser share exact OOG boundary for semver fixture', async ({ + page, +}) => { + const certCase = await buildCaseByFixtureId('green-semver'); + const maxGas = BigInt(certCase.gasLimit); + + const nodeBoundary = await searchOogBoundary({ + low: 1n, + high: maxGas, + runSuccess: async (gasLimit) => { + const snapshot = await runNodeSnapshot(certCase, gasLimit.toString()); + return snapshot.stage === 'success'; + }, + }); + const browserBoundary = await searchOogBoundary({ + low: 1n, + high: maxGas, + runSuccess: async (gasLimit) => { + const snapshot = await runBrowserSnapshot( + page, + certCase, + gasLimit.toString(), + ); + return snapshot.stage === 'success'; + }, + }); + + const parity = compareBoundaries(nodeBoundary, browserBoundary); + expect(parity.firstSuccessEqual).toBe(true); + expect(parity.lastFailureEqual).toBe(true); +}); diff --git a/apps/ecosystem-certifier/tests/parity.spec.ts b/apps/ecosystem-certifier/tests/parity.spec.ts new file mode 100644 index 0000000..933f224 --- /dev/null +++ b/apps/ecosystem-certifier/tests/parity.spec.ts @@ -0,0 +1,19 @@ +import { expect, test } from '@playwright/test'; +import { compareSnapshots, isStrictParity } from '../src/shared/parity.js'; +import { + buildCaseByFixtureId, + runBrowserSnapshot, + runNodeSnapshot, +} from './fixture-helpers.js'; + +test('flagship fixture preserves strict node/browser parity snapshot', async ({ + page, +}) => { + const certCase = await buildCaseByFixtureId('flagship-knowledge-pack'); + const nodeSnapshot = await runNodeSnapshot(certCase); + const browserSnapshot = await runBrowserSnapshot(page, certCase); + const parity = compareSnapshots(nodeSnapshot, browserSnapshot); + + expect(isStrictParity(parity)).toBe(true); + expect(browserSnapshot).toEqual(nodeSnapshot); +}); diff --git a/apps/ecosystem-certifier/tests/repeatability.spec.ts b/apps/ecosystem-certifier/tests/repeatability.spec.ts new file mode 100644 index 0000000..23b6648 --- /dev/null +++ b/apps/ecosystem-certifier/tests/repeatability.spec.ts @@ -0,0 +1,26 @@ +import { expect, test } from '@playwright/test'; +import { runRepeatability } from '../src/shared/repeatability.js'; +import { + buildCaseByFixtureId, + runBrowserSnapshot, + runNodeSnapshot, +} from './fixture-helpers.js'; + +test('stress corpus snapshot is stable across repeated node/browser runs', async ({ + page, +}) => { + const certCase = await buildCaseByFixtureId('green-stress-corpus'); + + const nodeRepeatability = await runRepeatability({ + iterations: 8, + runSnapshot: async () => runNodeSnapshot(certCase), + }); + const browserRepeatability = await runRepeatability({ + iterations: 8, + runSnapshot: async () => runBrowserSnapshot(page, certCase), + }); + + expect(nodeRepeatability.driftCount).toBe(0); + expect(browserRepeatability.driftCount).toBe(0); + expect(browserRepeatability.baseline).toEqual(nodeRepeatability.baseline); +}); diff --git a/apps/ecosystem-certifier/tsconfig.app.json b/apps/ecosystem-certifier/tsconfig.app.json new file mode 100644 index 0000000..070efab --- /dev/null +++ b/apps/ecosystem-certifier/tsconfig.app.json @@ -0,0 +1,36 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "dist/out-tsc", + "lib": ["es2022", "dom", "dom.iterable"], + "types": ["node", "vite/client"], + "module": "esnext", + "moduleResolution": "bundler", + "tsBuildInfoFile": "dist/tsconfig.app.tsbuildinfo" + }, + "include": ["src/**/*.ts", "src/**/*.d.ts"], + "exclude": ["src/**/*.spec.ts", "tests/**/*.ts"], + "references": [ + { + "path": "../../libs/deterministic-bundler/tsconfig.lib.json" + }, + { + "path": "../../libs/test-harness/tsconfig.lib.json" + }, + { + "path": "../../libs/quickjs-wasm/tsconfig.lib.json" + }, + { + "path": "../../libs/quickjs-runtime/tsconfig.lib.json" + }, + { + "path": "../../libs/dv/tsconfig.lib.json" + }, + { + "path": "../../libs/deterministic-builder/tsconfig.lib.json" + }, + { + "path": "../../libs/abi-manifest/tsconfig.lib.json" + } + ] +} diff --git a/apps/ecosystem-certifier/tsconfig.json b/apps/ecosystem-certifier/tsconfig.json new file mode 100644 index 0000000..bce248a --- /dev/null +++ b/apps/ecosystem-certifier/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "types": ["node"] + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/apps/ecosystem-certifier/tsconfig.spec.json b/apps/ecosystem-certifier/tsconfig.spec.json new file mode 100644 index 0000000..cf3ebc4 --- /dev/null +++ b/apps/ecosystem-certifier/tsconfig.spec.json @@ -0,0 +1,45 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "dist/out-tsc-spec", + "lib": ["es2022", "dom", "dom.iterable"], + "types": [ + "vitest/globals", + "vitest/importMeta", + "vite/client", + "node", + "vitest" + ], + "module": "esnext", + "moduleResolution": "bundler" + }, + "include": [ + "src/**/*.d.ts", + "src/**/*.spec.ts", + "src/shared/**/*.ts", + "tests/**/*.ts" + ], + "references": [ + { + "path": "./tsconfig.app.json" + }, + { + "path": "../../libs/test-harness/tsconfig.lib.json" + }, + { + "path": "../../libs/quickjs-wasm/tsconfig.lib.json" + }, + { + "path": "../../libs/quickjs-runtime/tsconfig.lib.json" + }, + { + "path": "../../libs/dv/tsconfig.lib.json" + }, + { + "path": "../../libs/deterministic-builder/tsconfig.lib.json" + }, + { + "path": "../../libs/abi-manifest/tsconfig.lib.json" + } + ] +} diff --git a/apps/ecosystem-certifier/vite.config.mts b/apps/ecosystem-certifier/vite.config.mts new file mode 100644 index 0000000..fef6928 --- /dev/null +++ b/apps/ecosystem-certifier/vite.config.mts @@ -0,0 +1,57 @@ +/// +import path from 'node:path'; +import { defineConfig } from 'vite'; + +export default defineConfig(() => ({ + root: import.meta.dirname, + cacheDir: '../../node_modules/.vite/apps/ecosystem-certifier', + server: { + port: 4310, + host: 'localhost', + fs: { + allow: [path.resolve(import.meta.dirname, '..', '..', '..')], + }, + }, + preview: { + port: 4310, + host: 'localhost', + }, + build: { + outDir: './dist', + emptyOutDir: true, + reportCompressedSize: true, + commonjsOptions: { + transformMixedEsModules: true, + }, + }, + test: { + name: 'ecosystem-certifier', + watch: false, + globals: true, + environment: 'node', + include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], + exclude: ['tests/**'], + reporters: ['default'], + coverage: { + reportsDirectory: './test-output/vitest/coverage', + provider: 'v8' as const, + all: true, + include: ['src/shared/**/*.{ts,mts}'], + exclude: [ + 'src/shared/**/*.d.ts', + 'src/shared/**/*.{test,spec}.{ts,mts}', + 'src/shared/fixtures/**', + 'src/shared/fixtures.ts', + 'src/shared/hash.ts', + 'src/shared/host.ts', + 'src/shared/types.ts', + ], + thresholds: { + lines: 40, + functions: 40, + branches: 40, + statements: 40, + }, + }, + }, +})); diff --git a/apps/smoke-node/package.json b/apps/smoke-node/package.json index 8d44dd9..357b33e 100644 --- a/apps/smoke-node/package.json +++ b/apps/smoke-node/package.json @@ -36,5 +36,8 @@ "@blue-quickjs/quickjs-runtime": "workspace:*", "@blue-quickjs/test-harness": "workspace:*", "tslib": "^2.3.0" + }, + "devDependencies": { + "@blue-quickjs/deterministic-bundler": "workspace:*" } } diff --git a/apps/smoke-node/src/lib/binary-library-reuse.spec.ts b/apps/smoke-node/src/lib/binary-library-reuse.spec.ts new file mode 100644 index 0000000..a42b6b3 --- /dev/null +++ b/apps/smoke-node/src/lib/binary-library-reuse.spec.ts @@ -0,0 +1,46 @@ +import { bundleDeterministicProgram } from '@blue-quickjs/deterministic-bundler'; +import path from 'node:path'; +import { + BINARY_LIBRARY_FIXTURES, + BINARY_LIBRARY_GAS_LIMIT, + BINARY_LIBRARY_INPUT, + BINARY_LIBRARY_MANIFEST, + BINARY_LIBRARY_PROGRAM_BASE, + createDeterminismHost, +} from '@blue-quickjs/test-harness'; +import { evaluate } from '@blue-quickjs/quickjs-runtime'; + +describe('smoke-node binary library reuse', () => { + it('bundles binary-heavy npm packages and matches expected results', async () => { + const workspaceRoot = path.resolve(process.cwd(), '../..'); + + for (const fixture of BINARY_LIBRARY_FIXTURES) { + const bundled = await bundleDeterministicProgram({ + absWorkingDir: workspaceRoot, + entryPath: fixture.entryPath, + profile: 'compat-binary-v1', + }); + + const host = createDeterminismHost(); + const result = await evaluate({ + program: { + ...BINARY_LIBRARY_PROGRAM_BASE, + code: bundled.code, + }, + input: BINARY_LIBRARY_INPUT, + gasLimit: BINARY_LIBRARY_GAS_LIMIT, + manifest: BINARY_LIBRARY_MANIFEST, + handlers: host.handlers, + }); + + expect(result.ok).toBe(true); + if (!result.ok) { + throw new Error( + `${fixture.name} failed: ${result.error.code}: ${result.message}`, + ); + } + + expect(result.value).toEqual(fixture.expectedValue); + } + }); +}); diff --git a/apps/smoke-node/src/lib/chess-library-reuse.spec.ts b/apps/smoke-node/src/lib/chess-library-reuse.spec.ts new file mode 100644 index 0000000..1a621f4 --- /dev/null +++ b/apps/smoke-node/src/lib/chess-library-reuse.spec.ts @@ -0,0 +1,41 @@ +import { bundleDeterministicProgram } from '@blue-quickjs/deterministic-bundler'; +import path from 'node:path'; +import { + CHESS_E2E6_EXPECTED_LEGAL, + CHESS_LIBRARY_ENTRY_PATH, + CHESS_LIBRARY_GAS_LIMIT, + CHESS_LIBRARY_INPUT, + CHESS_LIBRARY_MANIFEST, + CHESS_LIBRARY_PROGRAM_BASE, + createDeterminismHost, +} from '@blue-quickjs/test-harness'; +import { evaluate } from '@blue-quickjs/quickjs-runtime'; + +describe('smoke-node chess.js reuse', () => { + it('bundles chess.js and checks e2e6 legality', async () => { + const workspaceRoot = path.resolve(process.cwd(), '../..'); + const bundled = await bundleDeterministicProgram({ + absWorkingDir: workspaceRoot, + entryPath: CHESS_LIBRARY_ENTRY_PATH, + profile: 'compat-general-v1', + }); + + const host = createDeterminismHost(); + const result = await evaluate({ + program: { + ...CHESS_LIBRARY_PROGRAM_BASE, + code: bundled.code, + }, + input: CHESS_LIBRARY_INPUT, + gasLimit: CHESS_LIBRARY_GAS_LIMIT, + manifest: CHESS_LIBRARY_MANIFEST, + handlers: host.handlers, + }); + + expect(result.ok).toBe(true); + if (!result.ok) { + throw new Error(result.message); + } + expect(result.value).toBe(CHESS_E2E6_EXPECTED_LEGAL); + }); +}); diff --git a/apps/smoke-node/src/lib/examples-corpus.spec.ts b/apps/smoke-node/src/lib/examples-corpus.spec.ts new file mode 100644 index 0000000..2933eda --- /dev/null +++ b/apps/smoke-node/src/lib/examples-corpus.spec.ts @@ -0,0 +1,58 @@ +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { + BINARY_LIBRARY_FIXTURES, + DETERMINISM_FIXTURES, + EXAMPLE_CORPUS, + GAS_SAMPLE_FIXTURES, + MODULE_PACK_FIXTURES, +} from '@blue-quickjs/test-harness'; + +const currentDir = path.dirname(fileURLToPath(import.meta.url)); +const workspaceRoot = path.resolve(currentDir, '../../../..'); + +describe('examples corpus coverage', () => { + it('includes source files for all ten example categories', () => { + expect(EXAMPLE_CORPUS).toHaveLength(10); + const ids = new Set(EXAMPLE_CORPUS.map((entry) => entry.id)); + expect(ids.size).toBe(EXAMPLE_CORPUS.length); + + const sourcePaths = EXAMPLE_CORPUS.flatMap((entry) => entry.sourcePaths); + const missing = sourcePaths.filter( + (relativePath) => !fs.existsSync(path.join(workspaceRoot, relativePath)), + ); + + expect(missing).toEqual([]); + }); + + it('maps examples to existing fixture coverage', () => { + const fixtureSets = { + determinism: new Set(DETERMINISM_FIXTURES.map((fixture) => fixture.name)), + 'module-pack': new Set( + MODULE_PACK_FIXTURES.map((fixture) => fixture.name), + ), + 'gas-sample': new Set(GAS_SAMPLE_FIXTURES.map((fixture) => fixture.name)), + 'gas-boundary': new Set( + GAS_SAMPLE_FIXTURES.map((fixture) => fixture.name), + ), + 'binary-library': new Set( + BINARY_LIBRARY_FIXTURES.map((fixture) => fixture.name), + ), + 'chess-library': new Set(['chess-e2e6']), + } as const; + + const missingTargets: string[] = []; + for (const example of EXAMPLE_CORPUS) { + for (const target of example.coverage) { + if (!fixtureSets[target.suite].has(target.fixtureName)) { + missingTargets.push( + `${example.slug}:${target.suite}:${target.fixtureName}`, + ); + } + } + } + + expect(missingTargets).toEqual([]); + }); +}); diff --git a/apps/smoke-node/src/lib/module-pack-parity.spec.ts b/apps/smoke-node/src/lib/module-pack-parity.spec.ts new file mode 100644 index 0000000..30cff22 --- /dev/null +++ b/apps/smoke-node/src/lib/module-pack-parity.spec.ts @@ -0,0 +1,37 @@ +import { MODULE_PACK_FIXTURES } from '@blue-quickjs/test-harness'; +import { evaluate } from '@blue-quickjs/quickjs-runtime'; + +describe('smoke-node module-pack fixtures', () => { + it('executes module-pack fixtures with expected outcomes', async () => { + for (const fixture of MODULE_PACK_FIXTURES) { + const host = fixture.createHost(); + const result = await evaluate({ + program: fixture.program, + input: fixture.input, + gasLimit: fixture.gasLimit, + manifest: fixture.manifest, + handlers: host.handlers, + tape: { capacity: 16 }, + }); + + expect(result.ok).toBe(fixture.expected.ok); + + if (fixture.expected.ok) { + if (!result.ok) { + throw new Error( + `${fixture.name} expected success, got error ${result.error.code}`, + ); + } + expect(result.value).toEqual(fixture.expected.value); + } else { + if (result.ok) { + throw new Error(`${fixture.name} expected failure`); + } + expect(result.error.code).toBe(fixture.expected.errorCode); + expect('tag' in result.error ? result.error.tag : null).toBe( + fixture.expected.errorTag, + ); + } + } + }); +}); diff --git a/apps/smoke-node/tsconfig.lib.json b/apps/smoke-node/tsconfig.lib.json index c21c2fa..369217f 100644 --- a/apps/smoke-node/tsconfig.lib.json +++ b/apps/smoke-node/tsconfig.lib.json @@ -19,6 +19,9 @@ }, { "path": "../../libs/dv/tsconfig.lib.json" + }, + { + "path": "../../libs/deterministic-bundler/tsconfig.lib.json" } ], "exclude": [ diff --git a/apps/smoke-web/binary-library-reuse.html b/apps/smoke-web/binary-library-reuse.html new file mode 100644 index 0000000..cda1ead --- /dev/null +++ b/apps/smoke-web/binary-library-reuse.html @@ -0,0 +1,12 @@ + + + + + + Binary library reuse + + +
Loading binary library reuse fixture…
+ + + diff --git a/apps/smoke-web/chess-library-reuse.html b/apps/smoke-web/chess-library-reuse.html new file mode 100644 index 0000000..9db2f29 --- /dev/null +++ b/apps/smoke-web/chess-library-reuse.html @@ -0,0 +1,12 @@ + + + + + + Chess library reuse + + +
Loading chess library reuse fixture…
+ + + diff --git a/apps/smoke-web/module-pack-fixtures.html b/apps/smoke-web/module-pack-fixtures.html new file mode 100644 index 0000000..01f44ca --- /dev/null +++ b/apps/smoke-web/module-pack-fixtures.html @@ -0,0 +1,12 @@ + + + + + + Module-pack fixtures + + +
Loading module-pack fixtures…
+ + + diff --git a/apps/smoke-web/package.json b/apps/smoke-web/package.json index 24a5d08..1cbeb40 100644 --- a/apps/smoke-web/package.json +++ b/apps/smoke-web/package.json @@ -4,9 +4,10 @@ "type": "module", "private": true, "dependencies": { + "@blue-quickjs/deterministic-bundler": "workspace:*", "@blue-quickjs/dv": "workspace:*", - "@blue-quickjs/quickjs-wasm": "workspace:*", "@blue-quickjs/quickjs-runtime": "workspace:*", + "@blue-quickjs/quickjs-wasm": "workspace:*", "@blue-quickjs/test-harness": "workspace:*" }, "nx": { diff --git a/apps/smoke-web/src/app/gas-samples.element.ts b/apps/smoke-web/src/app/gas-samples.element.ts index 5fa6939..a583e64 100644 --- a/apps/smoke-web/src/app/gas-samples.element.ts +++ b/apps/smoke-web/src/app/gas-samples.element.ts @@ -45,13 +45,35 @@ interface FixtureResult { repeatSameContext?: RepeatSnapshot; } +interface BoundaryFixtureResult { + name: string; + firstSuccessGas: string; + lastFailureGas: string; + successGasUsed: string; + successGasRemaining: string; + failureGasUsed: string; + failureGasRemaining: string; + failureCode: string | null; + failureTag: string | null; +} + declare global { interface Window { __GAS_SAMPLE_RESULTS__?: FixtureResult[]; + __GAS_BOUNDARY_RESULTS__?: BoundaryFixtureResult[]; __GAS_SAMPLE_STATE__?: RunState; } } +const GAS_BOUNDARY_FIXTURE_NAMES = new Set([ + 'return-1', + 'loop-1k', + 'loop-10k', + 'string-concat', + 'object-alloc', + 'array-ops', +]); + export class GasSamplesElement extends HTMLElement { private isRunning = false; @@ -106,7 +128,13 @@ export class GasSamplesElement extends HTMLElement { }); } + const boundaryResults = await runBoundaryFixtureSearches( + metadata, + wasmBinary, + ); + window.__GAS_SAMPLE_RESULTS__ = results; + window.__GAS_BOUNDARY_RESULTS__ = boundaryResults; window.__GAS_SAMPLE_STATE__ = 'done'; this.renderResults(results); this.updateRunstate('done', 'Done'); @@ -222,6 +250,103 @@ function compareSnapshots( }; } +async function runBoundaryFixtureSearches( + metadata: Awaited>, + wasmBinary: Uint8Array, +): Promise { + const selected = GAS_SAMPLE_FIXTURES.filter((fixture) => + GAS_BOUNDARY_FIXTURE_NAMES.has(fixture.name), + ); + const results: BoundaryFixtureResult[] = []; + for (const fixture of selected) { + results.push(await findOutOfGasBoundary(fixture, metadata, wasmBinary)); + } + return results; +} + +async function findOutOfGasBoundary( + fixture: (typeof GAS_SAMPLE_FIXTURES)[number], + metadata: Awaited>, + wasmBinary: Uint8Array, +): Promise { + let upperGas = fixture.expected.gasUsed; + let upper = await runFixtureAtGasLimit( + fixture, + upperGas, + metadata, + wasmBinary, + ); + while (!upper.ok) { + upperGas *= 2n; + upper = await runFixtureAtGasLimit(fixture, upperGas, metadata, wasmBinary); + } + + let lowerGas = 0n; + let lower = await runFixtureAtGasLimit( + fixture, + lowerGas, + metadata, + wasmBinary, + ); + while (lowerGas + 1n < upperGas) { + const mid = (lowerGas + upperGas) >> 1n; + const current = await runFixtureAtGasLimit( + fixture, + mid, + metadata, + wasmBinary, + ); + if (current.ok) { + upperGas = mid; + upper = current; + } else { + lowerGas = mid; + lower = current; + } + } + + if (!upper.ok) { + throw new Error( + `boundary search failed for ${fixture.name}: no successful gas limit found`, + ); + } + if (lower.ok) { + throw new Error( + `boundary search failed for ${fixture.name}: expected failing gas limit`, + ); + } + + return { + name: fixture.name, + firstSuccessGas: upperGas.toString(), + lastFailureGas: lowerGas.toString(), + successGasUsed: upper.gasUsed.toString(), + successGasRemaining: upper.gasRemaining.toString(), + failureGasUsed: lower.gasUsed.toString(), + failureGasRemaining: lower.gasRemaining.toString(), + failureCode: lower.error.code, + failureTag: 'tag' in lower.error ? lower.error.tag : null, + }; +} + +async function runFixtureAtGasLimit( + fixture: (typeof GAS_SAMPLE_FIXTURES)[number], + gasLimit: bigint, + metadata: Awaited>, + wasmBinary: Uint8Array, +): Promise { + const host = fixture.createHost(); + return evaluate({ + program: fixture.program, + input: fixture.input, + gasLimit, + manifest: fixture.manifest, + handlers: host.handlers, + metadata, + wasmBinary, + }); +} + async function runRepeatSameContext( fixture: (typeof GAS_SAMPLE_FIXTURES)[number], metadata: Awaited>, diff --git a/apps/smoke-web/src/binary-library-reuse.ts b/apps/smoke-web/src/binary-library-reuse.ts new file mode 100644 index 0000000..c7456c0 --- /dev/null +++ b/apps/smoke-web/src/binary-library-reuse.ts @@ -0,0 +1,110 @@ +import { evaluate } from '@blue-quickjs/quickjs-runtime'; +import { + BINARY_LIBRARY_GAS_LIMIT, + BINARY_LIBRARY_INPUT, + BINARY_LIBRARY_MANIFEST, + BINARY_LIBRARY_PROGRAM_BASE, + createDeterminismHost, +} from '@blue-quickjs/test-harness'; + +type BinaryReuseResult = { + ok: boolean; + value: Record | null; + gasUsed: string; + gasRemaining: string; + errorCode: string | null; + errorTag: string | null; +}; + +declare global { + interface Window { + __BINARY_BUNDLED_CODE__?: string; + __BINARY_LIBRARY_REUSE_RESULT__?: BinaryReuseResult; + } +} + +renderShell(); +void run(); + +function renderShell(): void { + const app = document.querySelector('[data-app]'); + if (!app) { + return; + } + app.innerHTML = ` +

Binary package deterministic reuse

+

Execution profile: compat-binary-v1

+

Running…

+
waiting…
+ `; +} + +async function run(): Promise { + const runstate = document.querySelector('[data-runstate]'); + const resultEl = document.querySelector('[data-result]'); + + try { + const code = window.__BINARY_BUNDLED_CODE__; + if (typeof code !== 'string' || code.length === 0) { + throw new Error( + 'Missing bundled binary fixture code in window.__BINARY_BUNDLED_CODE__', + ); + } + + const host = createDeterminismHost(); + const result = await evaluate({ + program: { + ...BINARY_LIBRARY_PROGRAM_BASE, + code, + }, + input: BINARY_LIBRARY_INPUT, + gasLimit: BINARY_LIBRARY_GAS_LIMIT, + manifest: BINARY_LIBRARY_MANIFEST, + handlers: host.handlers, + }); + + const payload: BinaryReuseResult = result.ok + ? { + ok: true, + value: result.value as Record, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + errorCode: null, + errorTag: null, + } + : { + ok: false, + value: null, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + errorCode: result.error.code, + errorTag: 'tag' in result.error ? result.error.tag : null, + }; + + window.__BINARY_LIBRARY_REUSE_RESULT__ = payload; + if (runstate) { + runstate.dataset.runstate = 'done'; + runstate.textContent = payload.ok ? 'Done' : 'Failed'; + } + if (resultEl) { + resultEl.textContent = JSON.stringify(payload, null, 2); + } + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + window.__BINARY_LIBRARY_REUSE_RESULT__ = { + ok: false, + value: null, + gasUsed: '0', + gasRemaining: '0', + errorCode: 'BOOT_FAILURE', + errorTag: null, + }; + if (runstate) { + runstate.dataset.runstate = 'error'; + runstate.textContent = `Error: ${message}`; + } + if (resultEl) { + resultEl.textContent = message; + } + } +} diff --git a/apps/smoke-web/src/chess-library-reuse.ts b/apps/smoke-web/src/chess-library-reuse.ts new file mode 100644 index 0000000..7fa6294 --- /dev/null +++ b/apps/smoke-web/src/chess-library-reuse.ts @@ -0,0 +1,111 @@ +import { evaluate } from '@blue-quickjs/quickjs-runtime'; +import { + CHESS_E2E6_EXPECTED_LEGAL, + CHESS_LIBRARY_GAS_LIMIT, + CHESS_LIBRARY_INPUT, + CHESS_LIBRARY_MANIFEST, + CHESS_LIBRARY_PROGRAM_BASE, + createDeterminismHost, +} from '@blue-quickjs/test-harness'; + +type ChessReuseResult = { + ok: boolean; + value: boolean | null; + gasUsed: string; + gasRemaining: string; + errorCode: string | null; + errorTag: string | null; +}; + +declare global { + interface Window { + __CHESS_BUNDLED_CODE__?: string; + __CHESS_LIBRARY_REUSE_RESULT__?: ChessReuseResult; + } +} + +renderShell(); +void run(); + +function renderShell(): void { + const app = document.querySelector('[data-app]'); + if (!app) { + return; + } + app.innerHTML = ` +

Chess.js deterministic reuse

+

Expected e2e6 legal: ${String(CHESS_E2E6_EXPECTED_LEGAL)}

+

Running…

+
waiting…
+ `; +} + +async function run(): Promise { + const runstate = document.querySelector('[data-runstate]'); + const resultEl = document.querySelector('[data-result]'); + + try { + const code = window.__CHESS_BUNDLED_CODE__; + if (typeof code !== 'string' || code.length === 0) { + throw new Error( + 'Missing bundled chess code in window.__CHESS_BUNDLED_CODE__', + ); + } + + const host = createDeterminismHost(); + const result = await evaluate({ + program: { + ...CHESS_LIBRARY_PROGRAM_BASE, + code, + }, + input: CHESS_LIBRARY_INPUT, + gasLimit: CHESS_LIBRARY_GAS_LIMIT, + manifest: CHESS_LIBRARY_MANIFEST, + handlers: host.handlers, + }); + + const payload: ChessReuseResult = result.ok + ? { + ok: true, + value: result.value as boolean, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + errorCode: null, + errorTag: null, + } + : { + ok: false, + value: null, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + errorCode: result.error.code, + errorTag: 'tag' in result.error ? result.error.tag : null, + }; + + window.__CHESS_LIBRARY_REUSE_RESULT__ = payload; + if (runstate) { + runstate.dataset.runstate = 'done'; + runstate.textContent = payload.ok ? 'Done' : 'Failed'; + } + if (resultEl) { + resultEl.textContent = JSON.stringify(payload, null, 2); + } + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + window.__CHESS_LIBRARY_REUSE_RESULT__ = { + ok: false, + value: null, + gasUsed: '0', + gasRemaining: '0', + errorCode: 'BOOT_FAILURE', + errorTag: null, + }; + if (runstate) { + runstate.dataset.runstate = 'error'; + runstate.textContent = `Error: ${message}`; + } + if (resultEl) { + resultEl.textContent = message; + } + } +} diff --git a/apps/smoke-web/src/module-pack-fixtures.ts b/apps/smoke-web/src/module-pack-fixtures.ts new file mode 100644 index 0000000..f7ff9e0 --- /dev/null +++ b/apps/smoke-web/src/module-pack-fixtures.ts @@ -0,0 +1,103 @@ +import { evaluate } from '@blue-quickjs/quickjs-runtime'; +import { MODULE_PACK_FIXTURES } from '@blue-quickjs/test-harness'; +import { hashDv, hashTape } from './app/hash-utils.js'; + +type ModulePackFixtureSnapshot = { + ok: boolean; + valueHash: string | null; + errorCode: string | null; + errorTag: string | null; + gasUsed: string; + gasRemaining: string; + tapeHash: string | null; + tapeLength: number; +}; + +type ModulePackFixtureResult = { + name: string; + expectedOk: boolean; + actual: ModulePackFixtureSnapshot; +}; + +declare global { + interface Window { + __MODULE_PACK_FIXTURE_RESULTS__?: ModulePackFixtureResult[]; + } +} + +renderShell(); +void run(); + +function renderShell(): void { + const app = document.querySelector('[data-app]'); + if (!app) { + return; + } + app.innerHTML = ` +

Module-pack fixture parity

+

Running…

+
waiting…
+ `; +} + +async function run(): Promise { + const runstate = document.querySelector('[data-runstate]'); + const resultEl = document.querySelector('[data-result]'); + + try { + const results: ModulePackFixtureResult[] = []; + + for (const fixture of MODULE_PACK_FIXTURES) { + const host = fixture.createHost(); + const result = await evaluate({ + program: fixture.program, + input: fixture.input, + gasLimit: fixture.gasLimit, + manifest: fixture.manifest, + handlers: host.handlers, + tape: { capacity: 16 }, + }); + + const tape = result.tape ?? []; + const snapshot: ModulePackFixtureSnapshot = { + ok: result.ok, + valueHash: result.ok ? await hashDv(result.value) : null, + errorCode: result.ok ? null : result.error.code, + errorTag: result.ok + ? null + : 'tag' in result.error + ? result.error.tag + : null, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + tapeHash: await hashTape(tape), + tapeLength: tape.length, + }; + + results.push({ + name: fixture.name, + expectedOk: fixture.expected.ok, + actual: snapshot, + }); + } + + window.__MODULE_PACK_FIXTURE_RESULTS__ = results; + if (runstate) { + runstate.dataset.runstate = 'done'; + runstate.textContent = 'Done'; + } + if (resultEl) { + resultEl.textContent = JSON.stringify(results, null, 2); + } + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + window.__MODULE_PACK_FIXTURE_RESULTS__ = []; + if (runstate) { + runstate.dataset.runstate = 'error'; + runstate.textContent = `Error: ${message}`; + } + if (resultEl) { + resultEl.textContent = message; + } + } +} diff --git a/apps/smoke-web/tests/binary-library-reuse.spec.ts b/apps/smoke-web/tests/binary-library-reuse.spec.ts new file mode 100644 index 0000000..e389fe5 --- /dev/null +++ b/apps/smoke-web/tests/binary-library-reuse.spec.ts @@ -0,0 +1,89 @@ +import { bundleDeterministicProgram } from '@blue-quickjs/deterministic-bundler'; +import { evaluate } from '@blue-quickjs/quickjs-runtime'; +import { + BINARY_LIBRARY_FIXTURES, + BINARY_LIBRARY_GAS_LIMIT, + BINARY_LIBRARY_INPUT, + BINARY_LIBRARY_MANIFEST, + BINARY_LIBRARY_PROGRAM_BASE, + createDeterminismHost, +} from '@blue-quickjs/test-harness'; +import { expect, test } from '@playwright/test'; + +type BinaryReuseResult = { + ok: boolean; + value: Record | null; + gasUsed: string; + gasRemaining: string; + errorCode: string | null; + errorTag: string | null; +}; + +for (const fixture of BINARY_LIBRARY_FIXTURES) { + test(`browser matches node for ${fixture.name}`, async ({ page }) => { + const bundled = await bundleDeterministicProgram({ + absWorkingDir: process.cwd(), + entryPath: fixture.entryPath, + profile: 'compat-binary-v1', + }); + + const nodeResult = await runNodeFixture(bundled.code); + + await page.addInitScript((code) => { + ( + window as Window & { __BINARY_BUNDLED_CODE__?: string } + ).__BINARY_BUNDLED_CODE__ = code; + }, bundled.code); + + await page.goto('/binary-library-reuse.html'); + await page.waitForSelector('[data-runstate="done"]', { timeout: 30000 }); + + const browserResult = (await page.evaluate( + () => + ( + window as Window & { + __BINARY_LIBRARY_REUSE_RESULT__?: BinaryReuseResult; + } + ).__BINARY_LIBRARY_REUSE_RESULT__, + )) as BinaryReuseResult | undefined; + + expect(browserResult).toBeTruthy(); + expect(browserResult).toEqual(nodeResult); + expect(browserResult?.ok).toBe(true); + expect(browserResult?.value).toEqual(fixture.expectedValue); + }); +} + +async function runNodeFixture(code: string): Promise { + const host = createDeterminismHost(); + const result = await evaluate({ + program: { + ...BINARY_LIBRARY_PROGRAM_BASE, + code, + }, + input: BINARY_LIBRARY_INPUT, + gasLimit: BINARY_LIBRARY_GAS_LIMIT, + manifest: BINARY_LIBRARY_MANIFEST, + handlers: host.handlers, + }); + + if (result.ok) { + return { + ok: true, + value: result.value as Record, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + errorCode: null, + errorTag: null, + }; + } + + return { + ok: false, + value: null, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + errorCode: result.error.code, + errorTag: 'tag' in result.error ? result.error.tag : null, + }; +} diff --git a/apps/smoke-web/tests/chess-library-reuse.spec.ts b/apps/smoke-web/tests/chess-library-reuse.spec.ts new file mode 100644 index 0000000..dcb371f --- /dev/null +++ b/apps/smoke-web/tests/chess-library-reuse.spec.ts @@ -0,0 +1,87 @@ +import { bundleDeterministicProgram } from '@blue-quickjs/deterministic-bundler'; +import { evaluate } from '@blue-quickjs/quickjs-runtime'; +import { + CHESS_E2E6_EXPECTED_LEGAL, + CHESS_LIBRARY_ENTRY_PATH, + CHESS_LIBRARY_GAS_LIMIT, + CHESS_LIBRARY_INPUT, + CHESS_LIBRARY_MANIFEST, + CHESS_LIBRARY_PROGRAM_BASE, + createDeterminismHost, +} from '@blue-quickjs/test-harness'; +import { expect, test } from '@playwright/test'; + +type ChessReuseResult = { + ok: boolean; + value: boolean | null; + gasUsed: string; + gasRemaining: string; + errorCode: string | null; + errorTag: string | null; +}; + +test('browser matches node for bundled chess.js e2e6 legality', async ({ + page, +}) => { + const bundled = await bundleDeterministicProgram({ + absWorkingDir: process.cwd(), + entryPath: CHESS_LIBRARY_ENTRY_PATH, + profile: 'compat-general-v1', + }); + + const nodeResult = await runNodeFixture(bundled.code); + + await page.addInitScript((code) => { + ( + window as Window & { __CHESS_BUNDLED_CODE__?: string } + ).__CHESS_BUNDLED_CODE__ = code; + }, bundled.code); + + await page.goto('/chess-library-reuse.html'); + await page.waitForSelector('[data-runstate="done"]', { timeout: 30000 }); + + const browserResult = (await page.evaluate( + () => + (window as Window & { __CHESS_LIBRARY_REUSE_RESULT__?: ChessReuseResult }) + .__CHESS_LIBRARY_REUSE_RESULT__, + )) as ChessReuseResult | undefined; + + expect(browserResult).toBeTruthy(); + expect(browserResult).toEqual(nodeResult); + expect(browserResult?.ok).toBe(true); + expect(browserResult?.value).toBe(CHESS_E2E6_EXPECTED_LEGAL); +}); + +async function runNodeFixture(code: string): Promise { + const host = createDeterminismHost(); + const result = await evaluate({ + program: { + ...CHESS_LIBRARY_PROGRAM_BASE, + code, + }, + input: CHESS_LIBRARY_INPUT, + gasLimit: CHESS_LIBRARY_GAS_LIMIT, + manifest: CHESS_LIBRARY_MANIFEST, + handlers: host.handlers, + }); + + if (result.ok) { + return { + ok: true, + value: result.value as boolean, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + errorCode: null, + errorTag: null, + }; + } + + return { + ok: false, + value: null, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + errorCode: result.error.code, + errorTag: 'tag' in result.error ? result.error.tag : null, + }; +} diff --git a/apps/smoke-web/tests/examples-corpus.spec.ts b/apps/smoke-web/tests/examples-corpus.spec.ts new file mode 100644 index 0000000..1d1b784 --- /dev/null +++ b/apps/smoke-web/tests/examples-corpus.spec.ts @@ -0,0 +1,61 @@ +import { + BINARY_LIBRARY_FIXTURES, + EXAMPLE_CORPUS, +} from '@blue-quickjs/test-harness'; +import { expect, test } from '@playwright/test'; +import { mapByName, readBrowserResults } from './fixture-utils.js'; + +type NamedFixtureResult = { + name: string; +}; + +test('browser fixture suites cover example corpus mappings', async ({ + page, +}) => { + const determinismResults = await readBrowserResults( + page, + '/determinism.html', + '__DETERMINISM_RESULTS__', + 'determinism', + ); + const gasSampleResults = await readBrowserResults( + page, + '/gas-samples.html', + '__GAS_SAMPLE_RESULTS__', + 'gas sample', + ); + const gasBoundaryResults = await readBrowserResults( + page, + '/gas-samples.html', + '__GAS_BOUNDARY_RESULTS__', + 'gas boundary', + ); + const modulePackResults = await readBrowserResults( + page, + '/module-pack-fixtures.html', + '__MODULE_PACK_FIXTURE_RESULTS__', + 'module-pack fixture', + ); + + const suiteFixtureNames = { + determinism: new Set(mapByName(determinismResults).keys()), + 'gas-sample': new Set(mapByName(gasSampleResults).keys()), + 'gas-boundary': new Set(mapByName(gasBoundaryResults).keys()), + 'module-pack': new Set(mapByName(modulePackResults).keys()), + 'chess-library': new Set(['chess-e2e6']), + 'binary-library': new Set(BINARY_LIBRARY_FIXTURES.map((f) => f.name)), + } as const; + + const missingTargets: string[] = []; + for (const example of EXAMPLE_CORPUS) { + for (const target of example.coverage) { + if (!suiteFixtureNames[target.suite].has(target.fixtureName)) { + missingTargets.push( + `${example.slug}:${target.suite}:${target.fixtureName}`, + ); + } + } + } + + expect(missingTargets).toEqual([]); +}); diff --git a/apps/smoke-web/tests/gas-boundaries.spec.ts b/apps/smoke-web/tests/gas-boundaries.spec.ts new file mode 100644 index 0000000..5dbc9d9 --- /dev/null +++ b/apps/smoke-web/tests/gas-boundaries.spec.ts @@ -0,0 +1,152 @@ +import { + GAS_SAMPLE_FIXTURES, + type GasFixture, +} from '@blue-quickjs/test-harness'; +import { evaluate, type EvaluateResult } from '@blue-quickjs/quickjs-runtime'; +import { + loadQuickjsWasmBinary, + loadQuickjsWasmMetadata, +} from '@blue-quickjs/quickjs-wasm'; +import { expect, test } from '@playwright/test'; +import { mapByName, readBrowserResults } from './fixture-utils.js'; + +type BoundaryFixtureResult = { + name: string; + firstSuccessGas: string; + lastFailureGas: string; + successGasUsed: string; + successGasRemaining: string; + failureGasUsed: string; + failureGasRemaining: string; + failureCode: string | null; + failureTag: string | null; +}; + +const GAS_BOUNDARY_FIXTURE_NAMES = new Set([ + 'return-1', + 'loop-1k', + 'loop-10k', + 'string-concat', + 'object-alloc', + 'array-ops', +]); + +test('browser and node share exact OOG boundaries', async ({ page }) => { + const nodeResults = await runNodeBoundaries(); + const browserResults = await readBrowserResults( + page, + '/gas-samples.html', + '__GAS_BOUNDARY_RESULTS__', + 'gas boundary', + ); + + const nodeByName = mapByName(nodeResults); + const browserByName = mapByName(browserResults); + expect(browserByName.size).toBe(nodeByName.size); + + for (const [name, node] of nodeByName) { + const browser = browserByName.get(name); + expect(browser, `missing browser boundary fixture ${name}`).toBeTruthy(); + if (!browser) { + continue; + } + expect(browser).toEqual(node); + } +}); + +async function runNodeBoundaries(): Promise { + const metadata = await loadQuickjsWasmMetadata(); + const wasmBinary = await loadQuickjsWasmBinary(); + const selected = GAS_SAMPLE_FIXTURES.filter((fixture) => + GAS_BOUNDARY_FIXTURE_NAMES.has(fixture.name), + ); + + const results: BoundaryFixtureResult[] = []; + for (const fixture of selected) { + results.push(await findOutOfGasBoundary(fixture, metadata, wasmBinary)); + } + return results; +} + +async function findOutOfGasBoundary( + fixture: GasFixture, + metadata: Awaited>, + wasmBinary: Uint8Array, +): Promise { + let upperGas = fixture.expected.gasUsed; + let upper = await runFixtureAtGasLimit( + fixture, + upperGas, + metadata, + wasmBinary, + ); + while (!upper.ok) { + upperGas *= 2n; + upper = await runFixtureAtGasLimit(fixture, upperGas, metadata, wasmBinary); + } + + let lowerGas = 0n; + let lower = await runFixtureAtGasLimit( + fixture, + lowerGas, + metadata, + wasmBinary, + ); + while (lowerGas + 1n < upperGas) { + const mid = (lowerGas + upperGas) >> 1n; + const current = await runFixtureAtGasLimit( + fixture, + mid, + metadata, + wasmBinary, + ); + if (current.ok) { + upperGas = mid; + upper = current; + } else { + lowerGas = mid; + lower = current; + } + } + + if (!upper.ok) { + throw new Error( + `boundary search failed for ${fixture.name}: no successful gas limit found`, + ); + } + if (lower.ok) { + throw new Error( + `boundary search failed for ${fixture.name}: expected failing gas limit`, + ); + } + + return { + name: fixture.name, + firstSuccessGas: upperGas.toString(), + lastFailureGas: lowerGas.toString(), + successGasUsed: upper.gasUsed.toString(), + successGasRemaining: upper.gasRemaining.toString(), + failureGasUsed: lower.gasUsed.toString(), + failureGasRemaining: lower.gasRemaining.toString(), + failureCode: lower.error.code, + failureTag: 'tag' in lower.error ? lower.error.tag : null, + }; +} + +async function runFixtureAtGasLimit( + fixture: GasFixture, + gasLimit: bigint, + metadata: Awaited>, + wasmBinary: Uint8Array, +): Promise { + const host = fixture.createHost(); + return evaluate({ + program: fixture.program, + input: fixture.input, + gasLimit, + manifest: fixture.manifest, + handlers: host.handlers, + metadata, + wasmBinary, + }); +} diff --git a/apps/smoke-web/tests/module-pack-fixtures.spec.ts b/apps/smoke-web/tests/module-pack-fixtures.spec.ts new file mode 100644 index 0000000..3e3c68d --- /dev/null +++ b/apps/smoke-web/tests/module-pack-fixtures.spec.ts @@ -0,0 +1,97 @@ +import { evaluate } from '@blue-quickjs/quickjs-runtime'; +import { MODULE_PACK_FIXTURES } from '@blue-quickjs/test-harness'; +import { + loadQuickjsWasmBinary, + loadQuickjsWasmMetadata, +} from '@blue-quickjs/quickjs-wasm'; +import { expect, test } from '@playwright/test'; +import { hashDv, hashTape } from '../src/app/hash-utils.js'; +import { mapByName, readBrowserResults } from './fixture-utils.js'; + +type ModulePackFixtureSnapshot = { + ok: boolean; + valueHash: string | null; + errorCode: string | null; + errorTag: string | null; + gasUsed: string; + gasRemaining: string; + tapeHash: string | null; + tapeLength: number; +}; + +type ModulePackFixtureResult = { + name: string; + expectedOk: boolean; + actual: ModulePackFixtureSnapshot; +}; + +test('browser module-pack fixtures match Node outputs', async ({ page }) => { + const nodeResults = await runNodeFixtures(); + + const browserResults = await readBrowserResults( + page, + '/module-pack-fixtures.html', + '__MODULE_PACK_FIXTURE_RESULTS__', + 'module-pack fixture', + ); + + const nodeByName = mapByName(nodeResults); + const browserByName = mapByName(browserResults); + + expect(browserByName.size).toBe(nodeByName.size); + + for (const [name, node] of nodeByName) { + const browser = browserByName.get(name); + expect(browser, `missing browser fixture ${name}`).toBeTruthy(); + if (!browser) { + continue; + } + + expect(browser.expectedOk).toBe(node.expectedOk); + expect(browser.actual).toEqual(node.actual); + } +}); + +async function runNodeFixtures(): Promise { + const metadata = await loadQuickjsWasmMetadata(); + const wasmBinary = await loadQuickjsWasmBinary(); + const results: ModulePackFixtureResult[] = []; + + for (const fixture of MODULE_PACK_FIXTURES) { + const host = fixture.createHost(); + const result = await evaluate({ + program: fixture.program, + input: fixture.input, + gasLimit: fixture.gasLimit, + manifest: fixture.manifest, + handlers: host.handlers, + metadata, + wasmBinary, + tape: { capacity: 16 }, + }); + + const tape = result.tape ?? []; + const snapshot: ModulePackFixtureSnapshot = { + ok: result.ok, + valueHash: result.ok ? await hashDv(result.value) : null, + errorCode: result.ok ? null : result.error.code, + errorTag: result.ok + ? null + : 'tag' in result.error + ? result.error.tag + : null, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + tapeHash: await hashTape(tape), + tapeLength: tape.length, + }; + + results.push({ + name: fixture.name, + expectedOk: fixture.expected.ok, + actual: snapshot, + }); + } + + return results; +} diff --git a/apps/smoke-web/tsconfig.app.json b/apps/smoke-web/tsconfig.app.json index aa0ff36..963ca8c 100644 --- a/apps/smoke-web/tsconfig.app.json +++ b/apps/smoke-web/tsconfig.app.json @@ -34,13 +34,16 @@ "path": "../../libs/test-harness/tsconfig.lib.json" }, { - "path": "../../libs/quickjs-runtime/tsconfig.lib.json" + "path": "../../libs/quickjs-wasm/tsconfig.lib.json" }, { - "path": "../../libs/quickjs-wasm/tsconfig.lib.json" + "path": "../../libs/quickjs-runtime/tsconfig.lib.json" }, { "path": "../../libs/dv/tsconfig.lib.json" + }, + { + "path": "../../libs/deterministic-bundler/tsconfig.lib.json" } ] } diff --git a/docs/README.md b/docs/README.md index b5a00f6..3af2cc8 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,65 +1,67 @@ -# Documentation index - -This repository is a deterministic JavaScript execution environment built on **QuickJS** compiled to **WebAssembly**, with a **manifest-locked Host ABI**, a canonical **Deterministic Value (DV)** wire format, and **deterministic gas metering**. - -The docs are split between: - -- **Baselines** (what must be true) -- **Implementation plan** (how we intended to build it) -- **Implementation summary + guides** (what was built, how to use it) -- **Reference specs** (normative, detail-heavy) - -If you are new to determinism/gas (or coming from “normal” JS runtimes), follow the reading order below. - -## Recommended reading order - -1. **Baselines (requirements / contracts)** - - [Baseline #1 – Deterministic JS engine](./baseline-1.md) - - [Baseline #2 – Host ABI + DV contract](./baseline-2.md) - -2. **Plan (design log)** - - [Implementation plan](./implementation-plan.md) - -3. **What was built (narrative + repo map)** - - [Implementation summary](./implementation-summary.md) - -4. **Reference specs (details, normative behavior)** - - [Determinism profile](./determinism-profile.md) - - [Gas schedule](./gas-schedule.md) - - [Deterministic Value wire format](./dv-wire-format.md) - - [ABI manifest schema + canonical encoding](./abi-manifest.md) - - [Host call ABI (the `host_call` syscall)](./host-call-abi.md) - - [Toolchain + build determinism](./toolchain.md) - - [Release + compatibility policy](./release-policy.md) - -5. **Developer guides (practical usage)** - - [TypeScript SDK usage](./sdk.md) - - [ABI limits explained](./abi-limits.md) - - [Observability: host-call tape + gas trace](./observability.md) - -## Quick “repo map” - -Most people end up reading some docs and then jumping into these locations: - -- **QuickJS fork + deterministic patches**: `vendor/quickjs/` - - Deterministic init + gas metering: `vendor/quickjs/quickjs.c` - - Host ABI + manifest parsing + Host.v1 wrappers: `vendor/quickjs/quickjs-host.c` - - DV codec: `vendor/quickjs/quickjs-dv.c` - - SHA-256 helper used for tape hashing: `vendor/quickjs/quickjs-sha256.c` - - Wasm entrypoints: `vendor/quickjs/quickjs-wasm-entry.c` - -- **TypeScript libraries** - - DV reference implementation: `libs/dv/` - - Manifest schema + canonical encoding/hashing: `libs/abi-manifest/` - - Wasm constants + metadata types: `libs/quickjs-wasm-constants/` - - Wasm build pipeline + metadata: `libs/quickjs-wasm-build/` - - Packaged wasm artifacts: `libs/quickjs-wasm/` - - Runtime SDK (evaluate / init / dispatcher): `libs/quickjs-runtime/` - - Shared fixtures + parsers: `libs/test-harness/` - -- **Executable examples** - - Node smoke runner: `apps/smoke-node/` - - Browser smoke runner: `apps/smoke-web/` - -- **Native harness (golden tests & debugging)** - - `tools/quickjs-native-harness/` +# BlueQuickjs Docs + +Start with the root [README quickstart](../README.md), then jump to the +reference you need. + +## Start Here + +- [Core concepts](./concepts.md) +- [Learning path](./learn/README.md) +- [Architecture overview](./architecture-overview.md) +- [FAQ](./faq.md) +- [Glossary](./glossary.md) + +## Build And Use + +- [TypeScript SDK usage](./sdk.md) +- [Deterministic builder](./builder.md) +- [ModulePack.v1](./module-pack.md) +- [ProgramArtifact.v2](./program-artifact-v2.md) +- [Examples guide](./examples.md) +- [Playground](./playground.md) +- [Playground recipes](./playground-recipes.md) + +## Reference + +- [Consensus-safe vs diagnostic-only](./consensus-safe-vs-diagnostic-only.md) +- [Execution profiles](./execution-profiles.md) +- [Determinism profile](./determinism-profile.md) +- [Gas schedule](./gas-schedule.md) +- [DV wire format](./dv-wire-format.md) +- [Value model v2 (DV2)](./value-model-v2.md) +- [ABI manifest](./abi-manifest.md) +- [Host call ABI](./host-call-abi.md) +- [ABI limits](./abi-limits.md) +- [Observability](./observability.md) +- [Unsupported features and why](./unsupported-features-and-why.md) + +## Production + +- [Production embedder checklist](./production-embedder-checklist.md) +- [Embedder integration guide](./embedders.md) +- [Threat model](./threat-model.md) +- [Toolchain](./toolchain.md) + +## Release And Audit + +- [HEAD verification note](./head-verification-note.md) +- [Release-readiness report](./release-readiness-report.md) +- [Release checklist](./release-checklist.md) +- [Release policy](./release-policy.md) +- [Release provenance and trust model](./release-provenance.md) +- [Signature rotation and rollback](./signature-rotation-and-rollback.md) +- [Workload certification report](./workload-certification.md) +- [Ecosystem compatibility report](./ecosystem-compatibility-report.md) + +## Quick Repo Map + +- QuickJS fork and deterministic patches: `vendor/quickjs/`, + `vendor/quickjs-patches/` +- Builder and runtime libraries: `libs/deterministic-builder/`, + `libs/deterministic-bundler/`, `libs/quickjs-runtime/` +- Wasm build and package libraries: `libs/quickjs-wasm-build/`, + `libs/quickjs-wasm/` +- ABI and value libraries: `libs/abi-manifest/`, `libs/dv/` +- Smoke and certification apps: `apps/smoke-node/`, `apps/smoke-web/`, + `apps/ecosystem-certifier/` +- Diagnostic native harness: `tools/quickjs-native-harness/` diff --git a/docs/abi-manifest.md b/docs/abi-manifest.md index 74c6ddd..6121379 100644 --- a/docs/abi-manifest.md +++ b/docs/abi-manifest.md @@ -2,7 +2,7 @@ Baseline anchor: see `docs/baseline-2.md`. -The ABI manifest maps **numeric function IDs** to host capabilities and is the single source of truth for generating `Host.v1` and validating host responses. The manifest is canonicalized and hashed; both the VM and host dispatcher must consume identical bytes (Baseline #2 §1.1–§1.4, §6.1–§6.3). +The ABI manifest maps **numeric function IDs** to host capabilities and is the single source of truth for generating `Host.v*` namespaces (`Host.v1`, `Host.v2`) and validating host responses. The manifest is canonicalized and hashed; both the VM and host dispatcher must consume identical bytes (Baseline #2 §1.1–§1.4, §6.1–§6.3). ## Canonical structure @@ -13,8 +13,8 @@ The ABI manifest maps **numeric function IDs** to host capabilities and is the s ### Top-level fields -- `abi_id` (string): Must be `"Host.v1"` in the current implementation (validation rejects other values). This is the string baked into `P`. -- `abi_version` (uint32): Must be `1` in the current implementation (validation rejects other values). +- `abi_id` (string): Must be a supported ABI namespace id (currently `"Host.v1"` or `"Host.v2"`). This is the string baked into `P`. +- `abi_version` (uint32): Must match the selected `abi_id` (currently `1` for `Host.v1`, `2` for `Host.v2`). - `functions` (array): Ordered by ascending `fn_id` and must contain at least one entry. Each entry is a map described below. `fn_id` values MUST be unique. No other top-level keys are permitted; unknown keys make the manifest invalid. @@ -24,7 +24,7 @@ No other top-level keys are permitted; unknown keys make the manifest invalid. Each function is a DV map with the following fields (no extras): - `fn_id` (uint32): Numeric ID used by the VM when calling `host_call`. Range: `1`–`2^32 - 1`. -- `js_path` (array): Property path relative to `Host.v1` used to install the JS wrapper (e.g., `["document", "get"]`). Segments MUST be non-empty, match `[A-Za-z0-9_-]+`, and the array MUST contain at least one segment. The following segment values are forbidden: `__proto__`, `prototype`, `constructor`. +- `js_path` (array): Property path relative to the selected host namespace (`Host.v1` / `Host.v2`) used to install the JS wrapper (e.g., `["document", "get"]`). Segments MUST be non-empty, match `[A-Za-z0-9_-]+`, and the array MUST contain at least one segment. The following segment values are forbidden: `__proto__`, `prototype`, `constructor`. - `effect` (string enum): `"READ" | "EMIT" | "MUTATE"`. Determines host-side semantics and auditing. For P3, only `READ`/`EMIT` are used. - `arity` (uint32): Exact number of positional arguments accepted by the host function. - `arg_schema` (array): Length MUST equal `arity`. Each item is a schema map (see **Schema language** below). diff --git a/docs/architecture-overview.md b/docs/architecture-overview.md new file mode 100644 index 0000000..fb95a31 --- /dev/null +++ b/docs/architecture-overview.md @@ -0,0 +1,128 @@ +# Architecture overview + +BlueQuickjs turns source code into a pinned, deterministic execution artifact +that can be evaluated in consensus-safe wasm runtimes and then verified against +generated evidence. + +## End-to-end flow + +```text +source files / examples / package entrypoints + │ + ▼ +deterministic builder +(`buildDeterministicModulePack`, `blue-quickjs build`) + │ + ├─ compatibility diagnostics + ├─ ModulePack.v1 + └─ ProgramArtifact.v2 + - executionProfile + - abiManifestHash + - engineBuildHash + - gasVersion + - sourceKind + │ + ▼ +wasm runtime (`@blue-quickjs/quickjs-runtime`) + │ + ├─ wasm-node + └─ wasm-browser + with identical: + - value/error + - gas used/remaining + - host-call tape + - OOG boundary + │ + ▼ +generated evidence and reports + ├─ consensus reproducibility report + ├─ workload certification report + ├─ ecosystem compatibility report + └─ release evidence bundle +``` + +## The important product boundaries + +### 1. Builder stage + +The deterministic builder resolves imports, normalizes module sources, runs +profile-aware compatibility checks, and emits: + +- [`ModulePack.v1`](./module-pack.md) for static in-memory module execution +- [`ProgramArtifact.v2`](./program-artifact-v2.md) for pinned execution +- compatibility diagnostics for unsupported behavior + +This is where runtime `import()`/network/filesystem behavior is deliberately +removed from the consensus path. Imports are resolved **before** execution. + +### 2. Artifact stage + +`ProgramArtifact.v2` is the release-facing contract that binds together: + +- source mode (`script` or `module-pack`) +- execution profile +- ABI identity and manifest hash +- engine build pin (`engineBuildHash`) +- gas schedule pin (`gasVersion`) + +See: + +- [`ProgramArtifact.v2`](./program-artifact-v2.md) +- [`Execution profiles`](./execution-profiles.md) +- [`ModulePack.v1`](./module-pack.md) + +### 3. Runtime stage + +The runtime loads the canonical `wasm32` release engine and evaluates the +artifact against: + +- deterministic input envelope data, +- a manifest-locked host ABI, +- an exact gas limit, +- optional tape/trace capture. + +Consensus-safe release scope is currently: + +- `wasm-node` +- `wasm-browser` + +Native remains diagnostic-only unless explicitly promoted by release policy. + +See: + +- [`Determinism profile`](./determinism-profile.md) +- [`Host call ABI`](./host-call-abi.md) +- [`Consensus-safe vs diagnostic-only`](./consensus-safe-vs-diagnostic-only.md) + +### 4. Evidence stage + +What users see in docs, reports, and release artifacts should come from +generated evidence rather than hand-maintained prose. The repo already produces: + +- consensus parity reports, +- workload certification and ecosystem compatibility reports, +- release evidence manifests, checksums, and signatures. + +See: + +- [`HEAD verification note`](./head-verification-note.md) +- [`Workload certification`](./workload-certification.md) +- [`Release-readiness report`](./release-readiness-report.md) +- [`Release provenance and trust model`](./release-provenance.md) + +## Where to look in the repo + +- Builder APIs: `libs/deterministic-builder/`, `libs/deterministic-bundler/` +- Wasm packaging: `libs/quickjs-wasm-build/`, `libs/quickjs-wasm/` +- Runtime SDK: `libs/quickjs-runtime/` +- Shared fixtures/evidence inputs: `libs/test-harness/` +- Examples corpus: `examples/` +- Browser/node certification apps: + - `apps/smoke-web/` + - `apps/smoke-node/` + - `apps/ecosystem-certifier/` + +## Continue learning + +- Start the guided sequence at [Learn BlueQuickjs](./learn/README.md) +- Or jump straight to [Install and run your first script](./learn/01-install-and-run-your-first-script.md) diff --git a/docs/baseline-1.md b/docs/baseline-1.md index 50ef702..bb7fa10 100644 --- a/docs/baseline-1.md +++ b/docs/baseline-1.md @@ -37,7 +37,7 @@ Definitions: ## 2. “Same engine everywhere” (normative) - The evaluator must ship/instantiate the **same QuickJS-in-Wasm bytes** in Node and browsers. -- Engine identity (or equivalent immutable metadata) is pinnable via `P` (see runtime types and `docs/implementation-plan.md` for the broader architecture). +- Engine identity (or equivalent immutable metadata) is pinnable via `P` (see runtime types and `docs/architecture-overview.md` for the broader architecture). ## 3. Deterministic capability profile (normative) @@ -53,6 +53,10 @@ Determinism depends on a strict JS surface: The exact list and the required deterministic error messages are specified in `docs/determinism-profile.md`. +Compatibility profiles may opt in to narrowly scoped additional surfaces (for +example regexp support), but baseline behavior remains the default contract and +must stay unchanged unless explicitly selected by the program artifact. + ## 4. Canonical gas (normative) ### 4.1 Canonical gas is **inside QuickJS** diff --git a/docs/baseline-2.md b/docs/baseline-2.md index e6bb43f..de5e0e8 100644 --- a/docs/baseline-2.md +++ b/docs/baseline-2.md @@ -122,5 +122,6 @@ The VM projects the manifest into JS as: - namespace objects are non-extensible; function properties are non-writable and non-configurable, - ergonomic globals may be installed (`document`, `event`, `eventCanonical`, `steps`, `currentContract`, `currentContractCanonical`, `canon`) but must be deterministic and pinned by the deterministic init contract. -The current manifest ABI id/version is `Host.v1` (see `docs/abi-manifest.md` and `docs/determinism-profile.md`). +Current supported manifest ABI ids/versions are `Host.v1` and `Host.v2` +(see `docs/abi-manifest.md` and `docs/determinism-profile.md`). diff --git a/docs/builder.md b/docs/builder.md new file mode 100644 index 0000000..f8b7c73 --- /dev/null +++ b/docs/builder.md @@ -0,0 +1,87 @@ +# Deterministic builder + +This document defines the target behavior for the deterministic build pipeline. + +## Naming decision + +`deterministic-bundler` is a transitional bridge name. The long-term product +surface is **deterministic builder** because it emits first-class reusable +artifacts (`ModulePack.v1`, `ProgramArtifact.v2`), not just one script blob. + +### Current implementation status (P14) + +- `@blue-quickjs/deterministic-bundler` now exports + `buildDeterministicModulePack(...)` for `ModulePack.v1` emission. +- `@blue-quickjs/deterministic-builder` is introduced as a migration facade that + re-exports the deterministic builder APIs. +- `bundleDeterministicProgram(...)` remains available for transitional + script-mode execution. +- Builder result shape now includes: + - `CompatibilityReport.v1` + - optional embedded `ProgramArtifact.v2` output + - graph-hash golden test lock for serialization stability. + +## Goals + +- Deterministic JS/TS authoring pipeline for real libraries. +- Build-time resolution of npm/package imports. +- Emission of canonical module-pack artifacts and compatibility reports. + +## Inputs + +- Entry source: JS / TS / MJS / CJS. +- Installed dependencies + lockfile/integrity data. +- Execution profile target. +- Optional `dependencyIntegrity` override as lowercase SHA-256 hex (64 chars). + +## Outputs + +Required: + +- `ModulePack.v1` +- compatibility report +- canonical source maps + +Optional: + +- single-script debug artifact for transitional workflows + +## Deterministic constraints (normative) + +1. No network fetches during deterministic build. +2. No absolute path influence on hashed outputs. +3. Same graph + same dependencies => same `graphHash` across Linux/macOS/Windows. +4. Compatibility scanning must run on transformed JS or TS-aware AST, not raw TS + source text. +5. Dependency provenance is captured for diagnostics: + - package name, + - package version, + - integrity/lock fingerprint (`dependencyIntegrity`, lowercase SHA-256 hex), + - origin path (diagnostics-only metadata). + +## Build pipeline stages + +1. Resolve graph deterministically. +2. Transform sources to normalized JS modules. +3. Rewrite imports to canonical internal specifiers. +4. Run compatibility scan using selected profile/capability registry. +5. Emit module-pack + source maps + report. +6. Compute `graphHash`. +7. Emit `ProgramArtifact.v2` referencing module-pack and explicit profile. + +## Source map requirements + +- Canonical JSON formatting. +- Stable ordering for deterministic serialization. +- Path-clean mapping data (no absolute host paths in hashed content). + +## Release artifact rule + +Builder-produced release artifacts MUST include `engineBuildHash` and explicit +`executionProfile`, and `gasVersion`. + +## See also + +- `docs/program-artifact-v2.md` +- `docs/module-pack.md` +- `docs/execution-profiles.md` diff --git a/docs/concepts.md b/docs/concepts.md new file mode 100644 index 0000000..a666542 --- /dev/null +++ b/docs/concepts.md @@ -0,0 +1,59 @@ +# Core Concepts + +BlueQuickjs is an artifact, runtime, and evidence system. + +## Artifact + +A `ProgramArtifact.v2` pins the source, execution profile, ABI identity, engine +build hash, and gas schedule. Consensus execution should use artifacts, not ad +hoc source strings. + +See [ProgramArtifact.v2](./program-artifact-v2.md). + +## Runtime + +The consensus runtime is the canonical wasm32 QuickJS build. The current +consensus-safe executors are: + +- `wasm-node` +- `wasm-browser` + +Native tools are useful for diagnostics, but they are not consensus-safe unless +a release policy explicitly promotes them. + +See [Consensus-safe vs diagnostic-only](./consensus-safe-vs-diagnostic-only.md). + +## Profiles + +Execution profiles control which JavaScript capabilities are enabled: + +- `baseline-v1`: smallest deterministic surface. +- `compat-general-v1`: deterministic general JS features such as Promise jobs. +- `compat-binary-v1`: binary APIs and DV2 byte boundaries. + +See [Execution profiles](./execution-profiles.md). + +## Gas + +Gas is charged inside the engine and is part of the consensus result. Matching +value is not enough; gas used, gas remaining, and the exact out-of-gas boundary +must match too. + +See [Gas schedule](./gas-schedule.md). + +## Host ABI + +External capabilities cross a manifest-locked host boundary. Host values use +canonical DV/DV2 encoding, and host calls are metered and recorded in the +host-call tape. + +See [Host call ABI](./host-call-abi.md), [ABI manifest](./abi-manifest.md), and +[DV wire format](./dv-wire-format.md). + +## Evidence + +Generated evidence is the source of truth for release claims. Human summaries +should point to generated reports rather than restating the same facts by hand. + +See [HEAD verification note](./head-verification-note.md) and +[Release provenance](./release-provenance.md). diff --git a/docs/consensus-safe-vs-diagnostic-only.md b/docs/consensus-safe-vs-diagnostic-only.md new file mode 100644 index 0000000..29cb033 --- /dev/null +++ b/docs/consensus-safe-vs-diagnostic-only.md @@ -0,0 +1,51 @@ +# Consensus-safe vs diagnostic-only + +This page is the short answer to a critical release question: + +**what counts as the current consensus contract, and what is only diagnostic?** + +## Consensus-safe today + +The current consensus-safe executor matrix is: + +| Surface | Status | Notes | +| --- | --- | --- | +| `wasm-node` | consensus-safe | canonical `wasm32` release artifact | +| `wasm-browser` | consensus-safe | canonical `wasm32` release artifact | + +Release-critical parity for this matrix is exact: + +- value/error parity, +- gas used parity, +- gas remaining parity, +- host-call tape parity, +- OOG boundary parity. + +## Diagnostic-only today + +| Surface | Status | Why it is not consensus-safe today | +| --- | --- | --- | +| native harness | diagnostic-only | useful for debugging and reconciliation, but not the current release gate | +| WebKit browser runs | diagnostic-only | informative compatibility signal, not required release matrix | +| debug Wasm builds | diagnostic-only | useful for assertions/investigation, not the canonical release engine | +| alternate Wasm variants | diagnostic-only | canonical release scope is pinned to wasm32 | + +## What “diagnostic-only” does not mean + +Diagnostic-only does **not** mean “ignored” or “unimportant.” It means: + +- the repo may still generate reports for that surface, +- engineers may still use it to investigate mismatches, +- the release cannot market it as consensus-safe without explicit promotion. + +## What would change this page? + +Only an explicit policy and release decision should widen the consensus surface. +The repo should never silently drift from this page. + +## Related docs + +- [Release policy](./release-policy.md) +- [HEAD verification note](./head-verification-note.md) +- [Production embedder checklist](./production-embedder-checklist.md) +- [Workload certification](./workload-certification.md) diff --git a/docs/determinism-profile.md b/docs/determinism-profile.md index 0e2881f..2527451 100644 --- a/docs/determinism-profile.md +++ b/docs/determinism-profile.md @@ -7,6 +7,7 @@ Scope: capture the deterministic VM configuration required by Baseline #1 for bo ## Deterministic init entrypoints - `JS_NewDeterministicRuntime(out_rt, out_ctx)` creates a runtime/context in deterministic mode, disables GC heuristics, and sets gas to `JS_GAS_UNLIMITED` by default. +- `JS_NewDeterministicRuntimeWithFeatures(out_rt, out_ctx, feature_flags)` does the same with explicit deterministic feature toggles. Runtime integration uses this path for profile-controlled deterministic capabilities (RegExp, Promise jobs/`queueMicrotask`, console shim, stable sort, typed-array intrinsics). - `JS_InitDeterministicContext(ctx, options)` must run before user code. It: - requires manifest bytes and a lowercase hex hash; size limit 1 MiB (`JS_DETERMINISTIC_MAX_MANIFEST_BYTES`) - validates `sha256(manifest_bytes)` against the provided hash and throws `ManifestError` with code `ABI_MANIFEST_HASH_MISMATCH` on mismatch @@ -14,16 +15,36 @@ Scope: capture the deterministic VM configuration required by Baseline #1 for bo - optionally copies a context blob (max 5 MiB) and installs ergonomic globals - sets the gas limit to `options.gas_limit` +## Execution profiles + +`program.executionProfile` controls deterministic feature flags: + +- `baseline-v1` (default): canonical baseline restrictions. +- `compat-general-v1`: `baseline-v1` + RegExp + Promise jobs + + `queueMicrotask` + deterministic console shim + deterministic stable sort. +- `compat-binary-v1`: `compat-general-v1` + typed arrays / ArrayBuffer / + DataView plus DV2 byte-string boundary support. + +Profile behavior is implemented via `JS_NewDeterministicRuntimeWithFeatures` +feature flags and must stay aligned with `docs/execution-profiles.md`. + ## Enabled intrinsics -The deterministic init only loads these intrinsic sets: +Deterministic init always loads: - `JS_AddIntrinsicBaseObjects` - `JS_AddIntrinsicEval` - `JS_AddIntrinsicJSON` - `JS_AddIntrinsicMapSet` -`Date`, `RegExp`, `Proxy`, TypedArrays, Promise, and WeakRef intrinsics are not loaded in deterministic mode. +Profile-gated additions: + +- `JS_AddIntrinsicRegExp` when `regexp` is enabled. +- `JS_AddIntrinsicPromise` when Promise jobs are enabled. +- `JS_AddIntrinsicTypedArrays` when typed-array support is enabled. + +`Date`, `Proxy`, and `WeakRef` intrinsics remain unavailable in all current +profiles. ## Disabled or stubbed APIs (deterministic TypeError) @@ -32,19 +53,19 @@ The following globals or methods exist but throw the exact TypeError shown: - `eval(...)` -> `TypeError: eval is disabled in deterministic mode` - `Function(...)` -> `TypeError: Function is disabled in deterministic mode` - Function constructor paths (`Function.prototype.constructor`, arrow/generator constructors) -> `TypeError: Function constructor is disabled in deterministic mode` -- `RegExp` and regex literals -> `TypeError: RegExp is disabled in deterministic mode` +- `RegExp` and regex literals -> `TypeError: RegExp is disabled in deterministic mode` (**baseline-v1 only**) - `Proxy` -> `TypeError: Proxy is disabled in deterministic mode` -- `Promise` and statics (`resolve`, `reject`, `all`, `race`, `any`, `allSettled`) -> `TypeError: Promise is disabled in deterministic mode` +- `Promise` and statics (`resolve`, `reject`, `all`, `race`, `any`, `allSettled`) -> `TypeError: Promise is disabled in deterministic mode` (**baseline-v1 only**) - `Math.random()` -> `TypeError: Math.random is disabled in deterministic mode` -- `ArrayBuffer` -> `TypeError: ArrayBuffer is disabled in deterministic mode` +- `ArrayBuffer` -> `TypeError: ArrayBuffer is disabled in deterministic mode` (**baseline-v1 / compat-general-v1**) - `SharedArrayBuffer` -> `TypeError: SharedArrayBuffer is disabled in deterministic mode` -- `DataView` -> `TypeError: DataView is disabled in deterministic mode` -- Typed arrays: `Uint8Array`, `Uint8ClampedArray`, `Int8Array`, `Uint16Array`, `Int16Array`, `Uint32Array`, `Int32Array`, `BigInt64Array`, `BigUint64Array`, `Float16Array`, `Float32Array`, `Float64Array` -> `TypeError: Typed arrays are disabled in deterministic mode` +- `DataView` -> `TypeError: DataView is disabled in deterministic mode` (**baseline-v1 / compat-general-v1**) +- Typed arrays: `Uint8Array`, `Uint8ClampedArray`, `Int8Array`, `Uint16Array`, `Int16Array`, `Uint32Array`, `Int32Array`, `BigInt64Array`, `BigUint64Array`, `Float16Array`, `Float32Array`, `Float64Array` -> `TypeError: Typed arrays are disabled in deterministic mode` (**baseline-v1 / compat-general-v1**) - `Atomics` -> `TypeError: Atomics is disabled in deterministic mode` - `WebAssembly` -> `TypeError: WebAssembly is disabled in deterministic mode` -- `console.log/info/warn/error/debug` -> `TypeError: console is disabled in deterministic mode` +- `console.log/info/warn/error/debug` -> `TypeError: console is disabled in deterministic mode` (**baseline-v1**) - `print` -> `TypeError: print is disabled in deterministic mode` -- `Array.prototype.sort` -> `TypeError: Array.prototype.sort is disabled in deterministic mode` +- `Array.prototype.sort` -> `TypeError: Array.prototype.sort is disabled in deterministic mode` (**baseline-v1**) Notes: @@ -89,12 +110,16 @@ Why: ### Time, scheduling, and asynchrony -Absent/disabled: +Absent/disabled by profile: - `Date` - `setTimeout` / `setInterval` -- `queueMicrotask` -- `Promise` +- `queueMicrotask` (`baseline-v1`) +- `Promise` (`baseline-v1`) + +Enabled in compatibility profiles: + +- `Promise` jobs + `queueMicrotask` (`compat-general-v1`, `compat-binary-v1`) Why: @@ -117,12 +142,17 @@ Why: ### Binary buffers, shared memory, and low-level representation -Disabled: +Disabled by profile: -- `ArrayBuffer`, `DataView`, typed arrays (`Uint8Array`, `Float64Array`, …) +- `ArrayBuffer`, `DataView`, typed arrays (`Uint8Array`, `Float64Array`, ...) + (`baseline-v1`, `compat-general-v1`) - `SharedArrayBuffer` - `Atomics` +Enabled in compatibility profiles: + +- `ArrayBuffer`, `DataView`, typed arrays (`compat-binary-v1`) + Why: - **Representation leaks:** typed views can observe IEEE-754 edge cases like NaN payload bits and `-0` @@ -207,11 +237,11 @@ Why this split exists: ### Engine-version-dependent behavior and performance cliffs -Disabled: +Disabled by profile: -- `RegExp` (and regex literals) +- `RegExp` (and regex literals) in `baseline-v1` - `Proxy` -- `Array.prototype.sort` +- `Array.prototype.sort` in `baseline-v1` Why: @@ -242,7 +272,7 @@ The deterministic init does not install these globals; `typeof` returns `"undefi - `Date` - `setTimeout` / `setInterval` -- `queueMicrotask` +- `queueMicrotask` (**baseline-v1**) ## Host namespace and ergonomic globals diff --git a/docs/ecosystem-compatibility-baseline-0.4.1.json b/docs/ecosystem-compatibility-baseline-0.4.1.json new file mode 100644 index 0000000..e3e01f7 --- /dev/null +++ b/docs/ecosystem-compatibility-baseline-0.4.1.json @@ -0,0 +1,36 @@ +{ + "release": "0.4.1", + "date": "2026-03-13", + "summary": { + "greenCount": 16, + "redCount": 8, + "flagshipCount": 1 + }, + "fixtures": [ + { "id": "flagship-knowledge-pack", "kind": "flagship", "expectedStage": "success" }, + { "id": "green-chess", "kind": "positive", "expectedStage": "success" }, + { "id": "green-base64", "kind": "positive", "expectedStage": "success" }, + { "id": "green-noble-sha", "kind": "positive", "expectedStage": "success" }, + { "id": "green-semver", "kind": "positive", "expectedStage": "success" }, + { "id": "green-he", "kind": "positive", "expectedStage": "success" }, + { "id": "green-path-to-regexp", "kind": "positive", "expectedStage": "success" }, + { "id": "green-fast-json-stable-stringify", "kind": "positive", "expectedStage": "success" }, + { "id": "green-json-logic-js", "kind": "positive", "expectedStage": "success" }, + { "id": "green-crc32", "kind": "positive", "expectedStage": "success" }, + { "id": "green-tinyqueue", "kind": "positive", "expectedStage": "success" }, + { "id": "green-fflate", "kind": "positive", "expectedStage": "success" }, + { "id": "green-linkify-it", "kind": "positive", "expectedStage": "success" }, + { "id": "green-markdown-it", "kind": "positive", "expectedStage": "success" }, + { "id": "green-escape-string-regexp", "kind": "positive", "expectedStage": "success" }, + { "id": "green-fast-deep-equal", "kind": "positive", "expectedStage": "success" }, + { "id": "green-stress-corpus", "kind": "positive", "expectedStage": "success" }, + { "id": "red-diff-timers", "kind": "negative", "expectedStage": "builder_reject" }, + { "id": "red-yaml-date", "kind": "negative", "expectedStage": "builder_reject" }, + { "id": "red-graphlib-proxy", "kind": "negative", "expectedStage": "builder_reject" }, + { "id": "red-dynamic-import", "kind": "negative", "expectedStage": "builder_reject" }, + { "id": "red-proxy", "kind": "negative", "expectedStage": "builder_reject" }, + { "id": "red-math-random", "kind": "negative", "expectedStage": "builder_reject" }, + { "id": "red-lodash-function-constructor", "kind": "negative", "expectedStage": "artifact_validation" }, + { "id": "red-function-constructor", "kind": "negative", "expectedStage": "artifact_validation" } + ] +} diff --git a/docs/ecosystem-compatibility-report.md b/docs/ecosystem-compatibility-report.md new file mode 100644 index 0000000..eaa6469 --- /dev/null +++ b/docs/ecosystem-compatibility-report.md @@ -0,0 +1,75 @@ +# Ecosystem Compatibility Report + +This report tracks the current certification corpus in +`apps/ecosystem-certifier/src/shared/fixtures.ts`. + +## Green corpus (25 fixtures) + +All fixtures below are expected to pass with strict node/browser parity. +This corpus currently includes **24 third-party packages** plus one seeded +stress fixture. + +| Package | Fixture id | Profile | +| --- | --- | --- | +| `chess.js` | `green-chess` | `compat-general-v1` | +| `base64-js` | `green-base64` | `compat-binary-v1` | +| `@noble/hashes` | `green-noble-sha` | `compat-binary-v1` | +| `semver` | `green-semver` | `compat-general-v1` | +| `he` | `green-he` | `compat-general-v1` | +| `path-to-regexp` | `green-path-to-regexp` | `compat-general-v1` | +| `fast-json-stable-stringify` | `green-fast-json-stable-stringify` | `compat-general-v1` | +| `json-logic-js` | `green-json-logic-js` | `compat-general-v1` | +| `crc-32` | `green-crc32` | `compat-binary-v1` | +| `tinyqueue` | `green-tinyqueue` | `compat-general-v1` | +| `fflate` | `green-fflate` | `compat-binary-v1` | +| `linkify-it` | `green-linkify-it` | `compat-general-v1` | +| `markdown-it` | `green-markdown-it` | `compat-binary-v1` | +| `escape-string-regexp` | `green-escape-string-regexp` | `compat-general-v1` | +| `fast-deep-equal` | `green-fast-deep-equal` | `compat-general-v1` | +| `camelcase` | `green-camelcase` | `compat-general-v1` | +| `decamelize` | `green-decamelize` | `compat-general-v1` | +| `fastest-levenshtein` | `green-fastest-levenshtein` | `compat-binary-v1` | +| `dijkstrajs` | `green-dijkstrajs` | `compat-general-v1` | +| `spark-md5` | `green-spark-md5` | `compat-binary-v1` | +| `query-string` | `green-query-string` | `compat-general-v1` | +| `deepmerge` | `green-deepmerge` | `compat-general-v1` | +| `sort-keys` | `green-sort-keys` | `compat-general-v1` | +| `array-move` | `green-array-move` | `compat-general-v1` | +| Seeded stress corpus | `green-stress-corpus` | `compat-general-v1` | + +## Red corpus (8 scenarios) + +All fixtures below are expected deterministic failures with stable failure stage. + +| Scenario | Fixture id | Expected stage | Why | +| --- | --- | --- | --- | +| `diff` timer usage | `red-diff-timers` | `builder_reject` | package references `setTimeout` | +| `yaml` date usage | `red-yaml-date` | `builder_reject` | package references `Date` | +| `graphlib` proxy usage | `red-graphlib-proxy` | `builder_reject` | package references `Proxy` | +| Dynamic import | `red-dynamic-import` | `builder_reject` | `import()` disabled | +| Proxy API | `red-proxy` | `builder_reject` | `Proxy` disabled | +| Randomness API | `red-math-random` | `builder_reject` | `Math.random()` disabled | +| `lodash-es` runtime codegen path | `red-lodash-function-constructor` | `artifact_validation` | runtime reaches `Function` constructor path | +| Function constructor explicit | `red-function-constructor` | `artifact_validation` | deterministic runtime rejects dynamic codegen | + +## Flagship workload status + +- Fixture id: `flagship-knowledge-pack` +- Uses mixed deterministic package set (markdown/linkification/rules/semver/binary + decode/hash/queue ordering). +- Runs under `compat-binary-v1` with Host.v2 and emits deterministic tape + evidence. + +## Machine-readable evidence + +Generate and archive: + +```bash +node apps/ecosystem-certifier/scripts/archive-workload-certification-report.mjs --out-dir artifacts/workload-certification +node apps/ecosystem-certifier/scripts/generate-compatibility-delta-report.mjs --current-dir artifacts/workload-certification --out-dir artifacts/workload-certification +``` + +Use `compatibilityMatrix` and `records` in the generated JSON as canonical +source-of-truth for certification decisions. +Use `compatibility-delta-report.json` to compare fixture coverage against the +previous release baseline. diff --git a/docs/embedders.md b/docs/embedders.md new file mode 100644 index 0000000..e3ca51c --- /dev/null +++ b/docs/embedders.md @@ -0,0 +1,69 @@ +# Embedder integration guide + +This document defines integration boundaries for systems embedding blue-quickjs. + +## Scope boundary + +This repository owns **deterministic evaluation**. + +It does **not** own: + +- workflow orchestration, +- overlay/commit pipelines, +- external persistence or job scheduling. + +Those belong to the embedding system (for example document-processor). + +## Embedder responsibilities + +1. Build artifacts using deterministic builder outputs (`ProgramArtifact.v2`, + `ModulePack.v1`). +2. Provide deterministic host handlers for declared ABI functions. +3. Supply deterministic input envelope data (`I`) and gas limit (`G`). +4. Pin and validate: + - ABI manifest hash, + - engine build hash, + - execution profile. +5. Treat evaluator output (`result`, `gas`, `tape`, errors) as immutable + execution evidence. + +## Runtime constraints embedders must respect + +- No reentrant host calls into VM. +- No async host callbacks during synchronous VM evaluation. +- No hidden side channels (clock, randomness, network/filesystem) bypassing ABI. + +## Recommended integration flow + +1. Resolve/build source -> `ModulePack.v1` + compatibility report. +2. Construct `ProgramArtifact.v2` with explicit profile and pins. +3. Execute via SDK runtime. +4. Record deterministic outputs and optional tape/trace. +5. Perform policy-specific post-processing outside evaluator boundary. + +## Versioning expectations + +- Treat profile names, ABI ids/versions, and value-model version as explicit + contracts. +- Do not silently upgrade artifacts across incompatible versions. + +## Parity expectations + +For release confidence, embedders should run strict parity checks across the +supported **consensus executors**: + +- wasm in Node, +- wasm in browser, + +matching on result hash, gas, tape, error code/tag, and exact OOG boundary. + +Native harness parity remains strongly recommended for diagnostics and +reconciliation. Treat native as non-consensus unless it is explicitly certified +for strict zero-delta parity against canonical wasm execution. + +## See also + +- `docs/sdk.md` +- `docs/program-artifact-v2.md` +- `docs/module-pack.md` +- `docs/value-model-v2.md` diff --git a/docs/examples.md b/docs/examples.md new file mode 100644 index 0000000..8762dbc --- /dev/null +++ b/docs/examples.md @@ -0,0 +1,14 @@ +# Examples guide + +The runnable deterministic example corpus is maintained in: + +- [`examples/README.md`](../examples/README.md) + +That guide includes: + +- all 10 required example categories, +- source-file locations for each scenario, +- expected gas/result/OOG evidence keys, +- the in-repo playground entry point for interactive inspection, +- consensus executor reproducibility commands (`wasm-node` vs `wasm-browser`), +- native diagnostic reproducibility commands. diff --git a/docs/execution-profiles.md b/docs/execution-profiles.md new file mode 100644 index 0000000..76a82d7 --- /dev/null +++ b/docs/execution-profiles.md @@ -0,0 +1,81 @@ +# Execution profiles and capability registry + +Baseline anchor: `docs/baseline-1.md`. + +This document defines the **profile model** for runtime capability gating and +builder compatibility checks. + +## Design decision + +The platform uses: + +1. a **granular internal capability registry**, and +2. a **small public set of composite profiles**. + +We do **not** expose a growing list of one-feature public profiles. + +## Registry shape (conceptual) + +```ts +type Capability = + | 'regexp' + | 'promiseJobs' + | 'queueMicrotask' + | 'stableSort' + | 'consoleShim' + | 'typedArrays' + | 'dvBytes'; +``` + +The registry is the single source of truth for: + +- runtime validation, +- VM feature-flag wiring, +- builder compatibility scan, +- native harness profile flags, +- docs capability tables. + +## Public profiles (normative) + +### `baseline-v1` + +Deterministic baseline close to current behavior: + +- no Promise jobs / microtasks, +- no typed arrays / ArrayBuffer / DataView, +- no DV bytes boundary, +- no dynamic import/timers/runtime fs-network. + +### `compat-general-v1` + +`baseline-v1` +: + +- `regexp` +- `promiseJobs` +- `queueMicrotask` +- `stableSort` +- `consoleShim` + +### `compat-binary-v1` + +`compat-general-v1` +: + +- `typedArrays` +- `dvBytes` + +## Artifact rule + +`ProgramArtifact.v2.executionProfile` is required for build outputs and runtime +execution. Silent profile defaults are not allowed in release artifacts. + +## Compatibility policy + +- Baseline behavior MUST NOT widen unintentionally. +- Profile changes require explicit spec and tests. +- Public profile names are versioned contracts. + +## See also + +- `docs/program-artifact-v2.md` +- `docs/value-model-v2.md` +- `docs/determinism-profile.md` diff --git a/docs/faq.md b/docs/faq.md new file mode 100644 index 0000000..214a43d --- /dev/null +++ b/docs/faq.md @@ -0,0 +1,53 @@ +# FAQ + +## Is BlueQuickjs a general-purpose JavaScript runtime? + +No. It is a deterministic execution product for consensus-critical workloads. +The repo intentionally excludes or gates many capabilities that ordinary JS +runtimes expose freely. + +## What is the consensus-safe executor matrix? + +Today it is: + +- `wasm-node` +- `wasm-browser` + +using the canonical `wasm32` release engine. + +## Is native consensus-safe? + +Not today. Native remains diagnostic-only unless release policy explicitly +promotes it later. + +## Why are imports build-time deterministic instead of runtime dynamic? + +Because runtime fetch/import behavior would widen the deterministic surface. +BlueQuickjs resolves imports ahead of time and executes a pinned +`ModulePack.v1`. + +## Why are there multiple execution profiles? + +To keep the minimal consensus baseline narrow while still supporting specific +compatibility surfaces in explicitly versioned contracts. + +## When can I use Promises? + +Only under compatibility profiles that enable Promise job draining, such as +`compat-general-v1` and `compat-binary-v1`. + +## When can I use typed arrays or bytes? + +Only under `compat-binary-v1`, with the corresponding DV2 / `Host.v2` +boundaries. + +## Why do `engineBuildHash` and `gasVersion` matter? + +They are the pins that keep artifacts tied to the exact engine bytes and gas +schedule they were certified against. + +## What should I trust: docs or generated evidence? + +Generated evidence. The docs should explain the product, but release-critical +truth comes from the consensus, workload, consumer-proof, and release-evidence +artifacts. diff --git a/docs/gas-schedule.md b/docs/gas-schedule.md index 0f094b8..c5f1566 100644 --- a/docs/gas-schedule.md +++ b/docs/gas-schedule.md @@ -1,12 +1,15 @@ # Gas Schedule (Baseline #1) +> This file is generated from `tools/gas-spec/gas-spec.v3.json`. +> Update the gas spec source and rerun `node tools/gas-spec/render-gas-artifacts.mjs`. + Baseline anchor: see `docs/baseline-1.md` (determinism + canonical gas) and `docs/baseline-2.md` (host-call ABI/gas parameters). Scope: define canonical gas units for QuickJS execution and host calls per Baseline #1. This document is normative and must match harness assertions. ## Gas version and limits -- `JS_GAS_VERSION_LATEST = 2` +- `JS_GAS_VERSION_LATEST = 8` - Gas amounts are uint64. - `JS_GAS_UNLIMITED` disables charging and reports gas used as 0. - `JS_UseGas` subtracts from `gas_remaining`; if `amount > gas_remaining`, it sets `gas_remaining = 0` and throws an uncatchable `OutOfGas: out of gas` error. @@ -31,13 +34,49 @@ The per-element charge is applied for each iteration step, even when a hole is s Each allocation charges: -- Base: `JS_GAS_ALLOC_BASE = 3` +- Base: `JS_GAS_ALLOC_BASE = 0` - Byte charge: `1` gas per `16` requested bytes (`JS_GAS_ALLOC_PER_BYTE_SHIFT = 4`) Formula: - `JS_GAS_ALLOC_BASE + ceil(size / 16)` where `size` is the requested allocation size. +Current deterministic normalization model: + +- Mode: `none` +- Note: Canonical allocation charging no longer uses pointer-width normalization heuristics. +- No pointer-width normalization is applied. + +Canonical allocation classes (width-independent charged-byte formulas): + +- Object header: `64` +- Property slot: `16` +- Shape header: `48` +- Shape property entry: `12` +- String header: `0` +- Array slot: `8` +- Module record: `128` +- Module entry: `24` +- Promise/job base: `48` +- Promise/job arg unit: `8` +- ArrayBuffer header: `48` +- TypedArray backing unit: `1` +- TypedArray record: `40` +- Compiler function-def record: `512` +- Closure-var entry: `16` +- Var-ref pointer entry: `8` +- Var-ref record: `32` +- Generic dynamic-array unit: `16` +- Unknown-class small-allocation floor: `64` +- Unknown-class small-allocation max size: `4096` +- Unknown-class charges enabled: `false` +- Object-header charges enabled: `false` +- Property-slot charges enabled: `false` +- Shape charges enabled: `false` +- ArrayBuffer-header charges enabled: `false` +- TypedArray-backing charges enabled: `false` +- TypedArray-record charges enabled: `false` + ## Deterministic JSON builtin gas Deterministic mode exposes metered `JSON.parse` / `JSON.stringify` built-ins. These @@ -90,7 +129,7 @@ Interpretation: ## Garbage collection (GC) checkpoints - Automatic GC heuristics are disabled in deterministic mode (`js_trigger_gc` is a no-op and GC threshold is set to `-1`). -- A deterministic counter tracks requested allocation bytes. When it reaches `JS_DET_GC_THRESHOLD_BYTES = 512 * 1024`, `det_gc_pending` is set. +- A deterministic counter tracks charged allocation bytes. When it reaches `JS_DET_GC_THRESHOLD_BYTES = 524288`, `det_gc_pending` is set. - `JS_RunGCCheckpoint(ctx)` runs GC only when `det_gc_pending` is set; it then clears the flag and counter. - GC costs `0` gas; allocation gas amortizes it. - Checkpoints are invoked at deterministic points (pre/post eval and around host calls). @@ -100,9 +139,9 @@ Interpretation: Host-call gas uses parameters from the ABI manifest `gas` fields (see `docs/abi-manifest.md`). - Pre-charge before the host call: - - `gas_pre = base + (k_arg_bytes * request_bytes)` + - `base + (k_arg_bytes * request_bytes)` - Post-charge after response parse: - - `gas_post = (k_ret_bytes * response_bytes) + (k_units * units)` + - `(k_ret_bytes * response_bytes) + (k_units * units)` Where: @@ -119,5 +158,4 @@ Overflow during charge throws `TypeError: host_call gas overflow`. OOG on pre-ch - allocation gas, - deterministic `JSON.parse` gas, - deterministic `JSON.stringify` gas. -- Host-call gas is billed but not included in the trace totals; tests compute host gas as: - - `gasUsed - (opcode + array + allocation + jsonParse + jsonStringify)` +- Host-call gas is billed and tracked in dedicated host pre/post counters. diff --git a/docs/glossary.md b/docs/glossary.md new file mode 100644 index 0000000..22d33db --- /dev/null +++ b/docs/glossary.md @@ -0,0 +1,67 @@ +# Glossary + +## ABI manifest + +The canonical manifest that defines which host functions exist, what numeric +IDs they use, and which ABI version an artifact expects. + +## Consensus-safe + +Part of the current release contract. Today that means `wasm-node` and +`wasm-browser` running the canonical `wasm32` release engine with exact parity +requirements. + +## Diagnostic-only + +Useful for debugging, investigation, or reconciliation, but not part of the +current consensus release gate. Native and WebKit runs currently live here. + +## DV / DV1 + +Deterministic Value encoding used at host/runtime boundaries for canonical +structured values that do not include byte strings. + +## DV2 + +Versioned extension of DV that adds canonical bytes support for `Host.v2` and +binary-heavy workloads. + +## engineBuildHash + +The SHA-256 identity pin for the engine build bytes. Release-mode artifacts use +this to ensure the runtime matches the intended Wasm engine. + +## execution profile + +A named capability contract that determines which compatibility features are +allowed during execution: + +- `baseline-v1` +- `compat-general-v1` +- `compat-binary-v1` + +## gasVersion + +The version number of the canonical gas schedule expected by an artifact and +runtime. + +## host-call tape + +The deterministic record of host calls emitted during execution, including +request/response hashes, gas before/after, and units charged. + +## ModulePack.v1 + +The canonical deterministic module graph artifact used to execute static ESM +without runtime network/filesystem/module-registry access. + +## OOG boundary + +The exact gas limit where execution changes from failure to success, or +vice versa. BlueQuickjs treats this boundary as release-critical evidence for +consensus executors. + +## ProgramArtifact.v2 + +The versioned execution artifact that carries source, profile, ABI pins, +engine pin, gas pin, and source kind. diff --git a/docs/head-verification-note.md b/docs/head-verification-note.md new file mode 100644 index 0000000..8b0ae81 --- /dev/null +++ b/docs/head-verification-note.md @@ -0,0 +1,89 @@ +# HEAD verification note + +This document is the quickest “state of HEAD” snapshot for engineers, auditors, +and release reviewers. Use it to confirm that the branch still matches the +current wasm-consensus product contract. + +## Consensus-safe scope + +Consensus-safe release scope remains: + +- `wasm-node` +- `wasm-browser` +- canonical `wasm32` release artifacts + +Release-critical parity is exact across those executors for: + +- value or error, +- gas used and gas remaining, +- host-call tape, +- first-success / last-failure OOG boundary. + +## Diagnostic-only scope + +The following remain outside the current consensus release gate: + +- native harness parity, +- WebKit browser runs, +- other Wasm variants or debug builds used for investigation. + +These surfaces are still useful for debugging and reconciliation, but they +should not be presented as consensus executors. + +## Pins and shipped contracts + +The release story at HEAD should be internally consistent across docs, runtime +checks, and generated evidence: + +- execution profiles: + - `baseline-v1` + - `compat-general-v1` + - `compat-binary-v1` +- builder/runtime artifact contract: + - `ProgramArtifact.v2` + - `ModulePack.v1` +- explicit pins: + - `engineBuildHash` + - `gasVersion` + - ABI manifest hash + +## What a reviewer should verify + +1. Consensus mismatch counts are zero. +2. Workload certification mismatch counts are zero. +3. OOG boundary parity is exact for the release corpus. +4. Consumer-proof tarball and Verdaccio rehearsals still pass. +5. Docs still describe the same scope that the generated evidence proves. + +## Quick verification commands + +```bash +source tools/emsdk/emsdk_env.sh +pnpm nx test smoke-node +pnpm nx run smoke-web:e2e +pnpm nx test ecosystem-certifier +pnpm nx run ecosystem-certifier:e2e +node tools/consensus-parity/scripts/archive-consensus-reproducibility-report.mjs --out-dir artifacts/reproducibility-consensus +node apps/ecosystem-certifier/scripts/archive-workload-certification-report.mjs --out-dir artifacts/workload-certification +pnpm release-evidence:synthesize -- --out-dir artifacts/release-evidence +pnpm release-evidence:verify -- --evidence-dir artifacts/release-evidence +``` + +## Known limitations at HEAD + +- Consensus-safe execution is wasm-only; native remains diagnostic-only. +- Runtime network/fetch/import behavior is intentionally excluded from the + consensus surface. +- Live binary and Promise support are profile-gated and should not be assumed in + `baseline-v1`. + +## Where to continue + +- Product overview: [`README.md`](../README.md) +- Documentation hub: [`README.md`](./README.md) +- Architecture overview: [`architecture-overview.md`](./architecture-overview.md) +- Examples corpus: [`../examples/README.md`](../examples/README.md) +- Release readiness summary: [`release-readiness-report.md`](./release-readiness-report.md) +- Workload certification: [`workload-certification.md`](./workload-certification.md) +- Ecosystem compatibility: [`ecosystem-compatibility-report.md`](./ecosystem-compatibility-report.md) +- Consensus vs diagnostic scope: [`consensus-safe-vs-diagnostic-only.md`](./consensus-safe-vs-diagnostic-only.md) diff --git a/docs/host-call-abi.md b/docs/host-call-abi.md index 76d1980..3ad6063 100644 --- a/docs/host-call-abi.md +++ b/docs/host-call-abi.md @@ -2,13 +2,13 @@ Baseline anchor: see `docs/baseline-2.md`. -Scope: describe the single-dispatcher syscall (`host_call`) and generated `Host.v1` surface per Baseline #2 (e.g., §1.5, §2, §6.4, §9). +Scope: describe the single-dispatcher syscall (`host_call`) and generated `Host.v*` surface (`Host.v1`, `Host.v2`) per Baseline #2 (e.g., §1.5, §2, §6.4, §9). ## Goals - Define the Wasm import shape for `host_call` and the memory ownership contract. - Describe request/response bytes (DV), limits, and deterministic error handling. -- Explain how this import underpins the generated `Host.v1` surface and ergonomic globals. +- Explain how this import underpins generated `Host.v*` surfaces and ergonomic globals. ## Wasm import surface (T-037) diff --git a/docs/implementation-plan.md b/docs/implementation-plan.md deleted file mode 100644 index 90437fe..0000000 --- a/docs/implementation-plan.md +++ /dev/null @@ -1,1949 +0,0 @@ -# Deterministic QuickJS-in-Wasm Evaluator (Nx Monorepo) — Implementation Plan (Baseline #1 + #2 Compliant) - -This file is the “source of truth” execution plan for Codex (Cursor IDE) to implement a deterministic QuickJS-in-Wasm **JS evaluator** with: - -- **Canonical gas metering inside QuickJS** (Baseline #1), -- A **manifest-locked, numeric-ID, single-dispatcher host ABI** (Baseline #2), -- A **read-only Blue-style JS context** (`document()`, `event`, `eventCanonical`, `steps`, `currentContract`, `currentContractCanonical`, `canon`) intended to be embedded by Blue’s external `document-processor`. - -Baseline anchors: - -- Baseline #1: `docs/baseline-1.md` -- Baseline #2: `docs/baseline-2.md` - -This repo intentionally does **not** implement document overlay/commit logic. That remains the responsibility of `document-processor`. -However, Baseline #2 still applies: even read-only `document(path)` is a host capability and must be exposed through the syscall/manifest/DV model. - ---- - -## Overview (end state) - -- **Nx monorepo** (TypeScript-first) using **pnpm**, with consistent tooling (lint/format/test/build) and CI. -- **QuickJS fork** lives as a **git submodule** at `vendor/quickjs` (pinned commit). All determinism + gas + host ABI changes live in that fork. -- **Deterministic execution profile** is enforced in the VM init: time/random/async/network/fs/locale are removed or stubbed; typed arrays / ArrayBuffer / WebAssembly are disabled; dangerous features like `eval`/`Function` are disabled (Baseline #1 §1B–§1C, §3). -- **Canonical gas** is implemented inside QuickJS: opcode metering, metered C builtins, allocation charges, deterministic GC checkpoints (Baseline #1 §2B). -- **Single syscall ABI (`host_call`)** for all host capabilities: `fn_id + request_bytes -> response_bytes`, with **manifest mapping**, **manifest hash validation**, and **DV canonical encoding** (Baseline #2 §1.1–§1.4, §2). -- VM exposes a frozen **`Host.v1`** namespace generated from the manifest, and provides ergonomic globals: - `document(path)`, `document.canonical(path)`, `event`, `eventCanonical`, `steps`, `currentContract`, `currentContractCanonical`, `canon.unwrap`, `canon.at` (Baseline #2 §1.5, §6.4, §9). -- **Host implementation is provided by the embedder** (e.g., `document-processor`) via a JS-side dispatcher used to implement `host_call`. No overlay/commit logic exists here. -- **Emscripten build pipeline** produces deterministic Wasm with fixed memory sizing (Baseline #1 §2C) in `libs/quickjs-wasm-build`, packaged in `libs/quickjs-wasm`. -- **SDK** in `libs/quickjs-runtime` loads the same Wasm bytes in Node and browsers, initializes `(P, I, G)`, wires host dispatch, evaluates JS deterministically, and returns DV output + gas used + optional tape. -- **Test harness** verifies determinism and exact OOG point across Node and browser (Playwright), plus DV/manifest parity tests and host-call gas accounting. - ---- - -## Proposed repository layout - -```text -/ - vendor/ - quickjs/ # git submodule: your fork - libs/ - dv/ # DV types + canonical encode/decode + validation - abi-manifest/ # ABI manifest schema + canonicalization + hashing - quickjs-wasm-build/ # Emscripten build pipeline (Nx executor/targets) - quickjs-wasm/ # Published artifacts: wasm bytes + loader + metadata - quickjs-runtime/ # SDK: instantiate, init (P,I,G), evaluate, return DV+gas+tape - test-harness/ # Fixtures + golden tests + cross-env runners - apps/ - smoke-node/ # minimal CLI runner (dev + debugging) - smoke-web/ # minimal browser runner (dev + determinism checks) - tools/ - quickjs-native-harness/ # native harness sources for fast VM iteration (non-wasm) - nx-executors/ # custom executors (optional), build helpers - scripts/ # toolchain setup (emsdk), checks - docs/ - determinism-profile.md - gas-schedule.md - dv-wire-format.md - abi-manifest.md - host-call-abi.md - implementation-plan.md # (this file) -``` - ---- - -## Key integration boundary with `document-processor` - -This repo exports a deterministic evaluator. The external embedder (`document-processor`) is responsible for: - -- workflow orchestration (step sequencing), -- document overlay/commit/rollback logic, -- providing the **deterministic host-call implementation** for: - - `Host.v1.document.get(path)` - - `Host.v1.document.getCanonical(path)` - -- transforming the evaluator’s returned DV value into downstream workflow outputs / updates. - -This repo ensures: - -- host calls are made through Baseline #2’s syscall layer, -- gas is charged deterministically for host calls (size + units), -- no hidden channels exist in the VM-provided API. - ---- - -# Current repo snapshot (kickoff) - -- Nx 22.2 workspace scaffold exists with pnpm (`nx.json`, `tsconfig.base.json`, `package.json`, `pnpm-workspace.yaml`). -- Publishable libs are scaffolded (`dv`, `abi-manifest`, `quickjs-wasm`, `quickjs-runtime`), with internal libs (`quickjs-wasm-build`, `test-harness`) plus smoke apps (`smoke-node`, `smoke-web`) and placeholder src/tests passing build/test targets. -- Lint/format configs and root scripts are in place; `README.md` still contains the Nx placeholder. -- Docs folder currently only has this plan; toolchain/docs stubs are missing. - ---- - -# Phase P0 — Monorepo bootstrap and standards - -### T-000: Initialize Nx workspace with pnpm - -**Phase:** P0 – Monorepo bootstrap and standards -**Status:** DONE -**Depends on:** None - -**Goal:** -Create the Nx monorepo scaffold with pnpm workspaces, consistent TypeScript configuration, and a baseline build/test story. - -**Current state:** Nx workspace files configured (`nx.json`, `tsconfig.base.json`, `package.json`, `pnpm-workspace.yaml` with apps/libs/tools), engines policy + scripts added, .nvmrc pinned to Node 20.17.0; baseline Nx commands verified. - -**Detailed tasks:** - -- [x] Initialize Nx workspace (integrated monorepo style) with TypeScript support. -- [x] Configure pnpm workspace (`pnpm-workspace.yaml`) and root `package.json` scripts. -- [x] Add Node engine version policy (`.nvmrc` and `package.json#engines`). -- [x] Add base `tsconfig.base.json` and workspace path aliases strategy. -- [x] Verify `pnpm nx graph` runs. - -**Implementation hints (for Codex):** - -- Root-level files: `nx.json`, `tsconfig.base.json`, `package.json`, `pnpm-workspace.yaml`. -- Use Nx plugins appropriate for TS libs and Node/browser apps. - -**Acceptance criteria:** - -- [x] `pnpm install` succeeds. -- [x] `pnpm nx graph` runs without errors. -- [x] `pnpm nx run-many -t test` runs (even if no projects exist yet). - ---- - -### T-001: Establish repo-wide lint/format conventions - -**Phase:** P0 – Monorepo bootstrap and standards -**Status:** DONE -**Depends on:** T-000 - -**Goal:** -Standardize formatting and linting so Codex can make consistent changes across the repo. - -**Current state:** -Repo-wide Prettier config/ignore, ESLint base ignores, `.editorconfig`, and root `pnpm lint` (with Prettier enforced via ESLint) are in place and passing. Format script removed; use `pnpm lint --fix` for formatting. - -**Detailed tasks:** - -- [x] Add Prettier config and ignore files. -- [x] Add ESLint config for TypeScript projects. -- [x] Configure Nx lint targets for libs and apps. -- [x] Add `.editorconfig`, `.gitignore`. -- [x] Add root scripts: `pnpm lint` (formatting via `pnpm lint --fix`). - -**Implementation hints (for Codex):** - -- Keep rules pragmatic; avoid style churn. -- Ensure configs work for ESM-first TS. - -**Acceptance criteria:** - -- [x] `pnpm lint` runs successfully. - ---- - -### T-002: Create initial libs/apps skeletons (empty but buildable) - -**Phase:** P0 – Monorepo bootstrap and standards -**Status:** DONE -**Depends on:** T-001 - -**Goal:** -Create Nx projects for all major libs and smoke apps so later tickets can wire functionality incrementally. - -**Current state:** -All publishable libs and smoke apps scaffolded with placeholder src/test and working build/test targets (`nx run-many -t build|test` passing). - -**Detailed tasks:** - -- [x] Create publishable library projects under `libs/`: - - [x] `dv` - - [x] `abi-manifest` - - [x] `quickjs-wasm-build` - - [x] `quickjs-wasm` - - [x] `quickjs-runtime` - - [x] `test-harness` - -- [x] Create apps under `apps/`: `smoke-node`, `smoke-web`. -- [x] Ensure each project has `project.json` `src/index.ts`, and a trivial test. - -**Acceptance criteria:** - -- [x] `pnpm nx run-many -t build` succeeds. -- [x] `pnpm nx run-many -t test` succeeds. - ---- - -### T-003: Add QuickJS fork as git submodule at `vendor/quickjs` - -**Phase:** P0 – Monorepo bootstrap and standards -**Status:** DONE -**Depends on:** T-000 - -**Goal:** -Bring your QuickJS fork into the monorepo as a pinned submodule under `vendor/quickjs`. - -**Current state:** -QuickJS submodule added at `vendor/quickjs` pointing to `git@blue.github.com:mjwebblue/quickjs.git`; vendor README documents pin/update workflow and root README notes fork ownership/init steps. - -**Detailed tasks:** - -- [x] Add the git submodule under `vendor/quickjs`. -- [x] Add `vendor/README.md` documenting submodule update workflow and pinning rules. -- [x] Add a root README snippet explaining fork ownership and update process. - -**Implementation hints (for Codex):** - -- Keep QuickJS modifications inside the submodule. -- Ensure Nx ignores `vendor/quickjs` as a project. - -**Acceptance criteria:** - -- [x] Fresh clone + `git submodule update --init --recursive` populates `vendor/quickjs`. -- [x] `vendor/quickjs` contains expected QuickJS sources. - ---- - -### T-004: Pin Emscripten toolchain (local + CI) - -**Phase:** P0 – Monorepo bootstrap and standards -**Status:** DONE -**Depends on:** T-000 - -**Goal:** -Pin emsdk/emcc version and provide repeatable setup. - -**Current state:** -Pinned emsdk version `3.1.56` recorded in `tools/scripts/emsdk-version.txt`; idempotent setup script installs/activates into `tools/emsdk`; `docs/toolchain.md` documents setup, env sourcing, and CI cache guidance. - -**Detailed tasks:** - -- [x] Record pinned emsdk version in `tools/scripts/emsdk-version.txt`. -- [x] Add setup docs + scripts to install/activate pinned emsdk. -- [x] Add CI notes for caching emsdk directory. -- [x] Create `docs/toolchain.md`. - -**Implementation hints (for Codex):** - -- Scripts should be idempotent. -- Avoid relying on system emcc. - -**Acceptance criteria:** - -- [x] `emcc --version` matches pinned version after setup. -- [x] `docs/toolchain.md` is sufficient for a clean machine setup. - ---- - -### T-005: Add docs scaffolding for determinism/gas/DV/ABI - -**Phase:** P0 – Monorepo bootstrap and standards -**Status:** DONE -**Depends on:** T-001 - -**Goal:** -Create documentation placeholders aligned to Baseline #1 and #2. - -**Current state:** -Doc stubs added: `docs/determinism-profile.md`, `docs/gas-schedule.md`, `docs/dv-wire-format.md`, `docs/abi-manifest.md`, `docs/host-call-abi.md`, plus README links. Each file lists scope, Baseline references, and TODOs for future detail. - -**Detailed tasks:** - -- [x] Create `docs/determinism-profile.md`. -- [x] Create `docs/gas-schedule.md`. -- [x] Create `docs/dv-wire-format.md`. -- [x] Create `docs/abi-manifest.md`. -- [x] Create `docs/host-call-abi.md`. -- [x] Link docs from root `README.md`. - -**Implementation hints (for Codex):** - -- Keep docs short initially; later tickets fill details. -- Each doc should reference relevant Baseline sections. - -**Acceptance criteria:** - -- [x] Docs exist and are linked. -- [x] Each doc cites Baseline #1/#2 sections. - ---- - -# Phase P1 — QuickJS native harness and deterministic capability profile - -### T-010: Create a minimal native (non-Wasm) harness for the QuickJS fork - -**Phase:** P1 – QuickJS harness and deterministic capability profile -**Status:** DONE -**Depends on:** T-003, T-002 - -**Goal:** -Enable fast iteration on QuickJS changes by compiling and running the fork natively, with deterministic init and stable output capture. - -**Current state:** -`tools/quickjs-native-harness` added as an Nx project. Build compiles `vendor/quickjs` sources plus a small harness binary that evaluates `--eval ""` and prints `RESULT ` or `ERROR `. Tests spawn the binary and assert deterministic output. Runtime init currently uses QuickJS defaults; swap to the fork’s deterministic init once available. - -**Detailed tasks:** - -- [x] Add C harness under `tools/quickjs-native-harness/` that can: - - [x] create runtime/context using the deterministic init entrypoint, - - [x] evaluate a provided JS source string, - - [x] return stable JSON-like output (DV bytes or a stable text format) and stable error codes. - -- [x] Add Nx targets to build and run harness tests. -- [x] Add a minimal smoke test script. - -**Implementation hints (for Codex):** - -- Do not use QuickJS `qjs` shell; write your own harness to control init. -- Output must not include nondeterministic stack traces. - -**Acceptance criteria:** - -- [x] `pnpm nx build quickjs-native-harness` produces a runnable binary. -- [x] `pnpm nx test quickjs-native-harness` runs at least one deterministic test. - ---- - -### T-011: Implement deterministic VM init hook in QuickJS fork - -**Phase:** P1 – QuickJS harness and deterministic capability profile -**Status:** DONE -**Depends on:** T-010, T-005 - -**Goal:** -Centralize deterministic runtime/context initialization so native and wasm use the same profile. - -**Baseline references:** Baseline #1 §1B, §3; Baseline #2 §6.1, §6.3 - -**Detailed tasks:** - -- [x] Add a single “deterministic init” function in the fork that: - - [x] creates runtime/context, - - [x] installs minimal safe builtins, - - [x] removes or stubs forbidden capabilities deterministically, - - [x] prepares placeholders for `Host` namespace (to be installed from manifest later). - -- [x] Ensure harness uses this init. - -**Current state (P1 T-011):** - -- Added `JS_NewDeterministicRuntime(JSRuntime **, JSContext **)` in the fork (`quickjs.c`/`quickjs.h`): - - Initializes a context with base objects + JSON + Map/Set only; no Date/Proxy/RegExp/typed arrays/Promise/WeakRef/etc. yet. - - Stubs `eval` and `Function` with deterministic `TypeError` messages and clears `ctx->eval_internal`. - - Installs a null-prototype `Host.v1` placeholder on the global object with non-configurable/non-writable descriptor (to be populated later from manifest). -- Native harness now uses this initializer and tests assert the disabled `eval`/`Function` behavior and `Host` descriptor shape. - -**Implementation hints (for Codex):** - -- Favor removing globals or replacing them with deterministic stubs that throw stable errors. -- Use null-prototype objects where applicable. - -**Acceptance criteria:** - -- [x] A test asserts forbidden globals are absent/stubbed. -- [x] Global descriptors for injected names are stable across runs. - ---- - -### T-012: Disable time, randomness, timers, and locale channels - -**Phase:** P1 – QuickJS harness and deterministic capability profile -**Status:** DONE -**Depends on:** T-011 - -**Goal:** -Remove nondeterminism sources: time/randomness/timers/locale. - -**Baseline references:** Baseline #1 §1B–§1C; Baseline #2 §0.3 - -**Detailed tasks:** - -- [x] Disable/stub: `Date`, timing APIs, timers. -- [x] Disable/stub `Math.random` (or remove entirely). -- [x] Ensure no locale-dependent APIs are exposed. -- [x] Add tests proving stable behavior. - -**Implementation hints (for Codex):** - -- Decide “missing” vs “throws deterministic error” per API and document. - -**Acceptance criteria:** - -- [x] Capability tests pass and show no time/random/locale leaks. - -**Current state (P1 T-012):** - -- Deterministic init seeds `random_state = 1` and replaces `Math.random` with a throwing stub (`TypeError: Math.random is disabled in deterministic mode`). -- `Date` and timers (`setTimeout`) remain absent in the deterministic context; harness tests assert they are `undefined`. -- Added native harness tests covering the disabled random, missing Date/timers; all harness tests pass. - ---- - -### T-013: Disable async/Promises/job queue - -**Phase:** P1 – QuickJS harness and deterministic capability profile -**Status:** DONE -**Depends on:** T-011 - -**Goal:** -Enforce no async behavior and no hidden scheduling. - -**Baseline references:** Baseline #1 §1B; Baseline #2 §4.4 - -**Detailed tasks:** - -- [x] Remove/disable Promise, async functions, microtask processing. -- [x] Ensure VM doesn’t run jobs implicitly after evaluation. -- [x] Add tests verifying `Promise` absent and no microtasks run. - -**Acceptance criteria:** - -- [x] Async features are unavailable or deterministically rejected. - -**Current state (P1 T-013):** - -- Deterministic init overwrites the global `Promise` with a throwing stub (`TypeError: Promise is disabled in deterministic mode`) and keeps the runtime job queue unused. -- Async functions compile but throw when invoked because they rely on the disabled `Promise`. -- Harness tests assert `Promise` throws, async invocation errors, and `queueMicrotask` is absent; all pass. - ---- - -### T-014: Disable eval/Function, RegExp, Proxy - -**Phase:** P1 – QuickJS harness and deterministic capability profile -**Status:** DONE -**Depends on:** T-011 - -**Goal:** -Remove high-risk features excluded by Baseline #1 until explicitly supported/metered. - -**Baseline references:** Baseline #1 §3 - -**Detailed tasks:** - -- [x] Disable/stub `eval` and `Function`. -- [x] Disable/stub `RegExp`. -- [x] Disable/stub `Proxy`. -- [x] Add deterministic failure tests. - -**Acceptance criteria:** - -- [x] Scripts attempting these features fail deterministically. - -**Current state (P1 T-014):** - -- Deterministic init continues to stub `eval`/`Function` and now replaces `RegExp` and `Proxy` globals with deterministic TypeError stubs. -- `ctx->regexp_ctor` and `compile_regexp` point at the disabled stub, so both `new RegExp()` and regex literals throw `TypeError: RegExp is disabled in deterministic mode`. -- Native harness tests cover the RegExp constructor, RegExp literals, and Proxy construction and assert deterministic failures. - ---- - -### T-015: Disable typed arrays / ArrayBuffer / DataView / WebAssembly exposure - -**Phase:** P1 – QuickJS harness and deterministic capability profile -**Status:** DONE -**Depends on:** T-011 - -**Goal:** -Prevent float/NaN payload observability and low-level channels. - -**Baseline references:** Baseline #1 §1B, §3 - -**Detailed tasks:** - -- [x] Disable/stub ArrayBuffer, DataView, typed arrays, WebAssembly. -- [x] Add tests confirming they are unreachable. - -**Acceptance criteria:** - -- [x] These globals are absent/stubbed deterministically. - -**Current state (P1 T-015):** - -- Deterministic init installs TypeError stubs for `ArrayBuffer`, `SharedArrayBuffer`, `DataView`, all typed array constructors, `Atomics`, and `WebAssembly` so attempts to construct or call them fail with deterministic error strings. -- Native harness tests assert deterministic failures for `ArrayBuffer`, `SharedArrayBuffer`, `DataView`, `Uint8Array`, `Atomics`, and `WebAssembly`. - ---- - -### T-016: Disable console/print; provide deterministic logging path placeholder - -**Phase:** P1 – QuickJS harness and deterministic capability profile -**Status:** DONE -**Depends on:** T-011 - -**Goal:** -Prevent nondeterministic host logging. Logging (if any) must be via deterministic host ABI (Baseline #2 §5). - -**Baseline references:** Baseline #2 §5 - -**Detailed tasks:** - -- [x] Remove/stub `print`/`console` (if present in your embed) or ensure they do nothing deterministically. -- [x] Document recommended deterministic logging mechanism: `Host.v1.emit(...)` (implemented later). -- [x] Add tests that logging does not escape to host console. - -**Acceptance criteria:** - -- [x] No console output occurs from VM execution in harness tests. - -**Current state (P1 T-016):** - -- Deterministic init installs a null-prototype `console` with common methods (`log`, `info`, `warn`, `error`, `debug`) all mapped to deterministic `TypeError: console is disabled in deterministic mode`; global `print` is similarly stubbed. -- Native harness tests assert console/print calls throw deterministically (no host output); future logging should go through `Host.v1.emit(...)` once implemented. - ---- - -### T-017: Capability profile conformance test suite - -**Phase:** P1 – QuickJS harness and deterministic capability profile -**Status:** DONE -**Depends on:** T-012, T-013, T-014, T-015, T-016 - -**Goal:** -Lock down the deterministic profile with regression tests. - -**Detailed tasks:** - -- [ ] Add a suite of scripts checking: - - [x] forbidden globals are missing/stubbed, - - [x] key injected globals are immutable, - - [x] global property enumeration is stable for injected names. - -- [x] Add golden/snapshot outputs. - -**Acceptance criteria:** - -- [x] Running the suite twice yields identical outputs. - -**Current state (P1 T-017):** - -- Added a capability snapshot assertion in the native harness that records deterministic outcomes for all disabled globals, confirms `Host`/`Host.v1` immutability/non-extensibility, and checks global property ordering for injected names; compared against a golden JSON output. -- QuickJS deterministic init now prevents extensions on the `Host` namespaces to keep them immutable; harness suite passes deterministically. - ---- - -# Phase P2 — Canonical gas metering inside QuickJS fork - -### T-020: Add gas state to runtime/context - -**Phase:** P2 – Canonical gas metering inside QuickJS fork -**Status:** DONE -**Depends on:** T-010 - -**Goal:** -Introduce canonical gas state and deterministic OOG errors. - -**Baseline references:** Baseline #1 §2B - -**Detailed tasks:** - -- [x] Add gas fields: gas remaining, gas limit, schedule/version id. -- [x] Add charge/check helpers. -- [x] Define deterministic OOG error tag/code distinct from HostError. - -**Acceptance criteria:** - -- [x] Harness can trigger OOG deterministically by setting a low gas limit. - -**Current state (P2 T-020):** - -- `JSContext` now carries `gas_limit`, `gas_remaining`, and `gas_version` (default `JS_GAS_VERSION_LATEST`), initialized to `JS_GAS_UNLIMITED`. -- Public helpers added: `JS_SetGasLimit`, `JS_GetGasLimit/Remaining`, `JS_GetGasVersion`, and `JS_UseGas` to precharge/charge and throw deterministic uncatchable `OutOfGas` (`code: "OOG"`, message `out of gas`). -- Native harness accepts `--gas-limit` and tests assert the deterministic OOG error path. - ---- - -### T-021: Implement opcode/bytecode metering in interpreter loop - -**Phase:** P2 – Canonical gas metering inside QuickJS fork -**Status:** DONE -**Depends on:** T-020 - -**Goal:** -Charge gas per executed opcode using a versioned cost table. - -**Baseline references:** Baseline #1 §2B.1 - -**Detailed tasks:** - -- [x] Insert gas charge at opcode dispatch (charge-before-execute). -- [x] Define explicit opcode cost table in one file. -- [x] Add tests asserting exact gas used for small programs. - -**Acceptance criteria:** - -- [x] Gas usage is stable across repeated runs. - -**Current state (P2 T-021):** - -- Added per-opcode gas table (flat cost = 1 for now) in `quickjs.c` and charge-before-execute metering in the interpreter loop; direct-dispatch reworked to pass through the loop each opcode so gas is always charged. -- Harness exposes `--report-gas` and verifies deterministic gas usage for constant and addition scripts plus OOG boundaries. - ---- - -### T-022: Define deterministic OOG boundary semantics - -**Phase:** P2 – Canonical gas metering inside QuickJS fork -**Status:** DONE -**Depends on:** T-021 - -**Goal:** -Ensure exact out-of-gas point is stable across environments. - -**Baseline references:** Baseline #1 §2 - -**Detailed tasks:** - -- [x] Specify and implement OOG boundaries: opcode precharge, builtin loop checks, host-call boundaries (later). -- [x] Add tests that hit OOG at a known boundary and assert last successful observable state. - -**Acceptance criteria:** - -- [x] OOG boundary tests pass deterministically. - -**Current state (P2 T-022):** - -- OOG is thrown on opcode precharge before any instruction executes; the exception is uncatchable and zeros remaining gas. -- Native harness can snapshot a global property via `--dump-global` to observe progress even when execution OOGs. -- Tests cover zero-gas precharge (no progress, `STATE undefined`) and a loop boundary where OOG after the third increment reports deterministic state (`used=54`, `STATE 3`). - ---- - -### T-023: Meter C-builtins that loop in C (Array.map/filter/reduce) - -**Phase:** P2 – Canonical gas metering inside QuickJS fork -**Status:** DONE -**Depends on:** T-021 - -**Goal:** -Prevent cheap bytecode / expensive builtin loops. - -**Baseline references:** Baseline #1 §2B.2 - -**Detailed tasks:** - -- [x] Add base + per-element charges + OOG checks in map/filter/reduce. -- [x] Add tests verifying linear scaling and deterministic OOG index. - -**Acceptance criteria:** - -- [x] OOG occurs at the same element index for a fixed gas budget. - -**Current state (P2 T-023):** - -- Array/TypedArray map/filter/every/some/forEach/reduce/reduceRight precharge `JS_GAS_ARRAY_CB_BASE=5` on entry plus `JS_GAS_ARRAY_CB_PER_ELEMENT=2` before each element hits property lookup or callback, throwing uncatchable OOG deterministically. -- Harness tests cover map scaling (1 element uses 28 gas vs 5 elements uses 64), and OOG boundaries that stop after the 4th element for map (limit 55), filter (limit 60), and reduce (limit 61) with `--dump-global` asserting the last processed index. - ---- - -### T-024: Audit and meter/disable other heavy builtins - -**Phase:** P2 – Canonical gas metering inside QuickJS fork -**Status:** DONE -**Depends on:** T-017, T-021 - -**Goal:** -Ensure no builtin performs unmetered large work. - -**Baseline references:** Baseline #1 §2B.2, §3 - -**Detailed tasks:** - -- [x] Inventory heavy builtins (e.g., sort, JSON parse/stringify, string ops). -- [x] For each: meter deterministically or disable in profile. -- [x] Update docs and tests accordingly. - -**Acceptance criteria:** - -- [x] At least 3 heavy builtin behaviors are covered by tests. - -**Current state (P2 T-024):** - -- Deterministic profile now replaces `JSON.parse`, `JSON.stringify`, and `Array.prototype.sort` with a disabled stub that throws `TypeError: is disabled in deterministic mode`, preventing unmetered O(n) / O(n log n) native work. -- Harness tests assert these three disabled behaviors to lock in the restriction. - ---- - -### T-025: Allocation gas via allocator hooks - -**Phase:** P2 – Canonical gas metering inside QuickJS fork -**Status:** DONE -**Depends on:** T-020 - -**Goal:** -Charge gas deterministically by requested allocation bytes. - -**Baseline references:** Baseline #1 §2B.3 - -**Detailed tasks:** - -- [x] Wrap allocator hooks; charge `base + bytes*k`. -- [x] Define realloc charging rule and document it. -- [x] Add tests for predictable allocations. - -**Acceptance criteria:** - -- [x] Allocation-heavy scripts consume deterministic gas and can OOG deterministically. - -**Current state (P2 T-025):** - -- Allocation metering adds `JS_GAS_ALLOC_BASE=3` plus `ceil(bytes / 16)` via a helper and charges through context-aware allocators (`js_malloc`/`js_mallocz`/`js_realloc`/`js_realloc2`) and string allocations using the actual struct + buffer size; charges are skipped for unlimited gas or during uncatchable/OOG handling. -- Realloc charges on the requested size (not delta), string allocator meters before hitting the runtime allocator, and runtime-level allocators remain unmetered to avoid bootstrap recursion; runtime shutdown follows upstream GC sequencing (no extra final sweep added). -- `JS_ThrowOutOfGas` now guards against recursive throws while building the error. -- Harness now asserts allocation gas deterministically: a 32 KiB repeat consumes 2,391 gas with 5,000 limit and OOGs at 2,000; array map expectations updated to reflect the new allocation charges. - ---- - -### T-026: Deterministic GC checkpoints and charging - -**Phase:** P2 – Canonical gas metering inside QuickJS fork -**Status:** DONE -**Depends on:** T-025 - -**Goal:** -Run GC only at deterministic checkpoints; charge deterministically. - -**Baseline references:** Baseline #1 §2B.3 - -**Detailed tasks:** - -- [x] Disable/neutralize heuristic auto-GC triggers. -- [x] Add explicit GC checkpoints at controlled points (init/eval/end; host-call checkpoints to be wired when host ABI lands). -- [x] Define deterministic GC gas rule (GC free; cost amortized in allocation gas) and test it. - -**Acceptance criteria:** - -- [x] GC occurs only at checkpoints; charges match tests. -- [x] GC charging rule is documented (free; cost amortized in allocation gas) and validated by harness baselines. - -**Current state (P2 T-026):** - -- Deterministic runtimes disable QuickJS’s heuristic GC triggers and set the upstream threshold to `-1`; `js_trigger_gc` is a no-op under deterministic mode so allocator heuristics never fire. -- A deterministic allocator-side counter tracks requested allocation bytes; crossing a fixed threshold (512 KiB) sets a `det_gc_pending` flag. GC is still free (cost covered by T-025 allocation gas) and only runs via `JS_RunGCCheckpoint(JSContext *)`, which clears the flag/counter. -- The native harness calls the checkpoint at deterministic points (post-init, pre/post eval), so GC runs only at checkpoints and only if `det_gc_pending` is set; gas baselines were updated accordingly. - ---- - -### T-027: Optional gas trace facility - -**Phase:** P2 – Canonical gas metering inside QuickJS fork -**Status:** DONE -**Depends on:** T-021 - -**Goal:** -Enable deterministic gas tracing for golden tests (aggregated counts). - -**Detailed tasks:** - -- [x] Add optional trace: opcode counts, builtin charges, allocation totals. -- [x] Provide a stable export path for harness tests. - -**Acceptance criteria:** - -- [x] Trace output is stable and snapshot-testable. - -**Current state (P2 T-027):** - -- QuickJS exposes an optional aggregate gas trace (enabled via `JS_EnableGasTrace`, read via `JS_ReadGasTrace`) covering total opcode count/gas, array-callback base/per-element counts/gas, and allocation count/bytes/gas; no per-opcode vectors are stored to keep the fork minimal. -- The native harness enables tracing with `--gas-trace` and prints a deterministic `TRACE {…}` object alongside results/errors; harness tests snapshot the aggregate trace for addition and array map fixtures. -- Follow-up fix: gas/trace snapshots are now taken before optional `--dump-global` reads, so `gas used` and `TRACE` stay aligned even when dumping globals performs extra allocations; array-map baselines updated accordingly. - ---- - -### T-028: Native gas golden tests - -**Phase:** P2 – Canonical gas metering inside QuickJS fork -**Status:** DONE -**Depends on:** T-022, T-023, T-025, T-026, T-027 - -**Goal:** -Lock in gas semantics before wasm and host ABI. - -**Detailed tasks:** - -- [x] Create representative scripts and expected gas numbers / OOG boundaries. -- [x] Add harness runner that asserts exact gas used and outcomes. - -**Acceptance criteria:** - -- [x] Golden suite passes with exact expected values. - -**Current state (P2 T-028):** - -- Added gas golden fixtures under `tools/quickjs-native-harness/fixtures/gas/` covering straight-line programs, OOG precharge boundaries, loop OOG checkpoints, array callback C-builtins (map/filter/reduce success + OOG), heavy allocation + GC-pending trigger, and string repeat allocation edges; each fixture is referenced by name in `scripts/gas-goldens.json` with expected `GAS`/`STATE`/`TRACE` output. -- Introduced `tools/quickjs-native-harness/scripts/gas-goldens.mjs`, a Node runner that loads the JSON manifest, executes the native harness per case, and asserts exact stdout against the golden strings; the runner is invoked from the harness `test.sh` alongside the capability profile assertions. -- Suite is passing with deterministic outputs, locking in opcode gas, allocation gas, GC checkpoint behavior, and aggregate gas traces ahead of the wasm/host ABI work. - ---- - -# Phase P2.5 — Early QuickJS-in-Wasm gas harness - -### T-029: Early QuickJS-in-Wasm gas harness (no host ABI) - -**Phase:** P2.5 – Early QuickJS-in-Wasm gas harness -**Status:** DONE -**Depends on:** T-022, T-004, T-003, T-002 - -**Goal:** -Produce a minimal Emscripten-built QuickJS-in-Wasm binary that exposes the canonical gas metering (P2) and validate that native vs Wasm have identical results and OOG boundaries for representative scripts, before introducing the host ABI. - -**Baseline references:** Baseline #1 §1A–§2B - -**Detailed tasks (split into smaller subtasks):** - -- [x] **Subtask A – Minimal `quickjs-wasm-build` Nx target** - - [x] Add or wire up a `quickjs-wasm-build` Nx project (reusing the existing empty one if present) that compiles the current deterministic QuickJS fork with gas metering to Wasm using the pinned emsdk. - - [x] Expose a simple C entrypoint equivalent to the native harness: `eval(code, gas_limit) -> { result, gas_used | OOG }`. - - [x] Emit the `.wasm` artifact (plus minimal JS glue if needed) into a stable, deterministic `dist/` location that downstream tests can consume. - -- [x] **Subtask B – Node gas-equivalence harness** - - [x] Add a tiny TS harness in `libs/test-harness` that loads the Wasm in Node. - - [x] Run a fixed set of gas-focused scripts (straight-line code, small loops, OOG boundary), ideally reusing the existing gas fixtures where possible. - - [x] Compare `result`, `error code/tag`, and `gas_used` from the Wasm harness against the native harness, failing tests on any mismatch. - - [x] Wire this into `pnpm nx test` (or an equivalent script) so it runs in CI. - -- [x] **Subtask C – Browser gas smoke page** - - [x] Add a basic browser smoke page (or reuse `apps/smoke-web`) that loads the same `.wasm` bytes as the Node harness. - - [x] Run the same gas fixtures in the browser (no host ABI calls). - - [x] Surface a simple report (e.g., list of cases with OK/FAIL) and log mismatches to the console for debugging. - -- [x] **Subtask D – Document temporary limitations** - - [x] Document any temporary limitations of this early harness (e.g., no host ABI, no manifest, rough memory sizing, any non-final Emscripten flags) so that P4 can harden the build later without changing P2 gas semantics. - - [x] Clearly call out which aspects (e.g., gas schedule, OOG boundaries) are treated as stable contracts versus which are explicitly “pre-P4” and allowed to evolve. - -**Acceptance criteria (per subtask):** - -- [x] **Subtask A:** `pnpm nx build quickjs-wasm-build` produces a runnable `.wasm` artifact that exposes `eval(code, gas_limit) -> { result, gas_used | OOG }` and is written to a stable `dist/` path. -- [x] **Subtask B:** A `pnpm nx test` (or equivalent script) runs the gas fixtures in Node against the wasm harness: wasm32 is the default baseline (stable outputs for result/kind/gas), and the wasm64 variant can still be compared to native for debugging. -- [x] **Subtask C:** A manual or automated browser run of the same fixtures shows identical outcomes to the Node run for the selected scripts/gas limits using the current wasm variant (wasm32 by default). -- [x] **Subtask D:** A short, checked-in document (or updated section of this plan) describes the temporary limitations and P4 hardening expectations without leaving ambiguity about what must remain stable. - -**Current state (P2.5 T-029 Subtask A):** - -- `pnpm nx build quickjs-wasm-build` now calls an emscripten build script (pinned 3.1.56) that compiles the deterministic QuickJS fork + a wasm harness to `libs/quickjs-wasm-build/dist/quickjs-eval{,-debug}.{js,wasm}` (alongside the TS outputs in the same folder, with optional memory64 variants when enabled). -- The harness exports deterministic ABI entrypoints (`qjs_det_init`/`qjs_det_eval`/`qjs_det_free` plus gas/tape/trace helpers), returning DV-hex payloads with `RESULT … GAS …` / `ERROR … GAS …` formatting and consuming the imported `host_call` dispatcher. -- The JS glue is an ES module (`QuickJSGasWasm` factory) with runtime methods exported for `cwrap`/`UTF8ToString`; artifact paths are surfaced via `getQuickjsWasmArtifacts(variant, buildType)` in `libs/quickjs-wasm-build`. - -**Current state (P2.5 T-029 Subtask B):** - -- The vitest spec at `libs/test-harness/src/lib/gas-equivalence.spec.ts` covers the full gas fixture set (`zero-precharge`, `gc-checkpoint-budget`, `loop-oog`, `constant`, `addition`, `string-repeat`) against the wasm harness using the wasm32 artifact by default, driving `qjs_det_init`/`qjs_det_eval` with the Host.v1 manifest/context and asserting DV payloads + gas remaining/used. Setting `QJS_WASM_VARIANT=wasm64` switches the test to the memory64 artifact and restores native-vs-wasm comparisons for debugging. -- The wasm build defaults to wasm32 with `-sWASM_BIGINT=1`; `libs/quickjs-wasm-build/scripts/build-wasm.sh` accepts `WASM_VARIANTS=wasm32,wasm64` to also emit `quickjs-eval-wasm64{,-debug}.{js,wasm}`, and `WASM_BUILD_TYPES=release,debug` to control whether debug builds are emitted. Harnesses use `getQuickjsWasmArtifacts(variant, buildType)` with `QJS_WASM_BUILD_TYPE` defaulting to `release`. -- **Compatibility note:** wasm32 gas numbers diverge from native because of the 32-bit allocator layout, but Node and browser harnesses now agree on the wasm32 outputs. wasm32 is the chosen canonical variant; wasm64 is not planned/supported (memory64 remains non-portable in mainstream browsers), so native-parity debugging should proceed within wasm32 expectations. - -**Current state (P2.5 T-029 Subtask C):** - -- `apps/smoke-web` now hosts a browser gas smoke page that loads the wasm harness directly, runs the core gas golden fixtures, and reports pass/fail (logging mismatches to the console). -- A Playwright smoke test (`apps/smoke-web/tests/gas-smoke.spec.ts`) with `apps/smoke-web/playwright.config.cts` starts the Vite dev server, runs the page, and asserts all fixtures pass using the wasm32 artifact; no browser flags are required for memory64. - -**Current state (P2.5 T-029 Subtask D):** - -- Temporary wasm-gas notes from the pre-ABI harness were folded into the toolchain/build docs; the legacy JSON harness was removed in favor of the deterministic ABI entrypoints, with wasm32 gas fixtures now pinned via the DV-based path. - ---- - -# Phase P3 — Baseline #2 host ABI: DV + manifest + single dispatcher + Host.v1 - -### T-030: Decide and document canonical DV wire encoding - -**Phase:** P3 – Host ABI (DV + manifest + syscall) -**Status:** DONE -**Depends on:** T-005 - -**Goal:** -Pick one canonical encoding for DV used for args/returns and (preferably) manifest bytes. - -**Baseline references:** Baseline #2 §2.7 - -**Detailed tasks:** - -- [x] Evaluate candidate formats (canonical CBOR, JCS, custom minimal binary). - -- [x] Choose one and fully specify it in `docs/dv-wire-format.md`: - - [x] type tags, lengths, UTF-8 handling, - - [x] numeric restrictions: finite, no NaN/Inf, no -0 (canonicalize), - - [x] object key uniqueness + canonical key ordering, - - [x] max sizes/depth. - -- [x] Add examples (at least 5) with expected encoded form described. - -**Acceptance criteria:** - -- [x] `docs/dv-wire-format.md` is normative and unambiguous. - -**Current state (P3 T-030):** - -- DV is pinned to a deterministic CBOR subset: definite lengths only, no tags/byte strings, and a JSON-like type set (null, boolean, number, UTF-8 string, array, map with string keys). -- `docs/dv-wire-format.md` now normatively captures type tags, numeric restrictions (finite, no NaN/Inf, `-0` canonicalized), CBOR key ordering, global limits (1 MiB encoded size, 64 depth, 65,535 entries/items, 256 KiB strings), and five hex-encoded examples. - ---- - -### T-031: Implement DV encode/decode in TypeScript (`libs/dv`) - -**Phase:** P3 – Host ABI (DV + manifest + syscall) -**Status:** DONE -**Depends on:** T-030, T-002 - -**Goal:** -Provide TS reference implementation for DV validation and canonical encode/decode. - -**Baseline references:** Baseline #2 §2.1–§2.7 - -**Detailed tasks:** - -- [x] Define DV TS types and runtime validators. -- [x] Implement canonical encode/decode per spec. -- [x] Enforce numeric/string/object rules and limits. -- [x] Add property-based tests for roundtrip and canonicalization. - -**Acceptance criteria:** - -- [x] `pnpm nx test dv` passes; includes non-canonical input tests. - -**Current state (P3 T-031):** - -- `libs/dv` now exports DV types, limits, validators, and canonical CBOR subset encode/decode with strict rejection of non-canonical encodings, invalid UTF-8, and out-of-range numbers; limits match `docs/dv-wire-format.md`. -- Property-based tests plus targeted fixtures cover canonical examples, forbidden encodings (float width/float64 integers, map key ordering/duplicates, MIN_SAFE_INTEGER–1), and UTF-8/surrogate handling; `pnpm nx test dv` and `pnpm nx typecheck dv` pass. - ---- - -### T-032: Implement VM-side DV encode/decode (QuickJS fork) - -**Phase:** P3 – Host ABI (DV + manifest + syscall) -**Status:** DONE -**Depends on:** T-030, T-010 - -**Goal:** -Implement C encode/decode for DV to bridge JS values and request/response bytes deterministically. - -**Baseline references:** Baseline #2 §2, §6.2 - -**Detailed tasks:** - -- [x] JS→DV conversion enforcing DV restrictions deterministically. -- [x] DV→JS conversion preserving canonical key insertion order. -- [x] Enforce limits. -- [x] Add harness tests that compare encoded bytes to TS reference fixtures. - -**Acceptance criteria:** - -- [x] Byte-level parity tests vs `libs/dv` pass for a shared fixture set. - -**Current state (P3 T-032):** - -- DV encode/decode lives outside `quickjs.c` in `vendor/quickjs/quickjs-dv.c` with public APIs `JS_EncodeDV`, `JS_DecodeDV`, `JS_FreeDVBuffer`, and default limits `JS_DV_LIMIT_DEFAULTS` exposed via `quickjs.h`. -- The C implementation mirrors the TS reference: canonical CBOR subset, safe integer enforcement, `-0` canonicalization, UTF-8 validation, canonical map key ordering, depth/size limits, and null-prototype object decoding. -- Native harness now supports `--dv-encode` (evaluate JS and emit DV hex) and `--dv-decode ` (decode DV bytes and emit JSON). `tools/quickjs-native-harness/scripts/dv-parity.mjs` compares harness DV bytes/decodes against the TS `encodeDv`/`decodeDv` fixtures (null/boolean/ints/floats/strings/arrays/maps/null-proto/nested/-0), and `test.sh` runs this parity check. - ---- - -### T-033: Define ABI manifest schema and canonical serialization - -**Phase:** P3 – Host ABI (DV + manifest + syscall) -**Status:** DONE -**Depends on:** T-030, T-005 - -**Goal:** -Define manifest schema, canonical bytes, and hashing rules. - -**Baseline references:** Baseline #2 §1.3–§1.4, §7 - -**Detailed tasks:** - -- [x] Write `docs/abi-manifest.md` specifying: - - [x] top-level fields (`abi_id`, `abi_version`, entries), - - [x] entry fields: `fn_id`, `js_path`, `arity`, `arg_schema`, `return_schema`, `effect`, `gas_schedule_id`, `limits`, `error_codes`, - - [x] canonical serialization rules (prefer DV encoding from T-030), - - [x] hash algorithm + output format. - -- [x] Define a minimal schema language sufficient for initial functions (don’t overbuild). - -**Acceptance criteria:** - -- [x] Doc includes a complete example manifest for `Host.v1` with at least document.get/getCanonical. - -**Current state (P3 T-033):** - -- `docs/abi-manifest.md` now normatively specifies the manifest structure (top-level and per-function fields), minimal schema language, canonical DV encoding rules, SHA-256 hashing (lowercase hex), and validation constraints. It includes a complete `Host.v1` example covering `document.get`, `document.getCanonical`, and `emit` with gas parameters, limits, and error codes. - ---- - -### T-034: Implement manifest tooling in TypeScript (`libs/abi-manifest`) - -**Phase:** P3 – Host ABI (DV + manifest + syscall) -**Status:** DONE -**Depends on:** T-031, T-033 - -**Goal:** -Provide TS tools to create canonical manifest bytes and compute `abi_manifest_hash` for inclusion in `P`. - -**Baseline references:** Baseline #2 §1.3 - -**Detailed tasks:** - -- [x] Implement manifest types + validators. -- [x] Implement canonical serialization to bytes. -- [x] Implement hashing function (same as VM). -- [x] Add tests asserting stable bytes and hash for a fixture manifest. - -**Acceptance criteria:** - -- [x] `pnpm nx test abi-manifest` passes with stable fixture hashes. - -**Current state (P3 T-034):** - -- `libs/abi-manifest` now exposes manifest types, strict validators (uint32 bounds, js_path collision/prefix detection, sorted fn_ids/error_codes, arg_utf8_max checks, DV size limits), canonical DV serialization, and SHA-256 hashing helpers (`hashAbiManifest`, `hashAbiManifestBytes`). -- Tests include the Host.v1 fixture manifest, pin its canonical bytes/hash, and negative coverage for unsorted functions, path conflicts, and invalid arg_utf8_max; `pnpm nx test abi-manifest` passes. - ---- - -### T-035: Define the initial ABI surface manifest (v1) used by this evaluator - -**Phase:** P3 – Host ABI (DV + manifest + syscall) -**Status:** DONE -**Depends on:** T-033 - -**Goal:** -Lock down the minimal host ABI surface required by the read-only evaluator. - -**Baseline references:** Baseline #2 §1.4, §9 - -**Detailed tasks:** - -- [x] Create a fixture manifest (checked into `libs/test-harness/fixtures/`) that defines: - - [x] `Host.v1.document.get(path)` (READ) - - [x] `Host.v1.document.getCanonical(path)` (READ) - - [x] Optional: `Host.v1.emit(value)` (EMIT) for deterministic logging/tape (recommended) - -- [x] Define per-function limits and error codes (path invalid, not found, limit exceeded). - -- [x] Define per-function gas schedule parameters (base, k_arg_bytes, k_out_bytes, k_units). - -**Acceptance criteria:** - -- [x] Fixture manifest can be serialized + hashed by `libs/abi-manifest` reproducibly. - -**Current state (P3 T-035):** - -- Added `Host.v1` manifest fixture at `libs/test-harness/fixtures/abi-manifest/host-v1.json` with `document.get`, `document.getCanonical`, and `emit`; canonical DV bytes and SHA-256 hash are pinned alongside in `.bytes.hex`/`.hash` with a TS loader exported from `@blue-quickjs/abi-manifest` (and re-exported by `@blue-quickjs/test-harness`). -- `libs/abi-manifest` tests now consume the fixture to assert canonical bytes/hash parity via `hashAbiManifest`/`hashAbiManifestBytes`, locking in the reproducible manifest encoding. - ---- - -### T-036: Implement VM-side manifest hash validation during initialization - -**Phase:** P3 – Host ABI (DV + manifest + syscall) -**Status:** DONE -**Depends on:** T-033, T-010 - -**Goal:** -VM receives manifest bytes at init, computes hash, and exact-matches `abi_manifest_hash` pinned in `P`. - -**Baseline references:** Baseline #2 §1.3 - -**Detailed tasks:** - -- [x] Implement the hash algorithm in C (matching TS). -- [x] Add VM init API parameters for: manifest bytes, expected hash, gas limit, and context blob. -- [x] On mismatch, fail deterministically with fixed error code/tag. - -**Acceptance criteria:** - -- [x] Harness test verifies correct manifest passes and incorrect hash fails deterministically. - -**Current state (P3 T-036):** - -- Added `quickjs-sha256.c` with a standalone SHA-256 helper and wired `JS_InitDeterministicContext` in `quickjs.c`/`quickjs.h` to validate a provided manifest (bytes + expected hash), copy it into the context, and optionally stash a context blob while setting the gas limit (defaulting to unlimited when unset). A deterministic `ManifestError` with code `ABI_MANIFEST_HASH_MISMATCH` is thrown on hash mismatch, and invalid inputs surface `TypeError` failures. -- `JSContext` now retains the manifest bytes/hash/hex plus optional context blob and frees them on shutdown; vendor `Makefile` and harness/wasm build scripts include the new SHA source. -- Native harness CLI accepts manifest inputs via `--abi-manifest-hex`/`--abi-manifest-hex-file` + `--abi-manifest-hash` (and optional `--context-blob-hex`), and test/golden scripts load the Host.v1 manifest fixture by default. The harness test suite asserts the mismatch case and runs all eval capability checks under manifest validation. - ---- - -### T-037: Specify the Wasm `host_call` import ABI and memory ownership - -**Phase:** P3 – Host ABI (DV + manifest + syscall) -**Status:** DONE -**Depends on:** T-005 - -**Goal:** -Define the exact Wasm import signature and buffer ownership rules implementing `host_call(fn_id, request_bytes) -> response_bytes`. - -**Baseline references:** Baseline #2 §1.1, §4.4 - -**Detailed tasks:** - -- [x] Write `docs/host-call-abi.md` specifying: - - [x] function signature (fn_id + ptr/len for req; plus a response mechanism), - - [x] max request/response sizes, - - [x] error behavior for malformed responses, - - [x] memory ownership (who allocates response bytes and how VM reads them), - - [x] explicit no-reentrancy rule (host_call cannot call back into VM). - -**Acceptance criteria:** - -- [x] The ABI doc is unambiguous enough to implement in both wasm host (TS) and VM (C). - ---- - -### T-038: Implement VM-side syscall dispatcher plumbing + reentrancy guard - -**Phase:** P3 – Host ABI (DV + manifest + syscall) -**Status:** DONE -**Depends on:** T-037, T-020 - -**Goal:** -Add a single syscall path from VM to host with deterministic guardrails. - -**Baseline references:** Baseline #2 §1.1, §4.4 - -**Detailed tasks:** - -- [x] Implement `host_call` invocation layer in the fork that works in both: - - [x] native harness (function pointer callback), and - - [x] wasm build (imported function). - -- [x] Add a reentrancy guard preventing nested host calls. - -- [x] Add deterministic failures for oversized request/response. - -**Acceptance criteria:** - -- [x] Native harness can register a host_call stub and receive deterministic responses. -- [x] Reentrancy is detected and fails deterministically. - ---- - -### T-039: Define and implement the host-call response envelope + deterministic HostError - -**Phase:** P3 – Host ABI (DV + manifest + syscall) -**Status:** DONE -**Depends on:** T-032, T-038 - -**Goal:** -Standardize host responses as `Ok(DV)` or `Err({code, tag, details?})` plus deterministic `units`. - -**Baseline references:** Baseline #2 §1.6, §3.2 - -**Detailed tasks:** - -- [x] Define the response envelope structure (as DV) including: - - [x] ok vs err, - - [x] `units` (u32), - - [x] optional metadata needed for charging/tape. - -- [x] Implement parsing/validation in VM. - -- [x] Implement deterministic error throwing: `HostError` with stable `{code, tag}`. - -**Acceptance criteria:** - -- [x] VM throws deterministic HostError for Err responses. -- [x] Malformed envelopes are rejected with deterministic VM error. - -**Current state (P3 T-039):** - -- Added exported `JS_ThrowHostError`, `JS_ParseHostResponse`, and `JS_FreeHostResponse` in the fork (see `vendor/quickjs/quickjs-host.c`) to decode DV response envelopes (`ok`/`err` + `units`), enforce manifest-provided error code/tag mappings, and reject malformed envelopes with deterministic `HostError` codes (`HOST_TRANSPORT`, `HOST_ENVELOPE_INVALID`). -- `JS_HostCall` now surfaces transport failures as `HostError { code: "HOST_TRANSPORT", tag: "host/transport" }` instead of a `TypeError`. -- Native harness gains `--host-parse-envelope`/`--host-max-units` to decode host responses using default `Host.v1` error mappings; tests cover ok envelope decoding and HostError paths for manifest errors and invalid envelopes. -- Follow-up hardening: `JS_ParseHostResponse` now enforces strict `units` uint32 semantics (no strings/floats/-0), requires `err.code` to be a string, preserves OutOfGas instead of masking it as `HOST_ENVELOPE_INVALID`, and frees all intermediate refs; harness tests were expanded to pin these envelope validation rules (non-number/non-integer units, non-string code, `max_units=0` cases). - ---- - -### T-040: Generate `Host.v1` namespace from manifest in VM - -**Phase:** P3 – Host ABI (DV + manifest + syscall) -**Status:** DONE -**Depends on:** T-036, T-039, T-035 - -**Goal:** -Expose host functions in JS as `Host.v1.*`, generated from manifest entries (js_path), frozen and immutable. - -**Baseline references:** Baseline #2 §1.5, §6.2–§6.3 - -**Detailed tasks:** - -- [x] Parse manifest entries and install nested namespace objects (null prototype). - -- [x] For each entry, create a JS wrapper that: - - [x] validates args by `arg_schema`, - - [x] DV-encodes args, - - [x] performs pre-charge gas (base + arg_bytes), - - [x] calls host_call(fn_id, req_bytes), - - [x] validates response envelope, - - [x] performs post-charge gas (out_bytes + units), - - [x] returns DV or throws HostError. - -- [x] Freeze and make namespaces non-extensible, non-writable, non-configurable. - -**Acceptance criteria:** - -- [x] With the fixture manifest, `Host.v1.document.get` exists and is callable. -- [x] Attempts to mutate `Host` or sub-objects fail deterministically. - -**Current state (P3 T-040):** - -- VM now decodes/validates the ABI manifest bytes on init and installs Host.v1 wrappers for each entry in `vendor/quickjs/quickjs-host.c`: arg schema checks (string/dv/null + utf8 limits), DV encode of args, host_call dispatch with manifest limits, envelope parsing + HostError mapping, return schema checks, and gas pre/post charging (base + arg_bytes, ret_bytes + units). -- Namespaces are created from js_path segments with null prototypes and are made non-extensible after population; Host.v1 functions are bound via magic indices and respect manifest fn_id/error code tables. -- Native harness uses a manifest-backed host stub and adds tests covering Host.v1 document.get/getCanonical/emit ok paths, HostError responses, and validation failures (type/utf8). Running `tools/quickjs-native-harness/scripts/test.sh` passes with the Host.v1 manifest fixture. - ---- - -### T-041: Install Blue-style ergonomic globals using Host.v1 wrappers - -**Phase:** P3 – Host ABI (DV + manifest + syscall) -**Status:** DONE -**Depends on:** T-040 - -**Goal:** -Provide `document()`, `event`, `steps`, and `canon` helpers consistent with Blue’s JS context, while keeping Host.v1 canonical. - -**Baseline references:** Baseline #2 §6.4–§6.5, §9 - -**Detailed tasks:** - -- [x] Implement `document(path)` as a wrapper calling `Host.v1.document.get(path)`. -- [x] Implement `document.canonical(path)` calling `Host.v1.document.getCanonical(path)`. -- [x] Accept injected DV values for `event`, `eventCanonical`, `steps`, `currentContract`, `currentContractCanonical` from input envelope `I` (wired later). -- [x] Implement `canon.unwrap` and `canon.at` as pure JS helpers (loaded deterministically by init). -- [x] Freeze/lock `document`, `event`, `eventCanonical`, `steps`, `currentContract`, `currentContractCanonical`, `canon`. - -**Acceptance criteria:** - -- [x] A test script can call `document("x")` and read `event`/`steps`. -- [x] Helpers behave deterministically and cannot be overridden by user code. - -**Current state (P3 T-041):** - -- Deterministic init now installs ergonomic globals once the manifest is loaded: `document` calls `Host.v1.document.get`, `document.canonical` calls `Host.v1.document.getCanonical`, and helpers are non-extensible. -- Context blob DV decoding clones and deep-freezes `event`, `eventCanonical`, `steps`, `currentContract`, and `currentContractCanonical` before exposing them on the global. -- Added pure C `canon.unwrap` (DV roundtrip + freeze) and `canon.at` (safe path walker with deterministic errors and bounds) under a frozen `canon` object. -- Native harness tests now cover ergonomic globals + canon helpers using the pinned context blob fixture; full harness suite passes. - ---- - -### T-042: Implement two-phase gas charging for host calls (VM) - -**Phase:** P3 – Host ABI (DV + manifest + syscall) -**Status:** DONE -**Depends on:** T-040, T-022 - -**Goal:** -Ensure host calls incur deterministic gas independent of host performance. - -**Baseline references:** Baseline #2 §3.2–§3.4 - -**Detailed tasks:** - -- [x] Implement pre-charge: base + arg_bytes \* k_arg. -- [x] Implement post-charge: out*bytes * k*out + units * k_units. -- [x] Ensure OOG after host returns results in deterministic abort with no additional effects (for READ-only this is simpler; still must be deterministic). -- [x] Add tests for host-call gas formulas using a mock host_call stub. - -**Acceptance criteria:** - -- [x] Gas charged for host calls matches expected formula exactly. - -**Current state (P3 T-042):** - -- Host.v1 wrappers charge gas pre-call (`base + arg_bytes * k_arg`) and post-call (`resp_bytes * k_ret + units * k_units`) using the manifest parameters; overflow is guarded and out-of-gas is uncatchable. -- Added native harness coverage (`tools/quickjs-native-harness/scripts/host-gas.mjs`) that DV-encodes manifest fixture args/responses and asserts the measured host-call gas matches the formula for ok, err, and emit paths; wired into `tools/quickjs-native-harness/scripts/test.sh`. -- Existing host-call arg/response validation, manifest limits, and HostError mapping remain unchanged; the gas tests ensure formula stability across refactors. - ---- - -### T-043: Add optional VM-side tape for auditing host calls - -**Phase:** P3 – Host ABI (DV + manifest + syscall) -**Status:** DONE -**Depends on:** T-042 - -**Goal:** -Provide deterministic audit traces (request/response hashes, fn_id, gas breakdown). - -**Baseline references:** Baseline #2 §5 - -**Detailed tasks:** - -- [x] Define tape record fields and hashing algorithm(s) (document). -- [x] Implement bounded tape buffer in VM. -- [x] Expose tape output deterministically as part of evaluation result. - -**Acceptance criteria:** - -- [x] Tape enabled runs produce identical tape across repeated executions. - -**Current state (P3 T-043):** - -- `quickjs-host.*` now keeps an optional per-context ring buffer (max 1024 records) recording `fn_id`, request/response byte lengths, units, pre/post gas charges, `is_error`/`charge_failed` flags, and SHA-256 hashes of the request/response bytes. It is opt-in via `JS_EnableHostTape(ctx, capacity)`, resettable, and readable in order via `JS_ReadHostTape`/`JS_GetHostTapeLength`. -- Tape hashing uses SHA-256 over the exact DV request/response slices; ring order is deterministic and bounded, with overflow wrapping oldest entries. -- SDK/evaluator can include tape in results by calling the tape read API after execution without affecting VM semantics. - ---- - -# Phase P4 — Emscripten build pipeline and deterministic Wasm artifacts - -### T-050: Implement `libs/quickjs-wasm-build` pipeline scaffolding - -**Phase:** P4 – Emscripten build and deterministic artifacts -**Status:** DONE -**Depends on:** T-003, T-004, T-002, T-029 - -**Goal:** -Compile the forked QuickJS to Wasm using pinned Emscripten. - -**Baseline references:** Baseline #1 §1A - -**Detailed tasks:** - -- [x] Add Nx build target invoking emcc on QuickJS sources + fork changes. -- [x] Emit `.wasm` + loader/glue into deterministic `dist/` paths. -- [x] Emit build metadata (engine build hash). - -**Acceptance criteria:** - -- [x] `pnpm nx build quickjs-wasm-build` produces wasm + JS glue outputs. - -**Current state (P4 T-050):** - -- `pnpm nx build quickjs-wasm-build` calls `scripts/build-wasm.sh` (emscripten 3.1.56) to emit `quickjs-eval{,-wasm64}.{js,wasm}` into `libs/quickjs-wasm-build/dist/` alongside compiled TS outputs. -- Builds now emit `quickjs-wasm-build.metadata.json` capturing QuickJS version/commit, pinned emscripten version, per-variant artifact sizes and SHA-256 hashes, plus `engineBuildHash` (sha256 of wasm bytes, with the top-level hash pointing at wasm32 release when present); helpers `getQuickjsWasmMetadataPath`/`readQuickjsWasmMetadata` expose the metadata. - ---- - -### T-051: Enforce deterministic Wasm memory sizing + disable nondeterministic Emscripten features - -**Phase:** P4 – Emscripten build and deterministic artifacts -**Status:** DONE -**Depends on:** T-050 - -**Goal:** -Freeze memory growth and remove nondeterministic runtime features. - -**Baseline references:** Baseline #1 §2C - -**Detailed tasks:** - -- [x] Configure fixed memory sizing (min == max or strictly controlled). -- [x] Ensure no FS/network/syscalls. -- [x] Ensure build outputs don’t embed timestamps or env-dependent differences. -- [x] Document chosen flags in `docs/toolchain.md`. - -**Acceptance criteria:** - -- [x] Wasm memory growth is disabled/fixed per build inspection. -- [x] Wasm bytes hash is stable across repeated builds with identical inputs. - -**Current state (P4 T-051):** - -- `scripts/build-wasm.sh` now builds with `-sFILESYSTEM=0`, `-sALLOW_MEMORY_GROWTH=0`, `-sALLOW_TABLE_GROWTH=0`, fixed memory (`INITIAL_MEMORY=MAXIMUM_MEMORY=32 MiB`) and a 1 MiB stack; `SOURCE_DATE_EPOCH` is pinned (override via env) to strip timestamps, and we intentionally avoid `-sDETERMINISTIC` because it patches host `Date.now`/`Math.random`. -- Memory/flag settings are exported into `quickjs-wasm-build.metadata.json` under `build.memory` and `build.determinism` for audit, and `docs/toolchain.md` documents the deterministic flags/memory choices. -- `pnpm nx build quickjs-wasm-build` and `pnpm nx test quickjs-wasm-build` pass with the deterministic settings; wasm/hash metadata reflects stable builds given identical inputs. - ---- - -### T-052: Package artifacts into `libs/quickjs-wasm` - -**Phase:** P4 – Emscripten build and deterministic artifacts -**Status:** DONE -**Depends on:** T-050, T-002 - -**Goal:** -Publish Wasm bytes + loader and metadata in a consumable library. - -**Detailed tasks:** - -- [x] Define public API for getting wasm bytes (Node + browser). -- [x] Ensure `.wasm` is included in package output. -- [x] Export engine metadata (engine build hash, feature flags). - -**Acceptance criteria:** - -- [x] Node script can import `quickjs-wasm` and obtain wasm bytes. -- [x] Browser app can load wasm from the same package. - -**Current state (P4 T-052):** - -- `@blue-quickjs/quickjs-wasm` packages `quickjs-eval{,-debug}{,-wasm64}.{js,wasm}` and `quickjs-wasm-build.metadata.json` under `dist/wasm`, exporting them in `package.json`. -- Public helpers (`loadQuickjsWasmMetadata`, `getQuickjsWasmArtifact`, `loadQuickjsWasmBinary`, `loadQuickjsWasmLoaderSource`) resolve artifacts in Node (file URLs) and browser/bundler contexts; constants/types come from `@blue-quickjs/quickjs-wasm-constants`, and helpers accept both `variant` and `buildType`. -- Vite build copies artifacts from `quickjs-wasm-build/dist` into the package; tests assert metadata presence and successful wasm/loader loading (magic header, host_call marker). `quickjs-wasm-build` remains the build-only/private producer of artifacts. - ---- - -### T-053: Add release and debug Wasm variants (same semantics) - -**Phase:** P4 – Emscripten build and deterministic artifacts -**Status:** DONE -**Depends on:** T-051 - -**Goal:** -Provide two variants without changing semantics (debug adds assertions/tape, not behavior). - -**Baseline references:** Baseline #1 §1A - -**Detailed tasks:** - -- [x] Add release build config. -- [x] Add debug config (asserts/tracing). -- [x] Ensure runtime can select variant and that variant identity is pinnable via `P` metadata. - -**Acceptance criteria:** - -- [x] Both variants build and run the same sample program successfully. - -**Current state (P4 T-053):** - -- `libs/quickjs-wasm-build/scripts/build-wasm.sh` now emits release + debug artifacts for each requested variant (default wasm32) and accepts `WASM_BUILD_TYPES=release,debug` alongside `WASM_VARIANTS`. Debug builds add Emscripten assertions and stack-overflow checks; metadata records `buildType`, `buildFlags`, and per-build hashes. -- `@blue-quickjs/quickjs-wasm-build` exports debug basenames, and `getQuickjsWasmArtifacts(variant, buildType)` resolves the correct paths. -- `@blue-quickjs/quickjs-wasm` packages all release/debug artifacts, exposes `QuickjsWasmBuildType`, lists available build targets, and tests instantiate each build target to evaluate a sample program, asserting matching results/gas across release/debug for the same variant. Harnesses accept `QJS_WASM_BUILD_TYPE` alongside `QJS_WASM_VARIANT`. - ---- - -### T-054: Optional Wasm-level safety fuse (non-canonical) - -**Phase:** P4 – Emscripten build and deterministic artifacts -**Status:** WON'T DO (decision: avoid wasm instrumentation nondeterminism; rely on canonical gas inside QuickJS) -**Depends on:** T-051 - -**Goal:** -Add an optional safety fuse (not canonical gas) to prevent runaway computation. - -**Baseline references:** Baseline #1 §2A - -**Detailed tasks:** - -- [ ] Choose a fuse mechanism (wasm-instrument or equivalent). -- [ ] Ensure fuse is optional and produces deterministic failure. -- [ ] Document that canonical gas remains the QuickJS meter. - -**Acceptance criteria:** - -- [ ] Fuse can be triggered deterministically in a test without affecting canonical gas accounting. - -**Decision:** - -- Skipping this optional fuse. Prior wasm instrumentation attempts were not fully deterministic; QuickJS-level canonical gas already enforces bounded execution, and adding a wasm-level fuse would not add meaningful safety without risking nondeterminism. - ---- - -# Phase P5 — TypeScript SDK (`libs/quickjs-runtime`) + host dispatcher adapter - -### T-060: Define program artifact `P` and input envelope `I` types - -**Phase:** P5 – TypeScript runtime SDK -**Status:** DONE -**Depends on:** T-034, T-031 - -**Goal:** -Make `(P, I, G)` explicit and version-pin critical ABI/engine fields. - -**Baseline references:** Baseline #2 §1.3; Baseline #1 §1C - -**Detailed tasks:** - -- [x] Define `P` structure in TS including: - - [x] code (source string for now), - - [x] `abi_id`, `abi_version`, - - [x] `abi_manifest_hash`, - - [x] optional `engine_build_hash`. - -- [x] Define `I` structure in TS including: - - [x] `event` DV, `eventCanonical` DV, `steps` DV, `currentContract` DV, `currentContractCanonical` DV, - - [x] enforce rejection of unknown fields (no document snapshot/host metadata carried in the envelope). - -- [x] Add validation helpers. - -**Acceptance criteria:** - -- [x] `quickjs-runtime` can validate P and I and produce deterministic validation errors. - ---- - -### T-061: Implement TS host dispatcher adapter that powers wasm `host_call` - -**Phase:** P5 – TypeScript runtime SDK -**Status:** DONE -**Depends on:** T-031, T-037, T-035 - -**Goal:** -Implement the host-side `host_call` function in TS, using embedder-provided deterministic document access and optional emit handling. - -**Baseline references:** Baseline #2 §1.1–§1.2, §3.4, §4.4 - -**Detailed tasks:** - -- [x] Define a minimal embedder-facing interface for document reads (read-only): - - [x] `get(path) -> { ok DV | err {code,tag,details?}, units }` - - [x] `getCanonical(path) -> { ok DV | err ..., units }` - - (units is required unless you can prove a tight bound from sizes alone.) - -- [x] Implement a dispatcher that: - - [x] receives `fn_id` + request bytes, - - [x] DV-decodes args, - - [x] routes to correct handler based on fn_id, - - [x] enforces manifest limits (max req/resp bytes, max units), - - [x] returns DV-encoded response envelope bytes. - -- [x] Ensure deterministic errors on malformed requests or unknown fn_id. - -**Implementation hints (for Codex):** - -- Manifest is authoritative. Do not accept functions not in the manifest. -- Keep dispatch synchronous; enforce no reentrancy (lock). - -**Acceptance criteria:** - -- [x] Given mock handlers, dispatcher returns stable response bytes and units. -- [x] Unknown fn_id or malformed requests surface deterministically (transport sentinel / `HOST_TRANSPORT` path is acceptable since no manifest mapping exists for unknown `fn_id`). - ---- - -### T-062: Implement `quickjs-runtime` Wasm instantiation (Node + browser) - -**Phase:** P5 – TypeScript runtime SDK -**Status:** DONE -**Depends on:** T-052, T-061 - -**Goal:** -Load the same wasm bytes everywhere and instantiate with the TS `host_call` adapter. - -**Baseline references:** Baseline #1 §1A; Baseline #2 §6.1 - -**Detailed tasks:** - -- [x] Load wasm bytes via `libs/quickjs-wasm` in Node and browser. -- [x] Instantiate wasm with imports including `host_call` per `docs/host-call-abi.md`. -- [x] Provide a `createRuntime()` API that prepares an instance for evaluation. - -**Acceptance criteria:** - -- [x] Node and browser can instantiate runtime successfully using the same wasm bytes. - -**Current state (P5 T-062):** - -- `createRuntime` in `libs/quickjs-runtime` loads artifacts from `@blue-quickjs/quickjs-wasm`, wires the manifest-backed host dispatcher into the wasm `host_call` import, and returns a ready module + dispatcher metadata. The smoke-web app now uses `createRuntime` with the Host.v1 fixture and mock handlers to exercise browser instantiation; runtime tests cover the Node path and host_call wiring. -- wasm64 is explicitly rejected in `createRuntime` (host_call pointers are treated as 32-bit); wasm32 remains the canonical variant. -- Browser-safe constants now live in `@blue-quickjs/quickjs-wasm-constants` to avoid node-only imports in browser bundles; quickjs-wasm consumes this package. - ---- - -### T-063: Implement runtime initialization handshake (manifest bytes, hash, I blob, gas) - -**Phase:** P5 – TypeScript runtime SDK -**Status:** DONE -**Depends on:** T-060, T-062, T-036 - -**Goal:** -Initialize VM deterministically with manifest validation and injected globals before user code runs. - -**Baseline references:** Baseline #2 §6.1–§6.2 - -**Detailed tasks:** - -- [x] Pass manifest bytes to VM and provide expected manifest hash from `P`. -- [x] Pass `I` as canonical DV bytes (preferred) or a deterministic context blob. -- [x] Set gas limit `G`. -- [x] Ensure VM installs `Host.v1` and Blue-style globals before evaluating code. - -**Acceptance criteria:** - -- [x] Manifest hash mismatch fails deterministically. -- [x] Injected globals exist and are immutable. - -**Current state (P5 T-063):** - -- The wasm harness now exports deterministic init/eval/teardown (`qjs_det_init`, `qjs_det_eval`, `qjs_det_free`), wires the imported `host_call`, validates manifest bytes/hash via `JS_InitDeterministicContext`, and decodes the DV context blob to install ergonomic globals before running user code. -- `libs/quickjs-runtime` adds `initializeDeterministicVm`, which validates `P`/`I`, encodes manifest + DV context, sets gas limit, and drives the new wasm entrypoints; tests cover hash-mismatch failure and confirm `document`/`canon`/`event`/`steps` are present and frozen. - ---- - -### T-064: Implement `evaluate(P, I, G, host)` API and result model - -**Phase:** P5 – TypeScript runtime SDK -**Status:** DONE -**Depends on:** T-063, T-041, T-042 - -**Goal:** -Provide a single-call deterministic evaluator entrypoint suitable for embedding in `document-processor`. - -**Baseline references:** Baseline #1 §1–§2; Baseline #2 §0.3 - -**Detailed tasks:** - -- [x] Implement `evaluate()` that: - - [x] validates P and I, - - [x] initializes VM, - - [x] evaluates `P.code`, - - [x] returns result DV (or deterministic error), gas used/remaining, and optional host tape/gas trace. - -- [x] Ensure return value is DV-validated (JS can only return DV types or deterministic error). - -**Current state (P5 T-064):** - -- Added `evaluate()` in `libs/quickjs-runtime` that validates `P`/`I`, enforces `engineBuildHash` when provided, instantiates the wasm runtime with manifest-backed host dispatch, and runs deterministic init/eval with the provided gas limit. -- VM output is parsed into structured results with `gasUsed`/`gasRemaining` (bigint) and DV-validated return values; VM failures and non-DV payloads surface as deterministic `EvaluateResult` errors (no stack traces). -- Optional host-call tape and gas trace can be enabled via `evaluate` options, pulling deterministic tape/trace data from the wasm exports. -- Tests cover success, VM validation failures, invalid output handling, engine hash mismatch scenarios, tape capture, and gas trace capture using the Host.v1 fixture manifest/handlers. - -**Acceptance criteria:** - -- [x] Same `(P,I,G)` yields identical result across Node and browser for a fixture set. - ---- - -### T-065: Stable error mapping (VM OOG vs HostError vs DV/manifest errors) - -**Phase:** P5 – TypeScript runtime SDK -**Status:** DONE -**Depends on:** T-064 - -**Goal:** -Expose stable error objects in TS without leaking host-specific data. - -**Baseline references:** Baseline #2 §1.6; Baseline #1 determinism - -**Detailed tasks:** - -- [x] Define structured error types with stable `code/tag` fields. -- [x] Map VM-thrown deterministic errors into these types. -- [x] Ensure stack traces are not part of determinism comparisons (optionally available only in debug mode). - -**Acceptance criteria:** - -- [x] Errors match by code/tag across Node/browser for the same failure. - -**Current state (P5 T-065):** - -- Added stable error typing for `evaluate` covering host errors (manifest-derived codes/tags plus transport/envelope sentinels), OutOfGas, manifest errors, JS exceptions, and invalid outputs; stack traces remain excluded. -- Errors now surface deterministic `{type, code, tag, message}` payloads with manifest-driven lookup for HostError codes; invalid outputs return a fixed `INVALID_OUTPUT` code. -- Tests assert host error mapping, OutOfGas tagging, JS exception classification, and invalid-output handling across the runtime SDK. - ---- - -### T-066: Ensure returned JS values are DV-only (enforce in VM and TS) - -**Phase:** P5 – TypeScript runtime SDK -**Status:** DONE -**Depends on:** T-064, T-031, T-032 - -**Goal:** -Prevent nondeterministic or unsupported return types from escaping the evaluator. - -**Baseline references:** Baseline #2 §2.1 - -**Detailed tasks:** - -- [x] VM enforces return type conversion into DV (or deterministic error). -- [x] TS validates returned DV bytes and rejects malformed outputs deterministically. -- [x] Add tests for forbidden return types (functions, undefined, symbols, BigInt, etc.). - -**Acceptance criteria:** - -- [x] Forbidden return types produce deterministic errors across environments. - -**Current state (P5 T-066):** - -- `qjs_det_eval` now DV-encodes results and emits lowercase-hex payloads; unsupported JS return types surface deterministic errors instead of JSON stringify paths. -- The TypeScript runtime decodes/validates DV bytes (with limits) and returns structured invalid-output errors for malformed/oversize payloads. -- Tests cover forbidden return types, DV-limit enforcement, and deterministic DV decoding in both evaluate and deterministic init flows. - ---- - -# Phase P6 — Smoke apps (developer UX) - -### T-070: Node smoke runner (`apps/smoke-node`) - -**Phase:** P6 – Smoke apps -**Status:** DONE -**Depends on:** T-064 - -**Goal:** -Provide a CLI-like dev runner for quick debugging and fixtures. - -**Current state:** - -- `apps/smoke-node` bundles a sample `(P, I, G, manifest)` using the Host.v1 fixture and mock host handlers, runs `evaluate()`, and prints a stable summary (DV hash, gas used/remaining, host tape count, optional error code/tag). -- `--debug` expands DV payloads and emitted values; `--quiet` suppresses logs. -- `pnpm nx serve smoke-node [-- --debug|--quiet]` builds then runs the sample deterministically. - -**Detailed tasks:** - -- [x] Load sample fixture `(P, I, G, manifest)` and create a mock host implementation. -- [x] Run evaluate and print a stable summary: result DV hash, gas used, tape count, error code/tag. -- [x] Provide a “debug” mode that prints decoded DV JSON (still deterministic). - -**Acceptance criteria:** - -- [x] `pnpm nx serve smoke-node` runs a sample deterministically. - ---- - -### T-071: Browser smoke runner (`apps/smoke-web`) - -**Phase:** P6 – Smoke apps -**Status:** DONE -**Depends on:** T-064, T-053 - -**Goal:** -Run the same fixtures in browser and show stable results and wasm hash. - -**Current state:** - -- `apps/smoke-web` loads the wasm via `@blue-quickjs/quickjs-wasm`, instantiates with the Host.v1 manifest/handlers from `@blue-quickjs/test-harness`, runs the same `(P, I, G)` fixture as smoke-node through `evaluate`, and renders wasm hash/result hash/gas/tape hash/emit count plus manifest + engine hashes. -- Playwright smoke (`apps/smoke-web/tests/smoke.spec.ts`) starts Vite, waits for completion, and asserts all metrics match the Node baseline; the legacy gas fixtures UI/tests have been removed. - -**Detailed tasks:** - -- [x] Load wasm from `quickjs-wasm` and instantiate via `evaluate` with the Host.v1 manifest/handlers. -- [x] Run the shared smoke fixture from `@blue-quickjs/test-harness` (same `(P, I, G)` as smoke-node). -- [x] Display wasm hash, result hash, gas used/remaining, error code/tag, tape hash, host emit count, and manifest/engine hashes. -- [x] Add a Playwright check that waits for completion and asserts all metrics match the Node baseline. - -**Acceptance criteria:** - -- [x] Browser output matches the Node baseline for the Host.v1 smoke fixture and exposes the wasm hash in the UI/Playwright smoke. - ---- - -# Phase P7 — Determinism & gas test harnesses, CI, docs hardening - -### T-080: Cross-environment determinism harness (Node vs headless browser) - -**Phase:** P7 – Determinism & CI -**Status:** DONE -**Depends on:** T-071, T-028, T-064 - -**Goal:** -Prove Baseline determinism: same `(P, I, G)` yields identical outputs and OOG points in Node and browser. - -**Baseline references:** Baseline #1 §1–§2; Baseline #2 §0.3 - -**Current state:** Playwright runs smoke-web headlessly; determinism and gas fixtures live in `libs/test-harness` and are asserted in `apps/smoke-node` + `apps/smoke-web/tests` with cross-env equality (DV hash, errors, gas, tape). - -**Detailed tasks:** - -- [x] Set up Playwright to run `smoke-web` headlessly or run a direct test page. -- [x] Create fixtures in `libs/test-harness`: P, I, G, manifest bytes + expected hashes. -- [x] Compare Node vs browser outputs: - - [x] returned DV bytes hash, - - [x] error code/tag (if any), - - [x] gas used/remaining, - - [x] tape hash (if enabled). - -**Acceptance criteria:** - -- [x] At least 5 fixtures pass cross-env with exact equality of compared fields. - ---- - -### T-081: Host-call determinism + gas-by-size/units tests - -**Phase:** P7 – Determinism & CI -**Status:** DONE -**Depends on:** T-042, T-061, T-080 - -**Goal:** -Verify host-call charging and deterministic behavior for document reads. - -**Baseline references:** Baseline #2 §3.2–§3.4 - -**Current state (P7 T-081):** - -- Added host-call-heavy determinism fixtures (varying path lengths + error cases) in `libs/test-harness`. -- Node + browser determinism suites now cover these fixtures and compare DV hash, gas used/remaining, and tape hash (which includes per-call gas pre/post charges). -- Host-call OOG boundary behavior remains covered by the native harness tests introduced in T-042 to avoid duplication. - -**Detailed tasks:** - -- [x] Add fixtures that call `document()` repeatedly with varying paths. -- [x] Use mock host that returns deterministic DV and units. -- [x] Assert gas formula correctness (pre/post charge) and OOG boundaries on host calls. -- [x] Assert deterministic Err responses for invalid path/not found/limit exceeded. - -**Acceptance criteria:** - -- [x] Gas and errors match exactly across Node/browser for host-call-heavy scripts. - ---- - -### T-082: Manifest pinning tests (wrong hash, wrong manifest, wrong fn_id mapping) - -**Phase:** P7 – Determinism & CI -**Status:** DONE -**Depends on:** T-036, T-064 - -**Goal:** -Ensure ABI pinning is enforced deterministically. - -**Baseline references:** Baseline #2 §1.3–§1.4 - -**Detailed tasks:** - -- [x] Test: manifest hash mismatch fails deterministically. -- [x] Test: manifest entry order changes but canonical serialization yields same hash (if canonicalized). -- [x] Test: unknown fn_id invoked fails deterministically. - -**Acceptance criteria:** - -- [x] All ABI mismatch scenarios are deterministic and code/tag stable. - -**Current state (P7 T-082):** - -- Manifest hash mismatch is covered in `libs/quickjs-runtime/src/lib/deterministic-init.spec.ts`. -- Canonicalization parity (hash stable under key reordering) is covered in `libs/abi-manifest/src/lib/abi-manifest.spec.ts`. -- Unknown `fn_id` dispatch is covered in `libs/quickjs-runtime/src/lib/host-dispatcher.spec.ts` and surfaced as `HOST_TRANSPORT` in `libs/quickjs-runtime/src/lib/evaluate.spec.ts`. - ---- - -### T-083: CI pipeline (build, test, wasm build, browser tests) - -**Phase:** P7 – Determinism & CI -**Status:** DONE -**Depends on:** T-080, T-004 - -**Goal:** -Add CI that builds and tests everything including headless browser determinism and wasm builds. - -**Detailed tasks:** - -- [x] Add CI workflow steps: install, lint, unit tests, native harness tests, wasm build, Playwright tests. -- [x] Cache pnpm store and emsdk. -- [x] Upload wasm artifacts as CI artifacts (optional). - -**Acceptance criteria:** - -- [x] CI passes from a clean checkout. -- [x] Determinism tests are not flaky. - -**Current state (P7 T-083):** - -- CI runs lint/typecheck/test/build across all projects, installs/caches emsdk, executes Playwright smoke tests, and uploads wasm artifacts from `libs/quickjs-wasm-build/dist`. -- Node version is sourced from `.nvmrc`, with pnpm caching enabled. - ---- - -### T-084: Documentation hardening (make docs normative) - -**Phase:** P7 – Determinism & CI -**Status:** DONE -**Depends on:** T-080 - -**Goal:** -Update docs to match implementation and tests. - -**Detailed tasks:** - -- [x] Finalize determinism profile doc (exact allowed/disabled APIs). -- [x] Finalize gas schedule doc (opcode costs, builtin costs, alloc/GC, host call costs). -- [x] Finalize DV wire format and manifest docs with examples. -- [x] Add “Determinism checklist” in root README. - -**Acceptance criteria:** - -- [x] Docs contain testable statements that match harness assertions. - ---- - -### T-085: Release packaging strategy (pin engine + ABI) - -**Phase:** P7 – Determinism & CI -**Status:** DONE -**Depends on:** T-053, T-064 - -**Goal:** -Define versioning/publishing so consumers can pin engine/ABI reliably. - -**Baseline references:** Baseline #1 §1A; Baseline #2 §7 - -**Detailed tasks:** - -- [x] Define publishing for `quickjs-wasm`, `quickjs-runtime`, `dv`, `abi-manifest`. -- [x] Define how `engine_build_hash` is computed and exposed. -- [x] Define semver policy: what changes require new engine hash, new manifest, or new fn_id. -- [x] Add release checklist doc. - -**Acceptance criteria:** - -- [x] Release policy is documented and aligns with P pinning requirements. - -**Current state (P7 T-085):** - -- Added `docs/release-policy.md` covering published packages, engine/manifest hash definitions, and semver/hash/fn_id policy. -- Added `docs/release-checklist.md` with preflight, build, hash verification, and publishing steps. - ---- - -# Phase P8 — Legacy wasm harness cleanup - -### T-090: Retire legacy wasm JSON gas harness and consolidate docs - -**Phase:** P8 – Legacy wasm harness cleanup -**Status:** DONE -**Depends on:** T-053, T-063, T-064 - -**Goal:** -Remove the pre-ABI `qjs_eval`/`qjs_free_output` JSON harness, move wasm consumers/tests to the deterministic ABI path, and fold any still-relevant notes into canonical docs so `docs/wasm-gas-harness.md` can be deleted. - -**Current state:** -Deterministic ABI entrypoints are available; wasm gas consumers have been migrated off the legacy JSON harness, and the temporary wasm-gas-harness doc has been removed in favor of canonical toolchain/build notes. - -**Detailed tasks:** - -- [x] Update wasm-facing tests to use the deterministic ABI entrypoints: drive `qjs_det_init`/`qjs_det_eval` with the manifest + DV payloads in `libs/test-harness/src/lib/gas-equivalence.spec.ts`, `libs/quickjs-wasm/src/lib/quickjs-wasm.spec.ts`, and `libs/quickjs-runtime/src/lib/runtime.spec.ts`; rebaseline gas expectations from the ABI path. -- [x] Remove legacy exports from the wasm harness: drop `qjs_eval`/`qjs_free_output` from `libs/quickjs-wasm-build/src/wasm/quickjs_wasm.c` and from the exported symbols list in `libs/quickjs-wasm-build/scripts/build-wasm.sh`; update `libs/quickjs-wasm-build/README.md` to describe only the deterministic ABI entrypoints. -- [x] Consolidate documentation: migrate any persistent artifact path/metadata notes from `docs/wasm-gas-harness.md` into the appropriate canonical doc (`docs/toolchain.md` or this plan’s P4 state) and remove `docs/wasm-gas-harness.md` plus its reference in this file. - -**Acceptance criteria:** - -- [x] No tests or harnesses call `qjs_eval` or parse the legacy `RESULT|ERROR … GAS …` format; ABI/DV-based entrypoints are used instead. -- [x] Wasm build outputs expose only the deterministic ABI exports, and README/build scripts match. -- [x] `docs/wasm-gas-harness.md` is deleted and any needed stable details live in existing canonical docs. - -**Current state (P8 T-090):** - -- `libs/quickjs-wasm-build` exports only deterministic ABI entrypoints; qjs*eval/qjs_free_output were removed from the C harness and build script, and the README now documents qjs_det*\* usage and `_free` expectations. -- Wasm-facing specs in `libs/test-harness`, `libs/quickjs-wasm`, and `libs/quickjs-runtime` drive `qjs_det_init`/`qjs_det_eval` with the Host.v1 manifest/context and assert DV payloads + gas numbers (wasm32 expectations are pinned; wasm64 compares to native). -- Legacy notes from `docs/wasm-gas-harness.md` were folded into `docs/toolchain.md` and this plan; the legacy doc was deleted. - ---- - -## Appendix A — Minimal required ABI surface (v1) - -The initial manifest should define at least: - -- `Host.v1.document.get(path: string) -> DV` (READ) -- `Host.v1.document.getCanonical(path: string) -> DV` (READ) -- Optional but recommended for deterministic logging: - - `Host.v1.emit(value: DV) -> null` (EMIT) - -Ergonomic aliases: - -- `document(path)` calls `Host.v1.document.get(path)` -- `document.canonical(path)` calls `Host.v1.document.getCanonical(path)` -- `event`, `eventCanonical`, `steps`, `currentContract`, `currentContractCanonical` injected from input envelope `I` -- `canon.unwrap` and `canon.at` are pure JS helpers installed by init - ---- - -## Appendix B — Invariants checklist (what tests must prove) - -- **Determinism:** Same `(P, I, G)` ⇒ same outputs + same exact OOG point across Node and browser. -- **Canonical gas:** opcode + metered C builtins + deterministic alloc/GC; not wasm instruction counts. -- **Strict capability profile:** no time/random/async/network/fs/locale leaks; no typed arrays/ArrayBuffer/WebAssembly. -- **Baseline #2 ABI:** single dispatcher + numeric fn_id + manifest-locked mapping + manifest hash validation. -- **DV restrictions:** only allowed types; numeric restrictions; canonical key ordering; deterministic encoding. -- **Two-phase host-call charging:** base+arg bytes before call; out bytes+units after; deterministic OOG boundaries. -- **No reentrancy:** host_call cannot call back into VM or nest host calls. diff --git a/docs/implementation-summary.md b/docs/implementation-summary.md deleted file mode 100644 index 5a22e90..0000000 --- a/docs/implementation-summary.md +++ /dev/null @@ -1,393 +0,0 @@ -# Implementation summary - -This document summarizes what is **implemented in this repository**, and how it maps to: - -- [Baseline #1 – Deterministic JS engine](./baseline-1.md) -- [Baseline #2 – Host ABI + DV contract](./baseline-2.md) -- [Implementation plan](./implementation-plan.md) - -For deep/normative details, this doc always points to the corresponding reference spec in `docs/`. - ---- - -## What this repo provides - -At a high level, the repo provides a deterministic evaluator: - -> **evaluate(P, I, G, Host) → (Result, Gas, optional traces)** - -Where: - -- **P** is a *program artifact* (JS code plus ABI identity/pinning metadata). -- **I** is a *deterministic input envelope* injected into the VM (event, eventCanonical, steps, currentContract, currentContractCanonical). -- **G** is a *gas limit* (uint64). -- **Host** is a *manifest-backed set of synchronous host functions* exposed through a single ABI syscall. - -The evaluator runs JavaScript inside a **QuickJS VM compiled to WebAssembly** under a **determinism profile**, and only allows host interaction through a **manifest-locked ABI** (the `host_call` import). Values crossing this boundary are encoded as **Deterministic Values (DV)**. - -If you are new to the concepts: -- DV is explained in depth in [DV wire format](./dv-wire-format.md). -- The Host ABI is explained in depth in [Host call ABI](./host-call-abi.md) and [ABI manifest](./abi-manifest.md). -- Gas and the schedule are specified in [Gas schedule](./gas-schedule.md). -- The determinism profile (what JS features exist / don’t exist) is in [Determinism profile](./determinism-profile.md). - ---- - -## Core concepts and vocabulary - -These terms are used consistently across docs and code: - -- **VM**: the deterministic QuickJS instance (inside Wasm). -- **Host**: the embedding environment (Node or browser). -- **ABI**: the *binary-level* interface between VM and Host (`host_call`), plus its manifest. -- **Manifest**: the declarative “API surface” describing which host functions exist, their IDs, gas parameters, limits, and error codes. See [ABI manifest](./abi-manifest.md). -- **DV (Deterministic Value)**: the canonical wire format for all values crossing the VM boundary. See [DV wire format](./dv-wire-format.md). -- **Gas**: deterministic resource accounting used to bound execution. See [Gas schedule](./gas-schedule.md). -- **Tape**: an optional deterministic audit trace of host calls (fnId, sizes, units, hashes, gas breakdown). See [Observability](./observability.md) and the tape section in [Host call ABI](./host-call-abi.md). - ---- - -## Architecture at a glance - -### Dataflow - -``` -Program artifact P + Input I + Gas limit G + Manifest + Host handlers - | - v - Wasm QuickJS runtime - (deterministic init + Host.v1) - | - v - Deterministic JS evaluation - | - +--> DV result OR deterministic error - +--> gasUsed / gasRemaining - +--> optional: host-call tape, gas trace -``` - -### Why the “manifest-locked ABI” exists - -Normal JavaScript can call arbitrary host APIs (filesystem, network, time, randomness…). That destroys determinism. - -This repo instead uses a **single syscall** (`host_call`) plus a **manifest** to define and pin exactly what the VM is allowed to do. This achieves: - -- A *small, auditable interface* between VM and Host. -- *Deterministic validation* on both sides (request/response shape, limits, error codes). -- *Versioning and pinning* (programs declare the ABI identity/hash they expect). -- A clean boundary for metering and tracing. - -Details: [Baseline #2](./baseline-2.md), [Host call ABI](./host-call-abi.md), [ABI manifest](./abi-manifest.md). - ---- - -## What happens when you run code - -This repo implements the full end-to-end pipeline from the implementation plan (see [Implementation plan](./implementation-plan.md)). The core “run” steps are: - -### 1) Host loads the runtime (Wasm + dispatcher) - -The TypeScript SDK loads the prebuilt wasm artifact(s) and wires the imported `host_call` function to a **manifest-backed dispatcher**. - -Code pointers: -- Runtime loader: `libs/quickjs-runtime/src/lib/runtime.ts` -- Host dispatcher: `libs/quickjs-runtime/src/lib/host-dispatcher.ts` -- Wasm artifacts packaging: `libs/quickjs-wasm/`, `libs/quickjs-wasm-build/`, and `libs/quickjs-wasm-constants/` - -Build determinism details: [Toolchain](./toolchain.md). - -### 2) Deterministic init handshake (manifest + hash + context blob + gas) - -Before evaluating user code, the VM is initialized with: - -- **Manifest bytes** (canonical encoding) -- **Manifest hash** (from `P.abiManifestHash`) for pinning/anti-confusion -- **Context blob** (DV-encoded `I.event`, `I.eventCanonical`, `I.steps`, `I.currentContract`, `I.currentContractCanonical`) -- **Gas limit** `G` - -If the expected hash does not match the bytes, initialization fails deterministically. - -Reference spec: [Baseline #2](./baseline-2.md) and [ABI manifest](./abi-manifest.md). -SDK guide: [TypeScript SDK usage](./sdk.md). - -### 3) Determinism profile is installed - -During deterministic init, the VM configures QuickJS to match the deterministic feature set: - -- Disables or stubs nondeterministic APIs (`Date`, `Math.random`, etc.). -- Disables features that would make execution depend on host implementation details. -- Ensures the environment is “closed” (frozen globals, no ambient I/O APIs). - -Reference spec: [Determinism profile](./determinism-profile.md). - -### 4) Host API surface is installed from the manifest - -From the manifest, the VM installs a frozen, read-only namespace (e.g. `Host.v1.*`) and optionally ergonomic globals (`document`, `document.canonical`, `canon`, `event`, `eventCanonical`, `steps`, `currentContract`, `currentContractCanonical`) that map to those host functions. - -Reference spec: [Baseline #2](./baseline-2.md) and [Host call ABI](./host-call-abi.md). -Ergonomics and injected globals: [Determinism profile](./determinism-profile.md). - -### 5) User JS is evaluated and must return a DV - -The evaluator runs JS with deterministic gas metering enabled. The final return value must be DV-encodable, otherwise evaluation fails deterministically. - -Return encoding details: [DV wire format](./dv-wire-format.md). -Evaluation API: [TypeScript SDK usage](./sdk.md). - ---- - -## Deterministic Value (DV) - -DV is the repository’s “universal value model” for **all boundary crossings**: - -- Program outputs -- Host call arguments and results -- Context blob injected into the VM -- Manifest canonical encoding/hashing - -DV is a deliberately small subset: `null`, `boolean`, `int/float` (restricted), `string`, `bytes`, `array`, `map`, with **canonical encoding** rules and **size limits**. - -Reference spec: [DV wire format](./dv-wire-format.md). - -Why DV instead of JSON? - -- JSON has no bytes type. -- JSON has multiple valid serializations for the same data (key order, float formatting). -- We need *canonical bytes* for hashing, reproducible fixtures, and cross-language parity (C ↔ TS). - -Deterministic mode does expose **metered `JSON.parse` / `JSON.stringify` built-ins** for -internal VM ergonomics, but those do **not** replace DV at the boundary. The rule is: - -- use deterministic JSON built-ins for JSON work **inside** the VM, -- use DV for anything that must cross the VM boundary or be hashed/pinned canonically. - ---- - -## Gas and host-call metering - -Gas is a deterministic *budget* that bounds execution (similar in spirit to EVM gas, but used here as a runtime limit rather than a fee). - -### What is metered - -The VM charges gas for: - -- **Interpreter opcodes** (flat cost per step) -- **Certain builtins** (notably array callbacks) to avoid “free” work inside C loops -- **Deterministic JSON built-ins** (`JSON.parse` / `JSON.stringify`) -- **Memory allocations** (scaled by bytes) to bound allocation-heavy attacks -- **GC checkpoints** (a fixed cost) at deterministic points -- **Host calls** via manifest-defined parameters - -Reference spec: [Gas schedule](./gas-schedule.md). - -### How host-call gas is charged (two phase) - -For each host call, gas is billed in two phases using manifest gas parameters: - -- **Pre-charge** (before calling the host): - - `gas_pre = base + k_arg_bytes * request_bytes` -- **Post-charge** (after the host response is parsed): - - `gas_post = k_ret_bytes * response_bytes + k_units * units` - -Where: -- `request_bytes` is the DV-encoded args array. -- `response_bytes` is the DV-encoded response envelope. -- `units` is a host-reported scalar (used to represent host work not visible inside the VM). - -Reference spec: [Gas schedule](./gas-schedule.md) and [ABI manifest](./abi-manifest.md). - -**Why two phases?** - -- The VM must have enough gas *before* the host call to prevent “free” host effects. -- The VM can only know `response_bytes` and `units` *after* the host returns. - -A key semantic: **OOG on the post-charge happens after the host executed**, so host effects may already have occurred (e.g. `emit`). This is explicitly documented in the gas schedule and baseline, and is important when designing host side-effects. - ---- - -## ABI limits and why they matter - -There are two layers of limits: - -1. **Global DV limits** (hard caps to prevent pathological values) -2. **Per-function ABI limits** (declared in the manifest to bound each call) - -Per-function limits include: - -- `max_request_bytes` -- `max_response_bytes` -- `max_units` -- `arg_utf8_max` (per-argument string limits, in UTF-8 bytes) - -Reference spec: [ABI manifest](./abi-manifest.md) and [Host call ABI](./host-call-abi.md). -Developer guide with rationale and enforcement points: [ABI limits explained](./abi-limits.md). - ---- - -## Observability: gas trace and host-call tape - -Deterministic systems are hard to debug because “printing” can itself introduce nondeterminism. - -This repo provides two deterministic observability tools: - -- **Gas trace**: aggregate counters attributing VM gas to opcodes, array callback builtins, - allocations, and deterministic JSON built-ins. -- **Host-call tape**: bounded per-call records including hashes of the encoded request/response bytes and the gas breakdown. - -How to enable and interpret: [Observability](./observability.md). - ---- - -## Error model at a glance - -Evaluation can fail deterministically in a few broad ways: - -- **OutOfGas**: the VM gas counter hits zero. This is raised as an **uncatchable** VM error (run halts). - Spec: [Gas schedule](./gas-schedule.md). - -- **HostError**: the host returned a valid `err` envelope (with an error `code` declared in the manifest). - The VM throws an `Error` with `name = "HostError"` plus stable `code`, `tag`, and optional `details`. - Spec: [Baseline #2](./baseline-2.md), [Host call ABI](./host-call-abi.md). - - Two reserved HostErrors are used for ABI violations: - - `HOST_TRANSPORT` / `host/transport` (transport-level failure) - - `HOST_ENVELOPE_INVALID` / `host/envelope_invalid` (malformed or policy-violating envelope) - -- **ManifestError**: the VM rejected the manifest bytes or manifest hash pinning at init time. - Spec: [ABI manifest](./abi-manifest.md). - -- **JS errors (TypeError/RangeError/SyntaxError/...)**: normal JS errors from user code *or* from deterministic stubs (e.g. calling a disabled API). - Spec: [Determinism profile](./determinism-profile.md). - -On the host side, the TypeScript SDK maps raw VM errors into a stable `EvaluateResult` shape. See: -- `libs/quickjs-runtime/src/lib/evaluate-errors.ts` -- `libs/quickjs-runtime/src/lib/evaluate.ts` - - -## Repo implementation map (where the main pieces live) - -### QuickJS fork (C) - -- `vendor/quickjs/quickjs.c` - - deterministic runtime/context creation - - interpreter gas metering and allocation gas charging - - deterministic GC checkpoint support - - gas trace support -- `vendor/quickjs/quickjs-host.c` - - manifest parsing/validation - - Host.v1 wrapper generation and argument validation (`arg_utf8_max`) - - `host_call` bridge + envelope parsing + HostError mapping - - optional host-call tape -- `vendor/quickjs/quickjs-dv.c` - - DV encode/decode and canonicalization helpers used at the boundary -- `vendor/quickjs/quickjs-sha256.c` - - SHA-256 used for tape request/response hashing -- `vendor/quickjs/quickjs-wasm-entry.c` - - exported wasm functions: init/eval/setGasLimit/tape/trace/free - -Reference details: [Host call ABI](./host-call-abi.md), [DV wire format](./dv-wire-format.md), [Gas schedule](./gas-schedule.md). - -### TypeScript SDK and utilities - -- `libs/quickjs-runtime/` - - `evaluate()` convenience API and stable result model - - `createRuntime()` loader + dispatcher wiring - - `initializeDeterministicVm()` init handshake -- `libs/abi-manifest/` - - schema validation - - canonical manifest encoding and hashing - - public Host.v1 manifest fixtures (`HOST_V1_*`) -- `libs/dv/` - - DV reference encode/decode used by the host dispatcher and tests -- `libs/test-harness/` - - fixtures (determinism inputs, gas samples) - - re-exports Host.v1 manifest fixtures for internal tests - - output parsing utilities -- `libs/quickjs-wasm-build/` + `libs/quickjs-wasm/` - - deterministic wasm build pipeline and artifact metadata - ---- - -## Build determinism (Wasm artifacts) - -The wasm engine bytes are part of the deterministic surface, so builds are treated as reproducible, pinned artifacts: - -- **Pinned toolchain**: Emscripten/emsdk is locked (see `docs/toolchain.md`). -- **Deterministic build flags**: wasm output pins `SOURCE_DATE_EPOCH` (we intentionally avoid `-sDETERMINISTIC` because it patches host `Date.now`/`Math.random`). -- **Fixed memory model**: wasm memory is fixed (no growth), with a fixed stack size and no table growth. -- **No ambient host APIs**: the Emscripten filesystem is disabled; the module is built for `node,web`. -- **Auditable metadata**: build outputs record hashes, sizes, and flags in `quickjs-wasm-build.metadata.json`. -- **Release + debug builds**: debug builds add assertions/stack checks while preserving the same deterministic VM semantics. - -Details and exact flags: [Toolchain](./toolchain.md). - - -## Key decisions (planning → implementation) - -The implementation plan captures tasks and acceptance criteria; this section summarizes the biggest decisions that shaped the final code. - -### 1) Disable vs meter vs re-implement JS features - -Many JS features are either nondeterministic (time, randomness) or hard to meter precisely (some builtins do heavy work in C). The chosen strategy is: - -- **Disable** features that would compromise determinism and are not required. -- **Meter** the key “footguns” (allocation, array callbacks, host calls). -- Prefer **simple stable costs** over micro-optimizing per-op semantics. - -See: [Determinism profile](./determinism-profile.md), [Gas schedule](./gas-schedule.md). - -### 2) Single syscall (`host_call`) instead of many imports - -Instead of importing one wasm function per host capability, we use a single function: - -- simpler to version and audit -- consistent gas/limits enforcement -- allows manifest-driven installation of `Host.v1.*` - -See: [Host call ABI](./host-call-abi.md), [Baseline #2](./baseline-2.md). - -### 3) Canonical DV bytes everywhere - -To keep cross-environment parity (C ↔ TS, Node ↔ browser), every boundary value uses DV: - -- stable hashing -- stable tests/fixtures -- deterministic error behavior for malformed/oversized values - -See: [DV wire format](./dv-wire-format.md). - -### 4) Manifest pinning by hash - -Programs specify the manifest hash they were built against. The VM validates bytes+hash at init to prevent “same ABI id/version but different semantics”. - -See: [ABI manifest](./abi-manifest.md), [Release policy](./release-policy.md). - -### 5) Two-phase host-call gas + bounded traces - -Host-call gas is two-phase to fairly account for both request encoding and host work. - -Traces are **bounded** (tape capacity max) and **deterministic** (hashes, numeric counters) to avoid introducing nondeterminism. - -See: [Gas schedule](./gas-schedule.md), [Observability](./observability.md). - ---- - -## How to extend the system (high level) - -The most common extension is “add a new Host function” (new capability). The workflow is: - -1. Extend the manifest (new function entry, gas, limits, errors). -2. Implement the handler in the host dispatcher. -3. Add/extend fixtures + tests. -4. Consider ABI id/version policy (breaking vs non-breaking changes). - -Details: [ABI manifest](./abi-manifest.md), [Host call ABI](./host-call-abi.md), [Release policy](./release-policy.md). - ---- - -## Known limitations / non-goals (current state) - -- Only **wasm32** is supported by the TypeScript runtime integration (pointer sizes are treated as 32-bit). See runtime notes in the implementation plan and SDK docs. -- Wasm memory is configured for determinism (fixed sizing; no growth). See [Toolchain](./toolchain.md). -- The determinism profile is intentionally restrictive; many JS APIs are not available. See [Determinism profile](./determinism-profile.md). -- “Gas trace” attributes only VM-internal categories; host-call gas is billed but not counted inside trace totals. See [Gas schedule](./gas-schedule.md) and [Observability](./observability.md). diff --git a/docs/learn/00-what-is-bluequickjs.md b/docs/learn/00-what-is-bluequickjs.md new file mode 100644 index 0000000..755e76a --- /dev/null +++ b/docs/learn/00-what-is-bluequickjs.md @@ -0,0 +1,76 @@ +# 00 — What is BlueQuickjs? + +BlueQuickjs is a deterministic JavaScript execution stack built on a hardened +QuickJS engine compiled to Wasm. It is designed for **consensus-critical** +execution where independent runtimes must agree on: + +- value or error, +- gas used and gas remaining, +- host-call tape, +- exact out-of-gas boundary. + +Consensus-safe release scope today is deliberately narrow: + +- `wasm-node` +- `wasm-browser` +- canonical `wasm32` release artifacts only + +Native tooling exists for diagnostics, debugging, and reconciliation, but it is +**not** part of the consensus release contract unless a future release policy +promotes it explicitly. + +## Prerequisites + +- Node.js `>= 22.0.0` +- `pnpm` + +## Commands + +Build the CLI and inspect the current command surface: + +```bash +pnpm install +pnpm nx build blue-quickjs-cli +node tools/blue-quickjs-cli/dist/cli.js help +``` + +## Expected output + +You should see a command list that includes deterministic build/run/report +paths such as: + +- `build` +- `run` +- `inspect` +- `consensus-report` +- `native-report` + +That command surface mirrors the product shape: + +- build deterministic artifacts, +- run them in wasm, +- generate reproducibility evidence, +- keep native as an explicit diagnostic path. + +## What you learned + +- BlueQuickjs is a deterministic **artifact + runtime + evidence** system, not + just a JS interpreter. +- Consensus-safe execution is currently wasm-only (`wasm-node` vs + `wasm-browser`). +- Exact gas and exact OOG boundaries are part of the release contract. +- Profiles determine which compatibility features are available: + `baseline-v1`, `compat-general-v1`, and `compat-binary-v1`. + +## Continue + +Next: [01 — Install and run your first script](./01-install-and-run-your-first-script.md) + +## Troubleshooting + +- If `pnpm install` fails, confirm your Node version matches the root + `package.json` engines field. +- If the CLI build fails, run `bash tools/scripts/prepare-quickjs-source.sh` and + then retry. +- For a scope summary without running commands, read + [Consensus-safe vs diagnostic-only](../consensus-safe-vs-diagnostic-only.md). diff --git a/docs/learn/01-install-and-run-your-first-script.md b/docs/learn/01-install-and-run-your-first-script.md new file mode 100644 index 0000000..be6b212 --- /dev/null +++ b/docs/learn/01-install-and-run-your-first-script.md @@ -0,0 +1,72 @@ +# 01 — Install and run your first script + +This page walks through the fastest path from a clean checkout to a successful +deterministic run with visible gas accounting. + +## Prerequisites + +- Node.js `>= 22.0.0` +- `pnpm` + +## Commands + +Install dependencies, set up the pinned Wasm toolchain, build the CLI, create a +tiny entry module, build a deterministic artifact, and run it: + +```bash +pnpm install +bash tools/scripts/setup-emsdk.sh +source tools/emsdk/emsdk_env.sh +pnpm nx build blue-quickjs-cli +mkdir -p tmp/learn-first-script +printf 'export default (() => 1 + 2)();\n' > tmp/learn-first-script/entry.js +node tools/blue-quickjs-cli/dist/cli.js build \ + --entry tmp/learn-first-script/entry.js \ + --out tmp/learn-first-script/program.json +node tools/blue-quickjs-cli/dist/cli.js run \ + --artifact tmp/learn-first-script/program.json \ + --gas-limit 1000000 +``` + +## Expected output + +The `build` command should print a JSON summary with fields like: + +- `compatibilityOk: true` +- `moduleCount` +- `graphHash` + +The `run` command should print a success payload shaped like: + +```json +{ + "ok": true, + "value": 3, + "gasUsed": "...", + "gasRemaining": "...", + "tapeLength": 0 +} +``` + +The exact gas numbers matter and are deterministic for the same artifact, +inputs, and gas limit. + +## What you learned + +- How to install the pinned Emscripten toolchain used for wasm builds. +- How to build a deterministic artifact from source. +- How to execute that artifact and inspect deterministic gas output. +- That a simple local script already runs through the same artifact model used + by the wider product. + +## Continue + +Next: [02 — Understand the program artifact](./02-understand-the-program-artifact.md) + +## Troubleshooting + +- If `setup-emsdk.sh` fails, read [Toolchain + build determinism](../toolchain.md). +- If the build command reports compatibility diagnostics, confirm the file uses + plain deterministic JS and no unsupported APIs. +- If `run` fails with an execution-profile or pin error, inspect the artifact in + the next step before editing fields manually. diff --git a/docs/learn/02-understand-the-program-artifact.md b/docs/learn/02-understand-the-program-artifact.md new file mode 100644 index 0000000..1e5461c --- /dev/null +++ b/docs/learn/02-understand-the-program-artifact.md @@ -0,0 +1,70 @@ +# 02 — Understand the program artifact + +`ProgramArtifact.v2` is the release-facing execution contract. It makes runtime +scope explicit instead of relying on an unstructured code string. + +## Why it matters + +A release-mode artifact can pin: + +- `sourceKind` +- `executionProfile` +- `abiManifestHash` +- `engineBuildHash` +- `gasVersion` + +Those pins are what let runtimes reject incompatible or stale execution +surfaces before consensus work begins. + +## Prerequisites + +- Complete [01 — Install and run your first script](./01-install-and-run-your-first-script.md) +- `tmp/learn-first-script/program.json` exists + +## Commands + +Inspect the artifact you just built: + +```bash +node tools/blue-quickjs-cli/dist/cli.js inspect \ + --artifact tmp/learn-first-script/program.json +``` + +## Expected output + +You should see a JSON summary with fields similar to: + +- `version` +- `sourceKind` +- `executionProfile` +- `abiId` +- `abiVersion` +- `abiManifestHash` +- `engineBuildHash` (possibly `null` for a local dev artifact) +- `gasVersion` (possibly `null` for a local dev artifact) +- `graphHash` +- `moduleSpecifiers` + +Builder-produced release artifacts should carry explicit +`engineBuildHash` and `gasVersion`. Local development artifacts can omit them, +but they should not be treated as release evidence. + +## What you learned + +- `ProgramArtifact.v2` is the object that binds source, profile, ABI identity, + engine identity, and gas schedule identity together. +- `sourceKind` distinguishes `script` from `module-pack`. +- `executionProfile` is not cosmetic; it is part of the deterministic contract. +- Missing pins are acceptable for local iteration, but not for release-mode + reproducibility claims. + +## Continue + +Next: [03 — Module packs and imports](./03-module-packs-and-imports.md) + +## Troubleshooting + +- If the artifact cannot be inspected, rebuild it with the previous page’s + commands. +- For a schema-level reference, read [ProgramArtifact.v2](../program-artifact-v2.md). +- For profile meanings, read [Execution profiles](../execution-profiles.md). diff --git a/docs/learn/03-module-packs-and-imports.md b/docs/learn/03-module-packs-and-imports.md new file mode 100644 index 0000000..0f79f00 --- /dev/null +++ b/docs/learn/03-module-packs-and-imports.md @@ -0,0 +1,66 @@ +# 03 — Module packs and imports + +BlueQuickjs does not allow runtime fetch/import/network behavior in the +consensus path. Instead, the builder resolves imports ahead of time and emits a +deterministic `ModulePack.v1`. + +That means: + +- imports are part of the build step, +- the module graph is hashed, +- runtime execution is limited to the in-memory pack, +- the same source graph yields the same graph hash across environments. + +## Prerequisites + +- Node.js and `pnpm` installed +- CLI built with `pnpm nx build blue-quickjs-cli` + +## Commands + +Build and inspect the module-pack example that imports a sibling module: + +```bash +mkdir -p tmp/learn-module-pack +node tools/blue-quickjs-cli/dist/cli.js build \ + --entry examples/02-module-pack/entry.js \ + --out tmp/learn-module-pack/program.json +node tools/blue-quickjs-cli/dist/cli.js inspect \ + --artifact tmp/learn-module-pack/program.json +node tools/blue-quickjs-cli/dist/cli.js run \ + --artifact tmp/learn-module-pack/program.json \ + --gas-limit 50000 +``` + +## Expected output + +- `build` should report `compatibilityOk: true`. +- `inspect` should show: + - `sourceKind: "module-pack"` + - a non-null `graphHash` + - module specifiers for `./entry.js` and `./values.js` +- `run` should succeed with: + - `ok: true` + - a deterministic result (`7` for this example) + - deterministic gas usage + +## What you learned + +- Imports are resolved at build time, not consensus-time. +- `ModulePack.v1` is the transport for deterministic static ESM execution. +- The module graph hash is part of what lets other environments verify they are + running the same thing. +- “Imported library” support in BlueQuickjs means prebuilt deterministic packs, + not an open-ended runtime module loader. + +## Continue + +Next: [04 — Promises, async, and microtasks](./04-promises-async-and-microtasks.md) + +## Troubleshooting + +- If the builder rejects a dependency, inspect its diagnostics with + `blue-quickjs compat` or the CLI `build` output. +- If you want the normative schema, read [ModulePack.v1](../module-pack.md). +- For unsupported runtime import behavior, see + [Unsupported features and why](../unsupported-features-and-why.md). diff --git a/docs/learn/04-promises-async-and-microtasks.md b/docs/learn/04-promises-async-and-microtasks.md new file mode 100644 index 0000000..05c4709 --- /dev/null +++ b/docs/learn/04-promises-async-and-microtasks.md @@ -0,0 +1,69 @@ +# 04 — Promises, async, and microtasks + +Promise jobs are intentionally **not** part of the minimal baseline. They are +enabled only in compatibility profiles that explicitly opt into deterministic +job draining. + +Today that means: + +- `baseline-v1` — no Promise jobs / no `queueMicrotask` +- `compat-general-v1` — deterministic Promise jobs and `queueMicrotask` +- `compat-binary-v1` — same as `compat-general-v1`, plus binary support + +## Prerequisites + +- Complete [01 — Install and run your first script](./01-install-and-run-your-first-script.md) +- CLI built with `pnpm nx build blue-quickjs-cli` + +## Commands + +Create and run a Promise-based module under `compat-general-v1`: + +```bash +mkdir -p tmp/learn-promises +printf 'export default (() => Promise.resolve(40).then((value) => value + 2))();\n' > tmp/learn-promises/entry.js +node tools/blue-quickjs-cli/dist/cli.js build \ + --entry tmp/learn-promises/entry.js \ + --profile compat-general-v1 \ + --out tmp/learn-promises/program.json +node tools/blue-quickjs-cli/dist/cli.js run \ + --artifact tmp/learn-promises/program.json \ + --gas-limit 1000000 +``` + +## Expected output + +The artifact build should succeed and the run output should look like: + +```json +{ + "ok": true, + "value": 42, + "gasUsed": "...", + "gasRemaining": "...", + "tapeLength": 0 +} +``` + +If you rebuild the same file under `baseline-v1`, the Promise path should be +rejected or fail deterministically because Promise jobs are not part of that +profile’s contract. + +## What you learned + +- Promise support in BlueQuickjs is **profile-gated**, not ambient. +- Deterministic job draining is part of the compatibility contract for + `compat-general-v1` and `compat-binary-v1`. +- The right question is not “does BlueQuickjs support async?” but + “does this artifact’s profile allow deterministic Promise jobs?” + +## Continue + +Next: [05 — Binary mode and Host.v2](./05-binary-and-host-v2.md) + +## Troubleshooting + +- If the builder reports compatibility issues, make sure the file uses only + Promise/microtask behavior and not timers or dynamic imports. +- For the normative profile definitions, read [Execution profiles](../execution-profiles.md). +- For baseline restrictions, read [Determinism profile](../determinism-profile.md). diff --git a/docs/learn/05-binary-and-host-v2.md b/docs/learn/05-binary-and-host-v2.md new file mode 100644 index 0000000..fe04621 --- /dev/null +++ b/docs/learn/05-binary-and-host-v2.md @@ -0,0 +1,63 @@ +# 05 — Binary mode and Host.v2 + +Binary-heavy deterministic workloads use: + +- `compat-binary-v1` +- DV2 byte encoding +- `Host.v2` + +This keeps byte-oriented boundaries explicit instead of silently widening DV1 or +the baseline profile. + +## Prerequisites + +- Playwright Chromium installed for browser-backed certification commands +- pinned Emscripten environment loaded: + + ```bash + source tools/emsdk/emsdk_env.sh + ``` + +## Commands + +Generate the workload certification report and inspect the binary-oriented +fixtures: + +```bash +pnpm exec playwright install --with-deps chromium +node apps/ecosystem-certifier/scripts/archive-workload-certification-report.mjs \ + --out-dir artifacts/workload-certification \ + --browser chromium +rg "compat-binary-v1|green-base64|green-noble-sha|flagship-knowledge-pack" \ + artifacts/workload-certification -n +``` + +## Expected output + +You should see report matches for fixtures that rely on binary support, such as: + +- `green-base64` +- `green-noble-sha` +- `flagship-knowledge-pack` +- `compat-binary-v1` + +Those report entries prove that the binary path is not just a docs claim — it +is exercised through generated workload evidence. + +## What you learned + +- Binary support is not part of the baseline; it is a versioned compatibility + contract. +- `Host.v2` + DV2 are the deterministic boundary for byte-oriented workloads. +- The best proof that this works is generated workload evidence, not prose. + +## Continue + +Next: [06 — Gas, OOG, and max-gas policies](./06-gas-oog-and-max-gas-policies.md) + +## Troubleshooting + +- If Chromium is missing, rerun the Playwright install command. +- If the certification script fails, run `pnpm nx test ecosystem-certifier` + first to confirm the local certifier environment is healthy. +- For the normative value-model rules, read [Value model v2 (DV2)](../value-model-v2.md). diff --git a/docs/learn/06-gas-oog-and-max-gas-policies.md b/docs/learn/06-gas-oog-and-max-gas-policies.md new file mode 100644 index 0000000..1a82821 --- /dev/null +++ b/docs/learn/06-gas-oog-and-max-gas-policies.md @@ -0,0 +1,59 @@ +# 06 — Gas, OOG, and max-gas policies + +In BlueQuickjs, gas is not an approximate UI metric. It is part of the +deterministic execution contract, and the exact OOG boundary is a release gate +for consensus-safe executors. + +## Prerequisites + +- Pinned Emscripten environment loaded: + + ```bash + source tools/emsdk/emsdk_env.sh + ``` + +- Playwright Chromium installed + +## Commands + +Generate the workload OOG-boundary report and inspect the canonical loop +fixture: + +```bash +pnpm exec playwright install --with-deps chromium +node apps/ecosystem-certifier/scripts/run-oog-boundary-certification.mjs \ + --out-dir artifacts/workload-certification \ + --browser chromium +rg "loop-10k|firstSuccessGas|lastFailureGas|failureCode" \ + artifacts/workload-certification/oog-boundaries.json -n +``` + +## Expected output + +You should see entries for `loop-10k` including: + +- `firstSuccessGas` +- `lastFailureGas` +- failure code information (for example `OOG`) + +The important property is not just “fails when gas is low” but that the +boundary is **exact and reproducible**. + +## What you learned + +- Gas values are deterministic release evidence, not advisory counters. +- The exact success/failure boundary is part of the consensus contract. +- Max-gas policy should be treated as a pinned operational rule, not a fuzzy + runtime heuristic. + +## Continue + +Next: [07 — Verify release evidence](./07-verify-release-evidence.md) + +## Troubleshooting + +- If the boundary script fails, confirm `pnpm nx run ecosystem-certifier:e2e` + is green first. +- If you want the full gas specification, read [Gas schedule](../gas-schedule.md). +- If you want a human summary of current release evidence, read + [Release-readiness report](../release-readiness-report.md). diff --git a/docs/learn/07-verify-release-evidence.md b/docs/learn/07-verify-release-evidence.md new file mode 100644 index 0000000..f406fa4 --- /dev/null +++ b/docs/learn/07-verify-release-evidence.md @@ -0,0 +1,49 @@ +# 07 — Verify release evidence + +BlueQuickjs uses generated release evidence so auditors and operators can check +that the current branch or release bundle matches deterministic reality. + +## Prerequisites + +- Complete the toolchain setup from + [01 — Install and run your first script](./01-install-and-run-your-first-script.md) + +## Commands + +Synthesize a local release evidence bundle and verify it: + +```bash +pnpm release-evidence:synthesize -- --out-dir artifacts/release-evidence +pnpm release-evidence:verify -- --evidence-dir artifacts/release-evidence +``` + +## Expected output + +- The synthesize step should create: + - `release-evidence-summary.json` + - `release-evidence-summary.md` + - `release-evidence-manifest.json` + - `*.sha256` + - `*.sig` +- The verify step should exit successfully after checking: + - manifest entries, + - checksums, + - signature payloads, + - branch/date expectations when provided. + +## What you learned + +- Release evidence is a generated bundle, not a hand-written checklist. +- Verification checks both integrity (checksums/signatures) and release context. +- The release evidence bundle ties together consensus, workload, and + consumer-proof artifacts. + +## Continue + +Next: [08 — Build a real example](./08-build-a-real-example.md) + +## Troubleshooting + +- If synthesis reports stale docs, regenerate the affected reports and rerun. +- If verification fails, inspect the manifest paths and checksum sidecars first. +- For the trust model, read [Release provenance and trust model](../release-provenance.md). diff --git a/docs/learn/08-build-a-real-example.md b/docs/learn/08-build-a-real-example.md new file mode 100644 index 0000000..136896a --- /dev/null +++ b/docs/learn/08-build-a-real-example.md @@ -0,0 +1,71 @@ +# 08 — Build a real example + +This page walks a real example from source files to deterministic artifact to +runtime execution. + +We will use the kitchen-sink example because it exercises: + +- module-pack imports, +- host calls, +- Promise job draining, +- `queueMicrotask`, +- stable sort behavior, +- deterministic tape emission. + +## Prerequisites + +- CLI built with `pnpm nx build blue-quickjs-cli` +- toolchain environment loaded: + + ```bash + source tools/emsdk/emsdk_env.sh + ``` + +## Commands + +Build, inspect, and run the kitchen-sink example: + +```bash +mkdir -p tmp/learn-kitchen-sink +node tools/blue-quickjs-cli/dist/cli.js build \ + --entry examples/09-kitchen-sink/entry.js \ + --profile compat-general-v1 \ + --out tmp/learn-kitchen-sink/program.json +node tools/blue-quickjs-cli/dist/cli.js inspect \ + --artifact tmp/learn-kitchen-sink/program.json +node tools/blue-quickjs-cli/dist/cli.js run \ + --artifact tmp/learn-kitchen-sink/program.json \ + --gas-limit 1000000 +``` + +## Expected output + +- `build` should succeed with `compatibilityOk: true`. +- `inspect` should show: + - `sourceKind: "module-pack"` + - `executionProfile: "compat-general-v1"` + - a non-null `graphHash` + - multiple module specifiers +- `run` should return a success payload with: + - a structured object value, + - deterministic gas numbers, + - non-zero tape or host interaction metadata when appropriate. + +## What you learned + +- Real examples are still built as deterministic artifacts, not special cases. +- The profile pin matters when imported code uses Promise or microtask behavior. +- Host calls, module graphs, and gas accounting stay visible all the way through + execution. + +## Continue + +Next: [09 — Production embedder checklist](./09-production-embedder-checklist.md) + +## Troubleshooting + +- If the build fails, check whether the selected profile matches the example’s + capabilities. +- If the run fails, inspect the artifact first and confirm the example was built + under `compat-general-v1`. +- For the source corpus overview, read [`examples/README.md`](../../examples/README.md). diff --git a/docs/learn/09-production-embedder-checklist.md b/docs/learn/09-production-embedder-checklist.md new file mode 100644 index 0000000..47d03e1 --- /dev/null +++ b/docs/learn/09-production-embedder-checklist.md @@ -0,0 +1,50 @@ +# 09 — Production embedder checklist + +This final page turns the learning path into operational rules for real +deployments. + +## Prerequisites + +- Complete [07 — Verify release evidence](./07-verify-release-evidence.md) +- Read [Consensus-safe vs diagnostic-only](../consensus-safe-vs-diagnostic-only.md) + +## Commands + +Run the most important local release/consumer checks: + +```bash +pnpm release-evidence:verify -- --evidence-dir artifacts/release-evidence +pnpm workload:check-public-package-versions +pnpm workload:check-pack-manifests -- --out-dir artifacts/consumer-proof/pack-manifests +``` + +## Expected output + +- Release evidence verification should pass without checksum/signature errors. +- Public package version alignment should pass. +- Pack manifest validation should emit a deterministic manifest summary in + `artifacts/consumer-proof/pack-manifests`. + +## What you learned + +- Production embedders should pin: + - `engineBuildHash` + - `gasVersion` + - ABI manifest hash + - execution profile +- Production release confidence comes from generated evidence and rehearsed + packaging flows, not from ad hoc local runs. +- Consensus-safe deployment guidance is narrower than the full repo surface. + +## Continue + +Next: return to the [documentation hub](../README.md), then revisit the full +[Production embedder checklist](../production-embedder-checklist.md) and +[Release checklist](../release-checklist.md). + +## Troubleshooting + +- If verification fails, regenerate the evidence bundle and retry before + changing any release metadata manually. +- If package version alignment fails, fix the public package manifests before + attempting a release rehearsal. diff --git a/docs/learn/README.md b/docs/learn/README.md new file mode 100644 index 0000000..bf70743 --- /dev/null +++ b/docs/learn/README.md @@ -0,0 +1,44 @@ +# Learn BlueQuickjs + +This path is for readers who want more than the root README quickstart but less +than the full reference set. + +## Recommended Path + +1. [What is BlueQuickjs?](./00-what-is-bluequickjs.md) +2. [Install and run your first script](./01-install-and-run-your-first-script.md) +3. [Understand the program artifact](./02-understand-the-program-artifact.md) +4. [Build a real example](./08-build-a-real-example.md) +5. [Production embedder checklist](./09-production-embedder-checklist.md) + +## Topic Deep Dives + +Read these when the topic matters to your integration: + +- [Module packs and imports](./03-module-packs-and-imports.md) +- [Promises, async, and microtasks](./04-promises-async-and-microtasks.md) +- [Binary mode and Host.v2](./05-binary-and-host-v2.md) +- [Gas, OOG, and max-gas policies](./06-gas-oog-and-max-gas-policies.md) +- [Verify release evidence](./07-verify-release-evidence.md) + +## References + +- [Core concepts](../concepts.md) +- [Architecture overview](../architecture-overview.md) +- [Glossary](../glossary.md) +- [FAQ](../faq.md) +- [Unsupported features and why](../unsupported-features-and-why.md) +- [Consensus-safe vs diagnostic-only](../consensus-safe-vs-diagnostic-only.md) + +## What This Path Teaches + +By the end of the recommended path you should be able to: + +- explain the current consensus-safe scope, +- run deterministic scripts in wasm, +- understand how `ProgramArtifact.v2` pins engine, profile, gas, and ABI + identity, +- use module packs instead of runtime imports, +- inspect exact gas and OOG boundaries, +- verify generated release evidence, +- embed BlueQuickjs safely in production. diff --git a/docs/module-pack.md b/docs/module-pack.md new file mode 100644 index 0000000..fb25df2 --- /dev/null +++ b/docs/module-pack.md @@ -0,0 +1,100 @@ +# ModulePack.v1 + +Baseline anchors: + +- `docs/baseline-1.md` +- `docs/baseline-2.md` + +`ModulePack.v1` is the canonical reusable source-module artifact for deterministic +runtime execution. + +## Schema (normative) + +```ts +type ModulePackV1 = { + version: 1; + entrySpecifier: string; + entryExport?: string; // default: "default" + modules: ModuleRecord[]; + graphHash: string; // lowercase sha256 hex, 64 chars + builderVersion: string; + dependencyIntegrity: string; // lowercase sha256 hex, 64 chars + diagnosticsMeta?: Record; // non-hashed metadata only +}; + +type ModuleRecord = { + specifier: string; + source: string; + sourceMap?: string; // canonical source map JSON string + originMeta?: { + packageName?: string; + packageVersion?: string; + integrity?: string; // optional lowercase sha256 hex, 64 chars + originalPath?: string; // diagnostics only; never hashed + }; +}; +``` + +## Deterministic requirements + +### 1) Canonical module ordering + +`modules` MUST be sorted by canonical `specifier` byte order (UTF-8, ascending). + +### 2) Source normalization + +- Module source MUST use LF (`\n`) line endings. +- Trailing line ending normalization MUST be deterministic. + +### 3) Specifier normalization + +- All specifiers MUST use `/` separators. +- No absolute OS paths. +- Relative imports MUST be canonicalized during build. +- Bare package imports MUST be resolved at build time to canonical internal + specifiers. + +### 4) Hash independence from machine/checkout + +Hashed content MUST NOT include: + +- absolute paths, +- host OS path separators, +- timestamps, +- nondeterministic build metadata. + +### 5) Graph hash + +`graphHash = sha256(canonical_module_pack_bytes)` + +Where canonical bytes are produced from the ordered module list and normalized +fields only (excluding non-hashed diagnostics metadata). + +## Runtime loader contract + +When a runtime executes `sourceKind: "module-pack"`: + +- only module records in the pack are loadable, +- relative imports resolve within the pack graph, +- cyclic imports and live bindings MUST follow static ESM semantics, +- entry module namespace is queried for `entryExport` (default `"default"`), +- result is DV/DV2-encoded according to selected ABI/value-model version. + +## Deterministic error codes + +- `MODULE_PACK_HASH_MISMATCH` +- `MODULE_SPECIFIER_NOT_FOUND` +- `MODULE_EXPORT_MISSING` +- `MODULE_RESOLUTION_ERROR` +- `MODULE_EVALUATION_ERROR` + +## Source maps + +- `sourceMap` values MUST be canonical JSON and path-clean (no absolute paths in + hashed payloads). +- Path rewriting rules are specified in `docs/builder.md`. + +## See also + +- `docs/program-artifact-v2.md` +- `docs/builder.md` diff --git a/docs/observability.md b/docs/observability.md index b361b0a..89bcc4c 100644 --- a/docs/observability.md +++ b/docs/observability.md @@ -126,17 +126,31 @@ Or (lower-level): See: [SDK usage](./sdk.md). -### What it does *not* include +### Host-call trace coverage -The trace does **not** include host-call gas. Host calls are billed against the VM gas counter, but they are accounted separately. +The trace includes dedicated host-call counters: -If you want to estimate host-call gas from an `EvaluateResult` that includes a trace: +- `hostCallPreCount` / `hostCallPreGas` +- `hostCallPostCount` / `hostCallPostGas` -``` -hostCallGas ≈ gasUsed - (opcodeGas + arrayCbGas + allocationGas + jsonParseGas + jsonStringifyGas + gcCheckpointGas) -``` +So host-call charging can be attributed directly without deriving a residual from +total gas usage. -The exact accounting and the checkpoint behavior are described in [Gas schedule](./gas-schedule.md). +Allocation trace now reports both `requestedBytes` and charged `bytes` so +allocator-model drift can be separated from canonical gas charging. + +### Charge-event tape (debug mode) + +For first-divergence debugging, deterministic runtimes can enable a fixed-size +gas charge-event tape: + +- preallocated ring buffer (`JS_EnableGasChargeTape(ctx, capacity)`), +- no dynamic allocation while appending events, +- event fields include `siteId`, `kind`, `flags`, `amount`, optional + `logicalUnits`, and `gasBefore` / `gasAfter`. + +This tape is diagnostic-only and should not be treated as a release API +stability guarantee. ### Interpreting trace output @@ -170,5 +184,4 @@ They are safe to include in golden tests and reproducibility baselines (see fixt - [SDK usage](./sdk.md) (how to turn these on) - [Host call ABI](./host-call-abi.md) (tape details and ABI mechanics) - [Gas schedule](./gas-schedule.md) (what is metered and trace semantics) -- [Implementation summary](./implementation-summary.md) (how it all fits together) - +- [Core concepts](./concepts.md) (how it all fits together) diff --git a/docs/playground-recipes.md b/docs/playground-recipes.md new file mode 100644 index 0000000..6c89a80 --- /dev/null +++ b/docs/playground-recipes.md @@ -0,0 +1,86 @@ +# Playground recipes + +These recipes map common learning tasks to concrete playground actions. + +## 1. Run your first script + +1. Open the playground. +2. Leave the default **Gallery** selection on **Basic deterministic script**. +3. Click **Run current selection**. +4. Open the **Result** tab and inspect: + - result hash + - gas used + - gas remaining + +What this teaches: + +- how the browser runtime reports deterministic success, +- what an evidence-backed happy-path run looks like. + +## 2. Run a Promise example + +1. Choose **Promises / async / microtasks** from the gallery. +2. Confirm the profile is `compat-general-v1`. +3. Click **Run current selection**. +4. Open the **Determinism evidence** tab and confirm the browser run matches the + certified snapshot. + +What this teaches: + +- Promise jobs are profile-gated, +- `compat-general-v1` is the right profile for deterministic async support. + +## 3. Run a library/module-pack example + +1. Choose **Standard ESM module-pack** or **Real npm library reuse**. +2. Click **Run current selection**. +3. Open the **Metadata** tab and inspect: + - `sourceKind` + - module graph hash + - execution profile + +What this teaches: + +- imports are resolved into deterministic module packs ahead of execution, +- the runtime is executing a pinned artifact, not fetching modules live. + +## 4. Inspect a red deterministic failure + +1. Scroll to **Red fixtures** in the left rail. +2. Choose a fixture such as **dynamic import must be rejected at build stage**. +3. Open the **Determinism evidence** tab. +4. Read the failure stage and diagnostics. + +What this teaches: + +- unsupported behavior is surfaced explicitly, +- deterministic failures are part of the product, not hidden edge cases. + +## 5. Inspect a max-gas boundary + +1. Choose **Max-gas policy / OOG boundary**. +2. Click **Find OOG boundary**. +3. Open the **Determinism evidence** tab. +4. Inspect: + - `firstSuccessGas` + - `lastFailureGas` + - failure code/tag + +What this teaches: + +- exact OOG boundaries are visible and reproducible, +- gas policy is part of deterministic release evidence. + +## 6. Inspect a Host.v2 bytes roundtrip + +1. Choose **Binary / typed arrays / Host.v2 DV2**. +2. Click **Run current selection**. +3. Open the **Host + tape** tab. +4. Inspect the host payload previews and tape metadata. + +What this teaches: + +- `compat-binary-v1` and `Host.v2` are how byte-oriented workloads cross the + host boundary, +- the playground exposes both high-level result data and host interaction + evidence. diff --git a/docs/playground.md b/docs/playground.md new file mode 100644 index 0000000..9e68d50 --- /dev/null +++ b/docs/playground.md @@ -0,0 +1,184 @@ +# BlueQuickjs Playground + +The in-repo playground is the canonical interactive demo surface for the +wasm-consensus product. + +It is designed to help new engineers: + +- run deterministic JavaScript in the browser, +- inspect result/error, gas, and tape outputs, +- understand execution profiles, +- compare a browser run against certified evidence, +- inspect exact OOG boundaries, +- learn what is consensus-safe vs diagnostic-only. + +## What the playground is for + +Use it when you want a high-signal, evidence-backed browser experience without +leaving the repo. + +The playground is especially useful for: + +- onboarding, +- release review demos, +- teaching profiles and pins, +- validating that a certified example still matches generated evidence. + +## What runs live + +### Script mode + +The playground can execute raw deterministic snippets live in the browser using +`ProgramArtifact.v2` script mode. + +This is best for: + +- small deterministic examples, +- quick gas/result experiments, +- understanding profile differences. + +### Certified example mode + +The playground also ships prebuilt/certified artifacts for: + +- the 10 canonical example categories, +- selected green ecosystem fixtures, +- selected red deterministic-failure fixtures, +- the flagship workload entry. + +These examples are backed by generated JSON produced from in-repo fixtures and +runtime/build tooling. + +## What uses prebuilt artifacts + +The playground does **not** try to be a full npm-in-browser bundler. + +For module-pack and library examples it uses: + +- deterministic builder output, +- generated `ProgramArtifact.v2` payloads, +- certified evidence snapshots, +- generated OOG-boundary data. + +That keeps the demo aligned with deterministic reality rather than inventing a +separate browser-only toolchain. + +## Run it locally + +```bash +bash tools/scripts/prepare-quickjs-source.sh +bash tools/scripts/setup-emsdk.sh +bash apps/bluequickjs-playground/scripts/dev.sh +``` + +Open: + +- `http://localhost:4325` + +The dev script does three important things for a fresh checkout: + +1. sources the pinned Emscripten environment, +2. builds the workspace libraries the playground depends on, +3. regenerates the playground’s evidence-backed JSON before starting Vite. + +## Core UI areas + +### Gallery and run-mode controls + +The left side lets you switch between: + +- Gallery +- Script +- Artifact JSON + +It also exposes: + +- execution profile selection, +- gas-limit presets, +- host preset selection, +- run action, +- exact OOG search, +- artifact/evidence export. + +### Editor + +The editor uses Monaco and adapts to the current mode: + +- read-only source view for certified gallery examples, +- editable JavaScript in script mode, +- editable JSON in artifact-import mode. + +### Result and evidence panel + +The right side shows: + +- result or error, +- gas used / remaining, +- result hash and tape hash, +- `engineBuildHash`, +- `gasVersion`, +- `executionProfile`, +- `sourceKind`, +- module graph hash where applicable, +- current/certified evidence comparison. + +### Host and tape panel + +The playground wraps its deterministic mock hosts to show: + +- request inputs, +- response payload previews, +- units charged, +- tape metadata emitted by the runtime. + +## Import/export behavior + +- **Export artifact** downloads the current `ProgramArtifact.v2`. +- **Export run evidence** downloads the current browser run snapshot. +- **Artifact JSON mode** lets you paste an artifact and execute it with the + selected host preset. + +## Inspecting OOG boundaries + +For supported examples, the **Find OOG boundary** action performs a deterministic +binary search over gas limits and displays: + +- `firstSuccessGas` +- `lastFailureGas` +- success/failure gas used +- success/failure gas remaining +- failure code/tag + +## Comparing to certified evidence + +When an example is backed by generated evidence, the playground can show: + +- certified snapshot, +- current browser run snapshot, +- a match/diff summary, +- source report reference, +- precomputed OOG boundary when available. + +## Red fixture behavior + +Red fixtures are intentionally educational. They explain: + +- whether rejection happens at build or runtime, +- which deterministic rule is involved, +- where to read more in the docs. + +The playground never tries to “paper over” those failures. + +## Limitations + +- Consensus-safe scope is still wasm-only (`wasm-node` vs `wasm-browser`). +- Native remains diagnostic-only. +- Runtime fetch/import/network behavior is intentionally unsupported. +- The playground is a deterministic learning/demo surface, not a general npm + IDE or browser bundler. + +## See also + +- [Playground recipes](./playground-recipes.md) +- [Learning path](./learn/README.md) +- [Consensus-safe vs diagnostic-only](./consensus-safe-vs-diagnostic-only.md) diff --git a/docs/production-embedder-checklist.md b/docs/production-embedder-checklist.md new file mode 100644 index 0000000..e104aa3 --- /dev/null +++ b/docs/production-embedder-checklist.md @@ -0,0 +1,53 @@ +# Production embedder checklist + +Use this checklist before embedding BlueQuickjs in production consensus flows. + +## A) Deterministic pinning + +- [ ] Pin `engineBuildHash`. +- [ ] Pin `gasVersion`. +- [ ] Pin ABI manifest hash. +- [ ] Pin execution profile per workload (`baseline-v1` / `compat-*`). +- [ ] Keep consensus-safe scope explicit: `wasm-node` vs `wasm-browser` + (`wasm32` release engine only). + +## B) Runtime contract enforcement + +- [ ] Enforce strict parity acceptance on required consensus executors. +- [ ] Enforce exact OOG boundary parity checks. +- [ ] Treat native output as diagnostic-only unless explicitly promoted. + +## C) Host ABI discipline + +- [ ] Route all host capabilities through manifest-defined Host ABI calls. +- [ ] Reject undocumented host functions/surfaces. +- [ ] Keep deterministic failure-stage expectations for unsupported behavior. + +## D) Release evidence validation + +- [ ] Verify `release-evidence-manifest.json`. +- [ ] Verify checksums for all listed artifacts. +- [ ] Verify detached signatures (`*.sig`) using trusted key material. +- [ ] Record manifest hash and parity summary in release go/no-go template. +- [ ] Run the local auditor command: + `pnpm release-evidence:verify -- --evidence-dir artifacts/release-evidence` + +## E) Security/supply chain + +- [ ] Generate and archive SBOM (`pnpm release-evidence:sbom`). +- [ ] Generate and archive dependency license report (`pnpm release-evidence:licenses`). +- [ ] Review signature rotation / rollback runbook. + +## F) Operational readiness + +- [ ] Run consumer-proof matrix (Node 22 and multi-OS). +- [ ] Run registry-style publish rehearsal. +- [ ] Run tarball-based consumer rehearsal. +- [ ] Confirm docs/release notes match shipped consensus-safe scope. +- [ ] Keep the in-repo playground aligned with certified evidence and docs. + +## Reference docs + +- [Consensus-safe vs diagnostic-only](./consensus-safe-vs-diagnostic-only.md) +- [Release checklist](./release-checklist.md) +- [Playground](./playground.md) diff --git a/docs/program-artifact-v2.md b/docs/program-artifact-v2.md new file mode 100644 index 0000000..56fc44c --- /dev/null +++ b/docs/program-artifact-v2.md @@ -0,0 +1,97 @@ +# ProgramArtifact.v2 + +Baseline anchors: + +- `docs/baseline-1.md` (determinism + canonical gas) +- `docs/baseline-2.md` (manifest-locked host ABI + DV boundary) + +This document defines the **versioned execution artifact** consumed by runtimes +and produced by the deterministic builder. + +## Goals + +- Replace ambiguous “just a code string” payloads with explicit execution modes. +- Make profile and engine pinning explicit. +- Support script mode and first-class module-pack mode under one schema. + +## Schema (normative) + +```ts +type ProgramArtifactV2 = { + version: 2; + abiId: string; // e.g. "Host.v1" or "Host.v2" + abiVersion: number; // uint32 + abiManifestHash: string; // lowercase sha256 hex, 64 chars + engineBuildHash?: string; // lowercase sha256 hex, 64 chars + gasVersion?: number; // uint32, required for release-mode artifacts + executionProfile: ExecutionProfileName; + sourceKind: 'script' | 'module-pack'; + source: ScriptSource | ModulePackSource; +}; + +type ScriptSource = { + code: string; +}; + +type ModulePackSource = { + modulePack: ModulePackV1; +}; +``` + +## Field rules + +- `version` MUST be `2`. +- `executionProfile` is required. Release artifacts MUST NOT rely on implicit defaults. +- `sourceKind` and `source` shape MUST match. +- `engineBuildHash`: + - REQUIRED for builder-produced release artifacts. + - MAY be omitted only for local development/debug workflows that do not claim + reproducible release semantics. +- `gasVersion`: + - REQUIRED for builder-produced release artifacts. + - MUST match the runtime gas schedule version, otherwise execution must be + rejected in release mode. + +## Execution semantics + +### `sourceKind: "script"` + +- Evaluated as deterministic global script mode. +- Result is the final expression value (DV-encodable). + +### `sourceKind: "module-pack"` + +- Evaluated through deterministic in-memory static module loading from + `ModulePack.v1` only. +- No runtime filesystem/network/module registry lookups. +- Entry resolution is driven by the module-pack entry fields. + +## Validation failures (normative categories) + +- `PROGRAM_ARTIFACT_INVALID` +- `PROGRAM_SOURCE_KIND_MISMATCH` +- `PROGRAM_PROFILE_REQUIRED` +- `PROGRAM_ENGINE_HASH_REQUIRED` (for build outputs) + +Module-pack specific runtime errors are specified in `docs/module-pack.md`. + +## Canonicalization and hashing guidance + +`ProgramArtifact.v2` itself is typically transported as JSON-like host data, but +its pinned fields (`abiManifestHash`, `engineBuildHash`, `modulePack.graphHash`) +MUST be computed from canonical byte representations defined in their respective +specs. + +## Relationship to v1 artifacts + +- v1 (`code` + ABI pins) remains supported only as a compatibility input path. +- New builder output target is v2. +- New features (module-pack execution, composite profiles, DV2/Host.v2) are + specified against v2. + +## See also + +- `docs/module-pack.md` +- `docs/execution-profiles.md` +- `docs/builder.md` +- `docs/value-model-v2.md` diff --git a/docs/release-checklist.md b/docs/release-checklist.md index 8237d58..b399a58 100644 --- a/docs/release-checklist.md +++ b/docs/release-checklist.md @@ -6,16 +6,84 @@ Scope: steps to publish deterministic engine + ABI packages. - Confirm the working tree is clean and `vendor/quickjs` is pinned to the intended commit. - Run `pnpm lint`, `pnpm nx typecheck`, `pnpm nx test`, and `pnpm nx build`. +- Confirm release-facing docs still state the consensus-safe scope correctly: + - `wasm-node` vs `wasm-browser` + - canonical `wasm32` release engine + - native remains diagnostic-only +- Run strict parity gating for consensus executors (`wasm-node` vs + `wasm-browser`) with raw gas equality (no gas-delta baseline normalization). +- Verify gas schedule docs are synchronized with the canonical spec source: + - `pnpm gas-spec:test` + - `node tools/gas-spec/render-gas-artifacts.mjs --check` +- Enforce critical package coverage thresholds. The current accepted minimum is + 40% for lines, branches, functions, and statements across + `quickjs-runtime`, `deterministic-bundler`, `deterministic-builder`, + `abi-manifest`, `blue-quickjs-cli`, and `ecosystem-certifier`. + - `pnpm test:coverage:critical` +- Verify OOG boundary parity checks are green for the consensus fixture corpus. + - `pnpm nx test test-harness` (includes wasm/native boundary search fixtures in + `libs/test-harness/src/lib/gas-equivalence.spec.ts`). + - `pnpm nx run smoke-web:e2e` (includes browser/node boundary parity in + `apps/smoke-web/tests/gas-boundaries.spec.ts`). +- Archive reproducibility report artifacts for the release candidate: + - Consensus release gate reports (wasm-node vs wasm-browser) are required. + - `node tools/consensus-parity/scripts/archive-consensus-reproducibility-report.mjs --out-dir artifacts/reproducibility-consensus/chromium --browser chromium` + - `node tools/consensus-parity/scripts/archive-consensus-reproducibility-report.mjs --out-dir artifacts/reproducibility-consensus/firefox --browser firefox` + - Native report generation is diagnostic by default: + - `node tools/quickjs-native-harness/scripts/archive-reproducibility-report.mjs` + - If native is explicitly promoted to a consensus executor for this release, + require strict native report generation: + - `node tools/quickjs-native-harness/scripts/archive-reproducibility-report.mjs --strict` + - Preserve both generated report JSON and matching `.sha256` sidecars. +- Run workload/ecosystem certification reports: + - `node apps/ecosystem-certifier/scripts/check-builder-determinism.mjs --out-dir artifacts/workload-certification` + - `node tools/workload-certification/compare-builder-determinism-matrix.mjs --input-dir artifacts` + - `node apps/ecosystem-certifier/scripts/archive-workload-certification-report.mjs --out-dir artifacts/workload-certification` + - `node apps/ecosystem-certifier/scripts/generate-compatibility-delta-report.mjs --current-dir artifacts/workload-certification --out-dir artifacts/workload-certification` + - `node apps/ecosystem-certifier/scripts/run-oog-boundary-certification.mjs --out-dir artifacts/workload-certification` + - `node apps/ecosystem-certifier/scripts/run-repeatability-certification.mjs --out-dir artifacts/workload-certification --iterations 100 --flagship-iterations 40` + - `node apps/ecosystem-certifier/scripts/run-seeded-property-corpus.mjs --out-dir artifacts/workload-certification --seed-count 80` +- Run downstream tarball consumer reproducibility proof: + - Version alignment + pack manifest checks: + - `pnpm workload:check-public-package-versions` + - `pnpm workload:check-pack-manifests -- --out-dir artifacts/consumer-proof/pack-manifests` + - Primary registry-style rehearsal: + - `pnpm publish-rehearsal:verdaccio -- --out-dir artifacts/consumer-proof/verdaccio` + - Secondary tarball rehearsal: + - `node tools/workload-certification/pack-public-tarballs.mjs --out-dir artifacts/consumer-proof/tarballs` + - `pnpm --dir e2e/consumer-proof-app run install:tarballs -- --tarball-dir ../../artifacts/consumer-proof/tarballs` + - `pnpm --dir e2e/consumer-proof-app exec playwright install --with-deps chromium` + - `pnpm --dir e2e/consumer-proof-app run repro` +- Synthesize release evidence bundle (manifest + summaries + checksums + signatures): + - `pnpm release-evidence:synthesize -- --out-dir artifacts/release-evidence` +- Verify release evidence bundle locally (auditor command): + - `pnpm release-evidence:verify -- --evidence-dir artifacts/release-evidence` +- Confirm the release evidence manifest exists and is complete: + - `artifacts/release-evidence/release-evidence-manifest.json` +- Generate security/supply-chain artifacts: + - `pnpm release-evidence:sbom -- --out-dir artifacts/security` + - `pnpm release-evidence:licenses -- --out-dir artifacts/security` +- Refresh playground generated data and ensure it is not stale: + - `node apps/bluequickjs-playground/scripts/generate-playground-data.mjs` + - `node apps/bluequickjs-playground/scripts/generate-playground-data.mjs --check` ## Wasm build + metadata - Run `pnpm nx build quickjs-wasm-build`. - Verify `libs/quickjs-wasm-build/dist/quickjs-wasm-build.metadata.json`: - `engineBuildHash` is present. + - `gasVersion` is present and matches the release gas schedule. - `variants.wasm32.release.engineBuildHash` matches `sha256` of `quickjs-eval.wasm`. - Run `pnpm nx build quickjs-wasm` and confirm `libs/quickjs-wasm/dist/wasm` contains wasm, loader, and metadata assets. +## Parity policy checks + +- Confirm release workflows do **not** depend on + `tools/quickjs-native-harness/scripts/parity-gas-delta-baseline.json`. +- Diagnostic parity deltas may be retained for investigation workflows, but they + must not be part of release acceptance. + ## Manifest + fixtures - If the manifest changed: @@ -36,3 +104,9 @@ Scope: steps to publish deterministic engine + ABI packages. - Publish the five packages from their package roots after build (dist/ is included in `files`). - Tag the release and record the engine build hash + manifest hash in the release notes. + +## Reference docs + +- [Release-readiness report](./release-readiness-report.md) +- [Production embedder checklist](./production-embedder-checklist.md) +- [Playground](./playground.md) diff --git a/docs/release-policy.md b/docs/release-policy.md index 47c496f..1b65398 100644 --- a/docs/release-policy.md +++ b/docs/release-policy.md @@ -2,6 +2,39 @@ Scope: define publishing and versioning policy so consumers can pin engine + ABI deterministically (Baseline #1 §1A; Baseline #2 §7). +## Gas closure policy (release-critical) + +Gas is part of the deterministic consensus contract, not a benchmark hint. +Release gating therefore requires: + +- exact result/error/tape parity, +- exact gas used/remaining parity, and +- exact out-of-gas boundary parity + +across all supported **consensus executors**. + +Consensus executor matrix: + +- mandatory: `wasm-node` vs `wasm-browser` using pinned canonical `wasm32` + artifacts. +- required browser engines for release-candidate/release parity evidence: + - Chromium + - Firefox +- WebKit runs as scheduled diagnostic evidence unless explicitly promoted to a + required gate. +- native harness parity is required only when native is explicitly declared a + supported consensus executor for that release. + +`--gas-delta-baseline` style reconciliation artifacts are diagnostic tools only +and are never an acceptable release gate. + +Release candidates must archive signed strict-parity reproducibility reports +(parity report JSON signature + file checksum) for auditability. +The repository command for the consensus wasm-node/wasm-browser report is: +`node tools/consensus-parity/scripts/archive-consensus-reproducibility-report.mjs`. +Native reproducibility reports remain diagnostic by default; use strict +assertion mode only when native is explicitly promoted to a consensus executor. + ## Published packages - `@blue-quickjs/dv`: DV encode/decode + validation (pure TS). @@ -21,9 +54,27 @@ A deterministic program artifact `P` should pin: - `abiId`, `abiVersion` - `abiManifestHash` (sha256 of canonical manifest bytes) -- `engineBuildHash` (optional but strongly recommended) +- `executionProfile` (explicit, versioned profile name) +- `gasVersion` (required for release-mode artifacts) +- `engineBuildHash` (required for builder-produced release artifacts) `@blue-quickjs/quickjs-runtime` validates these fields and rejects mismatches when provided. +In `releaseMode`, embedders must pass an expected execution profile pin +(`expectedExecutionProfile`) so runtime execution fails on profile mismatches. + +For release-mode execution, `engineBuildHash`, `gasVersion`, and +`executionProfile` are required pins. + +For `ProgramArtifact.v2` module-pack outputs, pinning should additionally include: + +- `sourceKind` (`script` vs `module-pack`) +- `modulePack.graphHash` when `sourceKind = "module-pack"` + +See: + +- `docs/program-artifact-v2.md` +- `docs/module-pack.md` +- `docs/execution-profiles.md` ## engine_build_hash @@ -32,9 +83,16 @@ Definition: - `engineBuildHash = sha256(wasm_bytes)` for a given variant + buildType. - Lowercase hex, 64 characters. +`gasVersion` definition: + +- Monotonic integer identifying the canonical gas schedule semantics. +- Any semantic gas-schedule change (including allocation charging model changes) + requires an explicit gasVersion bump. + Exposure: - `quickjs-wasm-build.metadata.json` includes: + - top-level `gasVersion` for runtime/artifact gas pin validation. - `variants...engineBuildHash` for every emitted artifact. - Top-level `engineBuildHash`, set to the canonical engine hash (`wasm32` + `release`) when present. - `@blue-quickjs/quickjs-wasm` exposes these values via `loadQuickjsWasmMetadata()` and @@ -89,6 +147,13 @@ New `engineBuildHash` is required when: memory sizing, toolchain version, or build flags alters the wasm bytes. - Rebuilding with different Emscripten/flags also produces a new hash. +New `gasVersion` is required when: + +- Any change can alter canonical gas used/remaining or OOG boundaries for the + same `(P, I, G)`. +- This includes changes to opcode charges, builtin charges, host-call charging, + allocation charging model, or GC checkpoint charging semantics. + New `abiManifestHash` is required when: - Any manifest field changes: function list, `fn_id`, `js_path`, `arg_schema`, diff --git a/docs/release-provenance.md b/docs/release-provenance.md new file mode 100644 index 0000000..fa27420 --- /dev/null +++ b/docs/release-provenance.md @@ -0,0 +1,60 @@ +# Release provenance and trust model + +This document defines what release evidence is signed, how checksums are +produced, and how operators should validate trust before accepting a release. + +## Signed artifacts + +The release workflow generates a release-evidence bundle containing: + +- `release-evidence-summary.json` +- `release-evidence-summary.md` +- `release-evidence-manifest.json` +- `*.sha256` sidecars +- `*.sig` detached signature payloads +- copied source evidence inputs (consensus/workload/consumer reports) + +Generation command: + +```bash +pnpm release-evidence:synthesize -- --out-dir artifacts/release-evidence +``` + +Verification command: + +```bash +pnpm release-evidence:verify -- --evidence-dir artifacts/release-evidence +``` + +## Checksum model + +- SHA-256 is used for all artifact checksum entries. +- Manifest entries include per-file `sha256` and relative path. +- `*.sha256` sidecars are generated for summary/manifest outputs. + +## Signature model + +The synthesizer emits detached `*.sig` payloads in one of two modes: + +1. `ed25519` (preferred production mode, when signing key is supplied), or +2. `digest-fallback` (local/dev mode, checksum-backed proof only). + +Production releases should always use an injected signing key and verify with +the corresponding public key in CI and by downstream auditors. + +## Trust assumptions + +Consumers should trust a release only when: + +1. checksums match manifest entries, +2. detached signatures verify successfully, +3. branch/date/release metadata match expected release context, +4. consensus parity mismatch counts are zero and exact OOG parity is true. + +## Related commands and docs + +- `pnpm release-evidence:synthesize` +- `pnpm release-evidence:verify` +- `docs/release-policy.md` +- `docs/release-checklist.md` +- `docs/signature-rotation-and-rollback.md` diff --git a/docs/release-readiness-report.md b/docs/release-readiness-report.md new file mode 100644 index 0000000..07ec991 --- /dev/null +++ b/docs/release-readiness-report.md @@ -0,0 +1,53 @@ +# Release-readiness report (current branch snapshot) + +Date: 2026-05-02 +Branch: `robert/wasm-consensus-ga-readiness-51ed-evaluation` + +> This file is generated by `node tools/release-evidence/synthesize-release-evidence.mjs`. + +## Environment + +- engineBuildHash: `f91091cb7feb788df340305a877a9cadb0c6f4d13aea8a7da4040b6367d178ea` +- gasVersion: `8` + +## Consensus-safe vs diagnostic-only + +### Consensus-safe (release gate) + +- Executor pair: `wasm-node` vs `wasm-browser` (`wasm32` release artifacts). +- Gate requirements: exact value/error parity, exact gas parity, exact tape parity, exact OOG boundary parity. +- Consensus mismatch count: `0` + +### Diagnostic-only + +- Native parity remains diagnostic-only unless explicitly promoted by release policy. + +## Certification and parity snapshot + +- Workload totals: `34` fixtures (`25` green / `8` red / `1` flagship) +- Workload mismatch count: `0` +- Workload OOG mismatch count: `0` +- Compatibility green delta vs baseline: `9` +- Consumer snapshot parity: `true` +- Consumer OOG parity: `true` +- Exact OOG parity status: `true` + +## Evidence manifest + +- Manifest file: `artifacts/release-evidence/release-evidence-manifest.json` +- Manifest artifact entries: `10` + +## Included artifacts + +| Category | File | SHA256 | +| --- | --- | --- | +| consensus | `inputs/consensus-report.json` | `b01e7948a477083a321f88e5e76992f7f5c950879f118a4a87263a37a079ec2f` | +| workload | `inputs/workload-certification.json` | `63a0b476c7813518d17272937e9ca68e25ae5eba6988074b2b202955630e05a5` | +| workload | `inputs/workload-oog-boundaries.json` | `9a752526737d0369d899c5a3cdcd7c8b15044ad06e2e8810db1041446e42faf7` | +| workload | `inputs/workload-compatibility-matrix.json` | `8203f26999528e64cf7706398e3e8f043a508b20c0e2829c958e5d70b50068d1` | +| consumer | `inputs/consumer-reproducibility.json` | `f6105c8c771fc8ed87e30c493583251bd62cb628c686b1a37414431281a6a16c` | +| workload | `inputs/workload-repeatability.json` | `9a45b9878700780cf75cc9a5771fed71c2466c1e23dedecadd45551c90908142` | +| workload | `inputs/workload-seeded-corpus.json` | `150e466f2cc771005b4e92b1dacac6a11167337d7d73a2a159a1dad75ceea4f1` | +| workload | `inputs/workload-compatibility-delta.json` | `a266e297eb57d91113b823ce5b4a7507a38c594504773ffa59b3554deb609d6d` | +| release-evidence | `release-evidence-summary.json` | `4822a50c26f6c2285a36e56bedb12c0a4b09db917b00fd1d117c5c5fa4f1e23e` | +| release-evidence | `release-evidence-summary.md` | `437817ea562b712381d17c825c17fd94b02c83b74a25b5384c516770eacdaa40` | diff --git a/docs/sdk.md b/docs/sdk.md index 890b30a..91b317b 100644 --- a/docs/sdk.md +++ b/docs/sdk.md @@ -7,8 +7,10 @@ This doc explains how to use the TypeScript runtime SDK (`libs/quickjs-runtime`) - deterministic gas metering - optional tape + gas trace -Conceptual overview: [Implementation summary](./implementation-summary.md). +Conceptual overview: [Core concepts](./concepts.md). ABI and DV specs: [Baseline #2](./baseline-2.md), [ABI manifest](./abi-manifest.md), [Host call ABI](./host-call-abi.md), [DV wire format](./dv-wire-format.md). +Runnable scenario matrix (module-pack, promises, libraries, binary, OOG +boundaries): [Examples corpus](../examples/README.md). --- @@ -72,6 +74,72 @@ console.log('gas used:', result.gasUsed.toString()); console.log('gas remaining:', result.gasRemaining.toString()); ``` +## Bundling libraries into deterministic source + +`evaluate()` expects `program.code` to be a single source string. For reusable +multi-file libraries, bundle first: + +```ts +import { bundleDeterministicProgram } from '@blue-quickjs/deterministic-bundler'; + +const bundled = await bundleDeterministicProgram({ + absWorkingDir: process.cwd(), + entryPath: 'src/program-entry.ts', + // Use compat-general-v1 here and in program.executionProfile if entry uses RegExp. + profile: 'baseline-v1', +}); + +const program = { + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: '…', + executionProfile: 'baseline-v1', + code: bundled.code, +}; +``` + +Bundling returns a deterministic content hash and compatibility diagnostics. By +default, compatibility violations fail fast before VM execution. + +## Execution semantics (raw script mode) + +`blue-quickjs` evaluates `program.code` as a **raw global script**. + +- The result is the DV-encodable value of the script’s final expression. +- Top-level `return` is invalid in this mode and fails deterministically. +- Side effects can be emitted through `emit(value)` / `Host.v1.emit(value)`. + +Raw script with final expression: + +```ts +const program = { + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: '…', + code: ` + const base = 40; + base + 2 + `, +}; +``` + +Emit side effects plus explicit final result: + +```ts +const program = { + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: '…', + code: ` + emit({ type: 'trace', step: 'start' }); + ({ ok: true }) + `, +}; +``` + +If your surrounding workflow uses function wrappers or custom return conventions, +that wrapper behavior belongs to the embedder/orchestrator layer, not this evaluator. + ### What you get back `evaluate()` returns a structured `EvaluateResult`: @@ -95,12 +163,20 @@ A program artifact is “code + ABI identity/pinning metadata”. The SDK valida - `abiVersion` (integer) - `abiManifestHash` (lowercase hex) - `code` (string) +- optional `gasVersion` (uint32; required for release-mode artifact pinning) Some environments also provide `engineBuildHash` pinning; if present, the SDK checks that the wasm runtime build hash matches. +For `releaseMode` execution, pass `expectedExecutionProfile` to `evaluate()`. +The SDK rejects artifacts whose `program.executionProfile` is missing or does +not match the runtime's expected profile. + Optional fields: - `engineBuildHash` (lowercase hex; sha256 of the wasm bytes) +- `gasVersion` (uint32 gas schedule version) +- `executionProfile` (`"baseline-v1"` default, or `"compat-general-v1"` for + compatibility-mode execution) Program artifact limits (validation defaults used by `evaluate()` and `initializeDeterministicVm()`): @@ -117,6 +193,28 @@ The hash pinning rules are described in: - [ABI manifest](./abi-manifest.md) (canonical encoding + hash) - [Release policy](./release-policy.md) +### ProgramArtifact.v2 runtime support + +The runtime now accepts both: + +- legacy single-source script artifacts (`ProgramArtifact` v1), and +- `ProgramArtifact.v2` with `sourceKind: "script"`. + +`ProgramArtifact.v2` with `sourceKind: "module-pack"` now executes via the +runtime's in-memory module loader path. The runtime validates +`modulePack.graphHash` before execution and emits deterministic module-pack +error codes for hash mismatches, missing specifiers/exports, resolution errors, +and evaluation failures. + +The versioned artifact model is specified in: + +- [Program artifact v2](./program-artifact-v2.md) +- [Module pack v1](./module-pack.md) +- [Execution profiles](./execution-profiles.md) + +This locks the migration target for module-pack execution and explicit +profile-required build outputs. + ### 2) Input envelope (`I`) The input envelope is DV-encodable data injected into the VM as ergonomic globals. @@ -255,7 +353,7 @@ See the gas sample fixtures in `libs/test-harness` for examples. ## See also -- [Implementation summary](./implementation-summary.md) +- [Core concepts](./concepts.md) - [Determinism profile](./determinism-profile.md) - [Host call ABI](./host-call-abi.md) - [ABI manifest](./abi-manifest.md) diff --git a/docs/signature-rotation-and-rollback.md b/docs/signature-rotation-and-rollback.md new file mode 100644 index 0000000..925402d --- /dev/null +++ b/docs/signature-rotation-and-rollback.md @@ -0,0 +1,47 @@ +# Signature rotation and emergency rollback + +This document defines operational handling for evidence-signing key rotation and +release rollback when deterministic pins (`engineBuildHash`, `gasVersion`) move. + +## Key rotation policy + +1. Maintain a current active signing key pair and a staged next key pair. +2. Publish/commit the active public verification key material used by auditors. +3. Rotate keys on schedule or on compromise suspicion. +4. During rotation windows, optionally dual-sign evidence bundles until all + verifiers have adopted the new key. + +## Verification key updates + +- Any key update must be called out in release notes. +- CI verification jobs must validate signatures against the expected key for the + release line. +- Auditors should reject evidence signed by unknown/untrusted keys. + +## Emergency rollback triggers + +Rollback is required when any of the following occur: + +- signature verification failures on release evidence bundle, +- manifest/checksum mismatch in archived release artifacts, +- unintended `engineBuildHash` movement, +- unintended `gasVersion` movement, +- deterministic mismatch regression in consensus reports. + +## Rollback procedure (minimum) + +1. Halt release/publish jobs. +2. Mark current candidate as revoked. +3. Rebuild and regenerate release evidence on last-known-good commit. +4. Re-verify: + - `pnpm release-evidence:verify` + - strict consensus parity reports. +5. Publish rollback advisory with revoked hashes/versions and replacement + evidence bundle. + +## Mandatory operator checks before unpausing + +- `engineBuildHash` explicitly reviewed and expected. +- `gasVersion` explicitly reviewed and expected. +- release-evidence manifest hash recorded in go/no-go template. +- consensus mismatch counts and OOG parity status are green. diff --git a/docs/threat-model.md b/docs/threat-model.md new file mode 100644 index 0000000..9095ea2 --- /dev/null +++ b/docs/threat-model.md @@ -0,0 +1,53 @@ +# Operator threat model (wasm-consensus scope) + +This threat model is operator-facing and focused on production usage of the +wasm-consensus executor path. + +## In-scope guarantees + +For the same `(P, I, G)` and deterministic host responses: + +- deterministic result/error parity, +- deterministic gas used/remaining parity, +- deterministic host-call tape parity, +- deterministic exact OOG boundary parity + +across consensus executors (`wasm-node` + required browser engines). + +## Out-of-scope guarantees + +- native harness parity as a consensus claim (native is diagnostic-only unless + explicitly promoted), +- behavior of disabled nondeterministic APIs (time/random/timers/fs/network), +- security of host systems outside manifest-locked Host ABI boundaries. + +## Main threat categories + +1. **Artifact tampering** + - altered evidence files, checksums, or manifests. + - Mitigation: checksum + detached signature verification. + +2. **Pin drift** + - unexpected `engineBuildHash` / `gasVersion` changes. + - Mitigation: explicit pin review and release go/no-go recording. + +3. **Host capability widening** + - accidental ABI or runtime surface widening beyond profile policy. + - Mitigation: manifest lock, profile checks, deterministic negative fixtures. + +4. **Cross-environment parity regressions** + - browser/runtime drift introducing mismatch. + - Mitigation: strict parity matrix and OOG certification in CI/release. + +## Mandatory production pins + +- `engineBuildHash` +- `gasVersion` +- ABI manifest hash +- execution profile + +## Native status reminder + +Native executor output is diagnostic-only and must not be used as consensus +acceptance criteria unless release policy explicitly promotes native for that +release line. diff --git a/docs/toolchain.md b/docs/toolchain.md index 1f096b0..7066397 100644 --- a/docs/toolchain.md +++ b/docs/toolchain.md @@ -14,13 +14,40 @@ Baseline anchors: see `docs/baseline-1.md` (deterministic execution constraints) 1. From repo root: `tools/scripts/setup-emsdk.sh` - Clones `emsdk` into `tools/emsdk` if missing. - Installs + activates the pinned version. -2. Load env into your shell for the session: `source tools/emsdk/emsdk_env.sh`. -3. Verify: `emcc --version` should report `3.1.56`. +2. Ensure the generated QuickJS source tree is prepared: + + ```bash + bash tools/scripts/prepare-quickjs-source.sh + ``` + + The script verifies the vendored upstream QuickJS base archive checksum, + extracts that base source, and applies `vendor/quickjs-patches/series/*.patch`. + It can still fall back to the upstream Git mirror path if the archive fields + are removed from the manifest. The repo auto-runs this check before + native-harness and wasm builds, but it is still useful as an explicit recovery + step on fresh clones. +3. Load env into your shell for the session: `source tools/emsdk/emsdk_env.sh`. +4. Verify: `emcc --version` should report `3.1.56`. Notes: - Script is idempotent; rerun after pulling a new pinned version. - Keep `emsdk` network access unblocked during install. +- On macOS, the setup script now retries once automatically, clears quarantine + attributes if possible, and on Apple Silicon retries the install with + `EMSDK_ARCH=x86_64` as a fallback. If that fallback path succeeds, Rosetta may + be required: + + ```bash + softwareupdate --install-rosetta --agree-to-license + ``` + +- The setup script now prefers the host `python3`/`python` to run `emsdk.py` + directly, which avoids macOS repeatedly re-entering a partially installed + bundled Python during retries. +- On macOS specifically, the script prefers `/usr/bin/python3` over Conda or + other shimmed interpreters and clears `PYTHONHOME`, `PYTHONPATH`, and common + `CONDA_*` variables before invoking `emsdk.py`. ## CI caching @@ -47,4 +74,4 @@ Notes: - Artifacts land in `libs/quickjs-wasm-build/dist/` as `quickjs-eval{,-debug}{,-wasm64}.{js,wasm}` (wasm32 is canonical; wasm64 is optional for debugging). Loader + metadata are resolved via `getQuickjsWasmArtifacts(...)` and `readQuickjsWasmMetadata()`. - `quickjs-wasm-build.metadata.json` captures per-variant/per-build-type filenames, hashes, sizes, flags, and `engineBuildHash` (keyed to wasm32 release when present). -- The wasm harness exports deterministic ABI entrypoints only (`qjs_det_init`/`qjs_det_eval`/`qjs_det_set_gas_limit`/`qjs_det_free` plus tape/trace helpers) and returns DV-hex payloads with `RESULT … GAS …` / `ERROR … GAS …` formatting; strings are freed with the exported `_free` helper. +- The wasm harness exports deterministic ABI entrypoints only (`qjs_det_init`/`qjs_det_eval`/`qjs_det_set_gas_limit`/`qjs_det_free` plus tape/trace helpers) and returns DV-hex payloads with `RESULT … GAS …` / `ERROR … GAS …` formatting; `qjs_det_init(..., feature_flags)` accepts deterministic feature flags (`0` for baseline), and strings are freed with the exported `_free` helper. diff --git a/docs/unsupported-features-and-why.md b/docs/unsupported-features-and-why.md new file mode 100644 index 0000000..4778ad4 --- /dev/null +++ b/docs/unsupported-features-and-why.md @@ -0,0 +1,73 @@ +# Unsupported features and why + +BlueQuickjs is intentionally narrower than a general-purpose JavaScript +runtime. Unsupported features are not arbitrary omissions; they are deliberate +choices to preserve deterministic behavior and auditability. + +## Unsupported in the consensus baseline + +### Dynamic code generation + +- `eval` +- `Function` + +Why: these widen the executable surface at runtime and make review/auditing much +harder. + +### Ambient nondeterminism + +- clocks and wall time +- randomness +- timers +- filesystem +- network +- locale-sensitive ambient behavior + +Why: independent nodes must not depend on host-local state or scheduling. + +### Runtime module loading + +- dynamic `import()` +- runtime fetch/import/network resolution + +Why: module graphs must be fixed at build time and represented as +`ModulePack.v1`. + +## Unsupported unless a compatibility profile enables them + +### Promise jobs and microtasks + +Allowed only in: + +- `compat-general-v1` +- `compat-binary-v1` + +Why: Promise job draining must be deterministic and explicitly versioned. + +### Typed arrays / `ArrayBuffer` / `DataView` + +Allowed only in: + +- `compat-binary-v1` + +Why: binary boundaries require DV2 / `Host.v2` semantics and must not widen the +baseline accidentally. + +## Unsupported as consensus executors + +### Native runtime parity + +Native is still used heavily for diagnostics, reconciliation, and harness work, +but it is not part of today’s consensus release gate. + +### Diagnostic browser paths + +WebKit and other diagnostic browser runs may be useful, but the required +release matrix today is Chromium/Firefox-backed wasm browser execution. + +## Related docs + +- [Determinism profile](./determinism-profile.md) +- [Execution profiles](./execution-profiles.md) +- [Value model v2 (DV2)](./value-model-v2.md) +- [Consensus-safe vs diagnostic-only](./consensus-safe-vs-diagnostic-only.md) diff --git a/docs/value-model-v2.md b/docs/value-model-v2.md new file mode 100644 index 0000000..c5b8f6c --- /dev/null +++ b/docs/value-model-v2.md @@ -0,0 +1,77 @@ +# Value model v2 (DV2) and binary boundary support + +Baseline anchors: + +- `docs/baseline-1.md` +- `docs/baseline-2.md` +- current DV spec: `docs/dv-wire-format.md` + +## Decision + +Binary boundary support is delivered via a **new versioned value model** (DV2), +not by mutating DV1 in place. + +## Why + +- Current DV intentionally excludes byte strings. +- Typed-array-heavy libraries require a canonical bytes boundary. +- Versioning avoids breaking existing Host.v1/DV1 contracts. + +## DV2 additions + +DV2 extends DV1 with canonical byte strings: + +- `bytes` type (canonical CBOR byte string form, definite-length only). + +SDK surface: + +- `encodeDv2(...)`, `decodeDv2(...)`, `validateDv2(...)`, `isDv2(...)` + in `@blue-quickjs/dv`. +- QuickJS C surface: `JS_EncodeDV2(...)` / `JS_DecodeDV2(...)` (DV1 APIs remain + unchanged). +- DV1 APIs (`encodeDv`, `decodeDv`) remain unchanged and continue rejecting byte + strings. + +All existing DV1 canonical constraints still apply (finite numbers, canonical +ordering, deterministic size/depth limits). + +## JS boundary mapping + +- Wire `bytes` maps to `Uint8Array` at JS host/runtime boundaries. +- Within VM execution profiles that allow typed arrays, binary APIs can operate + on ArrayBuffer/DataView/typed arrays. +- Non-byte typed arrays are runtime values, but boundary canonicalization must + still be explicit and deterministic. +- Current implementation wires this mapping for Host.v2 boundaries in: + - quickjs-runtime host dispatcher, + - QuickJS host-call wrappers (`JS_EncodeDV2` / `JS_DecodeDV2`), + - native harness manifest stubs and parity scripts. + +## ABI versioning policy + +- Keep `Host.v1` + DV1 behavior unchanged. +- Introduce `Host.v2` (or equivalent ABI version bump) for DV2 boundary types. +- Mixed-version ambiguity is not allowed. + +## Canonical encoding notes + +- Definite lengths only. +- No non-canonical alternate encodings. +- No accidental acceptance of non-canonical buffer representations. + +## Compatibility profile linkage + +DV2 boundary bytes are enabled only when profile capabilities include `dvBytes` +(see `docs/execution-profiles.md`, e.g. `compat-binary-v1`). + +## Test requirements + +- bytes round-trip across host call args/returns and final result, +- canonical hash stability for byte values, +- rejection of non-canonical byte encodings, +- parity across native / wasm-node / wasm-browser. + +## See also + +- `docs/execution-profiles.md` +- `docs/abi-manifest.md` diff --git a/docs/workload-certification.md b/docs/workload-certification.md new file mode 100644 index 0000000..09b78af --- /dev/null +++ b/docs/workload-certification.md @@ -0,0 +1,82 @@ +# Workload Certification Report + +This document defines the workload-certification evidence flow for the RC +ecosystem phase. + +## What is certified + +1. **Flagship workload**: deterministic knowledge/compliance pack processing + (`apps/ecosystem-certifier/fixtures/flagship/knowledge-pack-entry.ts`). +2. **Compatibility matrix**: broad green/red third-party corpus executed via + `apps/ecosystem-certifier`. +3. **Consensus parity**: strict wasm-node vs wasm-browser comparison for + value/error, gas, tape, and expected failure stage. + - Required release-candidate browsers: **Chromium** and **Firefox**. + - WebKit remains diagnostic-only when run via scheduled workflow. +4. **Builder path determinism**: hash equality checks from distinct absolute + working directories. +5. **Downstream tarball consumer proof**: + `e2e/consumer-proof-app` installs packed `@blue-quickjs/*` tarballs and + validates node/browser parity plus exact OOG boundaries. + +## Commands + +From repo root: + +```bash +# Ecosystem certifier tests +source tools/emsdk/emsdk_env.sh +pnpm nx test ecosystem-certifier +pnpm nx run ecosystem-certifier:e2e + +# Builder path determinism + workload matrix report +node apps/ecosystem-certifier/scripts/check-builder-determinism.mjs --out-dir artifacts/workload-certification +node tools/workload-certification/compare-builder-determinism-matrix.mjs --input-dir artifacts +node apps/ecosystem-certifier/scripts/archive-workload-certification-report.mjs --out-dir artifacts/workload-certification --browser chromium +node apps/ecosystem-certifier/scripts/archive-workload-certification-report.mjs --out-dir artifacts/workload-certification --browser firefox +node apps/ecosystem-certifier/scripts/generate-compatibility-delta-report.mjs --current-dir artifacts/workload-certification --out-dir artifacts/workload-certification +node apps/ecosystem-certifier/scripts/run-oog-boundary-certification.mjs --out-dir artifacts/workload-certification --browser chromium +node apps/ecosystem-certifier/scripts/run-oog-boundary-certification.mjs --out-dir artifacts/workload-certification --browser firefox +node apps/ecosystem-certifier/scripts/run-repeatability-certification.mjs --out-dir artifacts/workload-certification --iterations 100 --flagship-iterations 40 --browser chromium +node apps/ecosystem-certifier/scripts/run-seeded-property-corpus.mjs --out-dir artifacts/workload-certification --seed-count 80 --browser chromium + +# Downstream tarball consumer proof (Node/OS matrix-ready) +pnpm workload:check-public-package-versions +pnpm workload:check-pack-manifests -- --out-dir artifacts/consumer-proof/pack-manifests +pnpm publish-rehearsal:verdaccio -- --out-dir artifacts/consumer-proof/verdaccio +node tools/workload-certification/pack-public-tarballs.mjs --out-dir artifacts/consumer-proof/tarballs +pnpm --dir e2e/consumer-proof-app run install:tarballs -- --tarball-dir ../../artifacts/consumer-proof/tarballs +pnpm --dir e2e/consumer-proof-app exec playwright install --with-deps chromium +pnpm --dir e2e/consumer-proof-app run repro +# optional native diagnostic section +pnpm --dir e2e/consumer-proof-app run repro -- --with-native +``` + +## Expected artifact outputs + +- `artifacts/workload-certification/builder-determinism-report.json` +- `artifacts/workload-certification/workload-certification-.json` +- `artifacts/workload-certification/workload-certification-.md` +- `artifacts/workload-certification/workload-certification-.json.sha256` +- `artifacts/workload-certification/compatibility-matrix-.json` +- `artifacts/workload-certification/compatibility-delta-report.json` +- `artifacts/workload-certification/oog-boundaries.json` +- `artifacts/workload-certification/repeatability-report.json` +- `artifacts/workload-certification/seeded-property-corpus-report.json` +- `e2e/consumer-proof-app/reports/reproducibility-report.json` +- `e2e/consumer-proof-app/reports/oog-boundary.json` +- `e2e/consumer-proof-app/reports/native-diagnostic.json` (optional) + +The workload-certification JSON includes: + +- summary counts (`greenCount`, `redCount`, `mismatches`, `flagshipCount`), +- a machine-readable `compatibilityMatrix`, +- full per-fixture node/browser snapshots with gas and tape hashes, +- signature digest (`sha256`) over canonical report payload. + +## Policy notes + +- Consensus remains **wasm-node vs wasm-browser**. +- Native harness remains diagnostic-only. +- Failures are documented as deterministic incompatibilities instead of widening + deterministic contracts. diff --git a/e2e/consumer-proof-app/README.md b/e2e/consumer-proof-app/README.md new file mode 100644 index 0000000..134b1ff --- /dev/null +++ b/e2e/consumer-proof-app/README.md @@ -0,0 +1,68 @@ +# consumer-proof-app + +Downstream application proof that consumes published `@blue-quickjs/*` +artifacts and validates deterministic parity from a consumer’s point of view. + +It supports both release-rehearsal paths used by the repo: + +- **tarball rehearsal** — install locally packed publish-style tarballs +- **registry/Verdaccio rehearsal** — publish to a local registry and install + from there + +## Tarball rehearsal flow + +1. Pack publish-style tarballs from repo root: + + ```bash + node tools/workload-certification/pack-public-tarballs.mjs --out-dir artifacts/consumer-proof/tarballs + ``` + +2. Install tarballs into this app: + + ```bash + cd e2e/consumer-proof-app + pnpm run install:tarballs -- --tarball-dir ../../artifacts/consumer-proof/tarballs + ``` + +3. Generate the reproducibility report (node + browser + OOG boundary): + + ```bash + pnpm run repro + ``` + + Firefox parity run: + + ```bash + pnpm run repro -- --browser firefox + ``` + +## Registry / Verdaccio rehearsal flow + +From repo root: + +```bash +pnpm publish-rehearsal:verdaccio -- --out-dir artifacts/consumer-proof/verdaccio +``` + +That flow publishes the workspace packages into a local Verdaccio registry, +installs them into this consumer app, and then runs the same downstream proof. + +## Outputs + +Reports are written to: + +- `e2e/consumer-proof-app/reports/` + +Key artifacts include: + +- reproducibility report +- OOG-boundary report +- optional native diagnostic report + +## Optional native diagnostic run + +Native remains non-consensus. Use only as a diagnostic supplement: + +```bash +pnpm run repro -- --with-native +``` diff --git a/e2e/consumer-proof-app/index.html b/e2e/consumer-proof-app/index.html new file mode 100644 index 0000000..f594262 --- /dev/null +++ b/e2e/consumer-proof-app/index.html @@ -0,0 +1,12 @@ + + + + + + Blue QuickJS Consumer Proof + + +
Loading consumer proof runner…
+ + + diff --git a/e2e/consumer-proof-app/package.json b/e2e/consumer-proof-app/package.json new file mode 100644 index 0000000..5ea23f4 --- /dev/null +++ b/e2e/consumer-proof-app/package.json @@ -0,0 +1,24 @@ +{ + "name": "consumer-proof-app", + "version": "0.0.1", + "private": true, + "type": "module", + "scripts": { + "install:tarballs": "node scripts/install-from-tarballs.mjs", + "build-artifact": "node scripts/build-artifact.mjs", + "run-node": "node scripts/run-node.mjs", + "run-browser": "node scripts/run-browser.mjs", + "find-oog": "node scripts/find-oog-boundary.mjs", + "run-native-diagnostic": "node scripts/run-native-diagnostic.mjs", + "repro": "node scripts/reproducibility-report.mjs" + }, + "dependencies": { + "he": "^1.2.0", + "path-to-regexp": "^8.2.0", + "semver": "^7.7.3" + }, + "devDependencies": { + "@playwright/test": "^1.57.0", + "vite": "^7.2.7" + } +} diff --git a/e2e/consumer-proof-app/playwright.config.mjs b/e2e/consumer-proof-app/playwright.config.mjs new file mode 100644 index 0000000..b2c40d7 --- /dev/null +++ b/e2e/consumer-proof-app/playwright.config.mjs @@ -0,0 +1,9 @@ +import { defineConfig } from '@playwright/test'; + +export default defineConfig({ + testDir: './tests', + use: { + headless: true, + baseURL: 'http://127.0.0.1:4320', + }, +}); diff --git a/e2e/consumer-proof-app/scripts/_helpers.mjs b/e2e/consumer-proof-app/scripts/_helpers.mjs new file mode 100644 index 0000000..43323a5 --- /dev/null +++ b/e2e/consumer-proof-app/scripts/_helpers.mjs @@ -0,0 +1,77 @@ +import { createHash } from 'node:crypto'; +import { mkdir, readFile, writeFile } from 'node:fs/promises'; +import path from 'node:path'; + +export const appRoot = path.resolve(import.meta.dirname, '..'); +export const reportsDir = path.resolve(appRoot, 'reports'); +export const artifactPath = path.join(reportsDir, 'program-artifact.json'); +export const nodeResultPath = path.join(reportsDir, 'node-result.json'); +export const browserResultPath = path.join(reportsDir, 'browser-result.json'); +export const oogBoundaryPath = path.join(reportsDir, 'oog-boundary.json'); +export const reproPath = path.join(reportsDir, 'reproducibility-report.json'); + +export async function ensureReportsDir() { + await mkdir(reportsDir, { recursive: true }); +} + +export async function writeJson(targetPath, payload) { + await mkdir(path.dirname(targetPath), { recursive: true }); + await writeFile(targetPath, `${JSON.stringify(payload, null, 2)}\n`, 'utf8'); +} + +export async function readJson(targetPath) { + const text = await readFile(targetPath, 'utf8'); + return JSON.parse(text); +} + +export function createInputEnvelope() { + return { + event: { type: 'consumer-proof' }, + eventCanonical: { type: 'consumer-proof' }, + steps: [], + currentContract: { id: 'consumer-proof' }, + currentContractCanonical: { id: { value: 'consumer-proof' } }, + }; +} + +export function snapshotFromResult(result, encodeDv) { + const tape = result.tape ?? []; + if (result.ok) { + return { + stage: 'success', + resultHash: sha256Hex(Buffer.from(encodeDv(result.value))), + errorCode: null, + errorTag: null, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + tapeHash: + tape.length > 0 + ? sha256Hex(Buffer.from(stringifyWithBigInt(tape))) + : null, + tapeLength: tape.length, + }; + } + return { + stage: 'error', + resultHash: null, + errorCode: result.error.code, + errorTag: 'tag' in result.error ? result.error.tag : null, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + tapeHash: + tape.length > 0 + ? sha256Hex(Buffer.from(stringifyWithBigInt(tape))) + : null, + tapeLength: tape.length, + }; +} + +export function sha256Hex(input) { + return createHash('sha256').update(input).digest('hex'); +} + +function stringifyWithBigInt(value) { + return JSON.stringify(value, (_, item) => + typeof item === 'bigint' ? item.toString() : item, + ); +} diff --git a/e2e/consumer-proof-app/scripts/build-artifact.mjs b/e2e/consumer-proof-app/scripts/build-artifact.mjs new file mode 100644 index 0000000..475b4e0 --- /dev/null +++ b/e2e/consumer-proof-app/scripts/build-artifact.mjs @@ -0,0 +1,56 @@ +#!/usr/bin/env node + +import { HOST_V1_HASH } from '@blue-quickjs/abi-manifest'; +import { buildDeterministicModulePack } from '@blue-quickjs/deterministic-bundler'; +import path from 'node:path'; +import { + appRoot, + artifactPath, + ensureReportsDir, + writeJson, +} from './_helpers.mjs'; + +await ensureReportsDir(); + +const built = await buildDeterministicModulePack({ + absWorkingDir: appRoot, + entryPath: 'src/shared/consumer-workload.ts', + profile: 'compat-general-v1', + emitProgramArtifact: true, + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, +}); + +if (!built.compatibility.ok) { + throw new Error( + `consumer workload is incompatible: ${JSON.stringify( + built.compatibility.diagnostics, + )}`, + ); +} +if (!built.programArtifact) { + throw new Error('builder did not produce ProgramArtifact.v2'); +} + +const payload = { + generatedAt: new Date().toISOString(), + graphHash: built.modulePack.graphHash, + moduleCount: built.modulePack.modules.length, + artifact: built.programArtifact, +}; + +await writeJson(artifactPath, payload); + +console.log( + JSON.stringify( + { + artifactPath, + graphHash: payload.graphHash, + moduleCount: payload.moduleCount, + relativeEntry: path.relative(appRoot, 'src/shared/consumer-workload.ts'), + }, + null, + 2, + ), +); diff --git a/e2e/consumer-proof-app/scripts/consumer-host.mjs b/e2e/consumer-proof-app/scripts/consumer-host.mjs new file mode 100644 index 0000000..ad4e823 --- /dev/null +++ b/e2e/consumer-proof-app/scripts/consumer-host.mjs @@ -0,0 +1,32 @@ +export function createConsumerHost() { + const emitted = []; + return { + emitted, + handlers: { + document: { + get(docPath) { + switch (docPath) { + case 'consumer/version': + return { ok: '1.2.3', units: 1 }; + case 'consumer/encoded': + return { ok: '<b>deterministic</b>', units: 1 }; + case 'consumer/route': + return { ok: '/contract/:id/release/:version', units: 1 }; + default: + return { + err: { code: 'NOT_FOUND', tag: 'host/not_found' }, + units: 1, + }; + } + }, + getCanonical(docPath) { + return this.get(docPath); + }, + }, + emit(value) { + emitted.push(value); + return { ok: null, units: 1 }; + }, + }, + }; +} diff --git a/e2e/consumer-proof-app/scripts/find-oog-boundary.mjs b/e2e/consumer-proof-app/scripts/find-oog-boundary.mjs new file mode 100644 index 0000000..8782cbe --- /dev/null +++ b/e2e/consumer-proof-app/scripts/find-oog-boundary.mjs @@ -0,0 +1,174 @@ +#!/usr/bin/env node + +import { HOST_V1_MANIFEST } from '@blue-quickjs/abi-manifest'; +import { evaluate } from '@blue-quickjs/quickjs-runtime'; +import { chromium, firefox, webkit } from '@playwright/test'; +import { createServer } from 'vite'; +import path from 'node:path'; +import { + appRoot, + artifactPath, + createInputEnvelope, + oogBoundaryPath, + readJson, + writeJson, +} from './_helpers.mjs'; +import { createConsumerHost } from './consumer-host.mjs'; + +const args = parseArgs(process.argv.slice(2)); +const payload = await readJson(args.artifactPath ?? artifactPath); + +const nodeBoundary = await searchBoundary({ + low: 1n, + high: BigInt(args.maxGas), + run: async (gasLimit) => { + const host = createConsumerHost(); + const result = await evaluate({ + program: payload.artifact, + input: createInputEnvelope(), + gasLimit, + manifest: HOST_V1_MANIFEST, + handlers: host.handlers, + tape: { capacity: 32 }, + }); + return result.ok; + }, +}); + +const viteServer = await createServer({ + configFile: path.join(appRoot, 'vite.config.mts'), + clearScreen: false, +}); +await viteServer.listen(); +const browserType = resolveBrowserType(args.browser); +const browser = await browserType.launch({ headless: true }); +const context = await browser.newContext({ baseURL: args.baseUrl }); + +let browserBoundary; +try { + const page = await context.newPage(); + await page.addInitScript((artifact) => { + window.__CONSUMER_ARTIFACT__ = artifact; + }, payload.artifact); + await page.goto('/'); + await page.waitForFunction( + () => typeof window.__runConsumerEvaluation === 'function', + ); + + browserBoundary = await searchBoundary({ + low: 1n, + high: BigInt(args.maxGas), + run: async (gasLimit) => + page.evaluate(async (value) => { + const result = await window.__runConsumerEvaluation?.(String(value)); + return result?.stage === 'success'; + }, gasLimit.toString()), + }); +} finally { + await context.close(); + await browser.close(); + await viteServer.close(); +} + +const parity = { + firstSuccessEqual: + nodeBoundary.firstSuccessGas.toString() === + browserBoundary.firstSuccessGas.toString(), + lastFailureEqual: + nodeBoundary.lastFailureGas.toString() === + browserBoundary.lastFailureGas.toString(), +}; + +const report = { + generatedAt: new Date().toISOString(), + browser: args.browser, + node: { + firstSuccessGas: nodeBoundary.firstSuccessGas.toString(), + lastFailureGas: nodeBoundary.lastFailureGas.toString(), + }, + browser: { + firstSuccessGas: browserBoundary.firstSuccessGas.toString(), + lastFailureGas: browserBoundary.lastFailureGas.toString(), + }, + parity, +}; + +await writeJson(oogBoundaryPath, report); +console.log(JSON.stringify({ oogBoundaryPath, parity, report }, null, 2)); + +if (!parity.firstSuccessEqual || !parity.lastFailureEqual) { + process.exitCode = 1; +} + +async function searchBoundary({ low, high, run }) { + let left = low; + let right = high; + const rightSuccess = await run(right); + if (!rightSuccess) { + throw new Error( + `max gas ${high.toString()} is still OOG; increase --max-gas to locate boundary`, + ); + } + + while (left + 1n < right) { + const mid = (left + right) / 2n; + const ok = await run(mid); + if (ok) { + right = mid; + } else { + left = mid; + } + } + return { + lastFailureGas: left, + firstSuccessGas: right, + }; +} + +function parseArgs(argv) { + let maxGas = '2000000'; + let artifact = null; + let baseUrl = 'http://127.0.0.1:4320'; + let browser = 'chromium'; + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--') { + continue; + } + if (arg === '--max-gas') { + maxGas = argv[index + 1] ?? maxGas; + index += 1; + continue; + } + if (arg === '--artifact') { + artifact = argv[index + 1] ?? artifact; + index += 1; + continue; + } + if (arg === '--base-url') { + baseUrl = argv[index + 1] ?? baseUrl; + index += 1; + continue; + } + if (arg === '--browser') { + browser = argv[index + 1] ?? browser; + index += 1; + continue; + } + throw new Error(`unknown argument: ${arg}`); + } + return { maxGas, artifactPath: artifact, baseUrl, browser }; +} + +function resolveBrowserType(browserName) { + if (browserName === 'chromium') { + return chromium; + } + if (browserName === 'firefox') { + return firefox; + } + if (browserName === 'webkit') { + return webkit; + } + throw new Error(`unsupported browser: ${browserName}`); +} diff --git a/e2e/consumer-proof-app/scripts/install-from-tarballs.mjs b/e2e/consumer-proof-app/scripts/install-from-tarballs.mjs new file mode 100644 index 0000000..1b6cab6 --- /dev/null +++ b/e2e/consumer-proof-app/scripts/install-from-tarballs.mjs @@ -0,0 +1,83 @@ +#!/usr/bin/env node + +import { mkdir, readdir } from 'node:fs/promises'; +import path from 'node:path'; +import process from 'node:process'; +import { spawn } from 'node:child_process'; + +const appRoot = path.resolve(import.meta.dirname, '..'); +const npmCacheDir = path.join(appRoot, '.npm-cache'); +const args = parseArgs(process.argv.slice(2)); +const tarballDir = path.resolve(appRoot, args.tarballDir); +const useShell = process.platform === 'win32'; +const npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm'; +await mkdir(npmCacheDir, { recursive: true }); +const entries = await readdir(tarballDir); +const tarballs = entries + .filter((entry) => entry.endsWith('.tgz')) + .filter((entry) => !entry.includes('deterministic-builder')) + .map((entry) => path.join(tarballDir, entry)) + .sort(); + +if (tarballs.length === 0) { + throw new Error(`no .tgz files found in ${tarballDir}`); +} + +await run(npmCommand, ['install', '--no-fund', '--no-audit'], appRoot); +await run( + npmCommand, + ['install', '--no-save', '--no-fund', '--no-audit', ...tarballs], + appRoot, +); + +console.log( + JSON.stringify({ tarballDir, installed: tarballs.length }, null, 2), +); + +function parseArgs(argv) { + let tarballDir = '../../artifacts/consumer-proof/tarballs'; + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--') { + continue; + } + if (arg === '--tarball-dir') { + tarballDir = argv[index + 1] ?? tarballDir; + index += 1; + continue; + } + throw new Error(`unknown argument: ${arg}`); + } + return { tarballDir }; +} + +async function run(command, args, cwd) { + await new Promise((resolve, reject) => { + const child = spawn(command, args, { + cwd, + stdio: 'inherit', + env: createCleanNpmEnv(), + shell: useShell, + }); + child.on('error', reject); + child.on('exit', (code) => { + if (code === 0) { + resolve(undefined); + return; + } + reject(new Error(`command failed (${command} ${args.join(' ')})`)); + }); + }); +} + +function createCleanNpmEnv() { + const env = { ...process.env }; + for (const key of Object.keys(env)) { + if (key.startsWith('npm_config_')) { + delete env[key]; + } + } + env.npm_config_cache = npmCacheDir; + env.npm_config_package_lock = 'false'; + return env; +} diff --git a/e2e/consumer-proof-app/scripts/reproducibility-report.mjs b/e2e/consumer-proof-app/scripts/reproducibility-report.mjs new file mode 100644 index 0000000..842f4de --- /dev/null +++ b/e2e/consumer-proof-app/scripts/reproducibility-report.mjs @@ -0,0 +1,108 @@ +#!/usr/bin/env node + +import { spawn } from 'node:child_process'; +import path from 'node:path'; +import { + appRoot, + artifactPath, + browserResultPath, + nodeResultPath, + oogBoundaryPath, + readJson, + reproPath, + sha256Hex, + writeJson, +} from './_helpers.mjs'; + +const args = parseArgs(process.argv.slice(2)); + +await run('node', ['scripts/build-artifact.mjs']); +await run('node', ['scripts/run-node.mjs']); +await run('node', ['scripts/run-browser.mjs', '--browser', args.browser]); +await run('node', ['scripts/find-oog-boundary.mjs', '--browser', args.browser]); +if (args.withNative) { + await run('node', ['scripts/run-native-diagnostic.mjs']); +} + +const artifact = await readJson(artifactPath); +const nodeResult = await readJson(nodeResultPath); +const browserResult = await readJson(browserResultPath); +const oogBoundary = await readJson(oogBoundaryPath); +const nativeDiagnostic = args.withNative + ? await readJson(path.join(appRoot, 'reports/native-diagnostic.json')) + : null; + +const nodeSnapshot = nodeResult.snapshot; +const browserSnapshot = browserResult.snapshot; +const parity = { + snapshotEqual: + JSON.stringify(nodeSnapshot) === JSON.stringify(browserSnapshot), + oogEqual: + oogBoundary.parity.firstSuccessEqual && oogBoundary.parity.lastFailureEqual, +}; + +const report = { + generatedAt: new Date().toISOString(), + browser: args.browser, + artifact: { + graphHash: artifact.graphHash, + moduleCount: artifact.moduleCount, + }, + node: nodeSnapshot, + browser: browserSnapshot, + oogBoundary, + nativeDiagnostic, + parity, + signature: { + algorithm: 'sha256', + digest: sha256Hex( + JSON.stringify({ artifact, nodeSnapshot, browserSnapshot, oogBoundary }), + ), + }, +}; + +await writeJson(reproPath, report); +await writeJson(`${reproPath}.sha256`, { + algorithm: 'sha256', + digest: sha256Hex(JSON.stringify(report)), +}); + +console.log(JSON.stringify({ reproPath, parity }, null, 2)); +if (!parity.snapshotEqual || !parity.oogEqual) { + process.exitCode = 1; +} + +function parseArgs(argv) { + let withNative = false; + let browser = 'chromium'; + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--') { + continue; + } + if (arg === '--with-native') { + withNative = true; + continue; + } + if (arg === '--browser') { + browser = argv[index + 1] ?? browser; + index += 1; + continue; + } + throw new Error(`unknown argument: ${arg}`); + } + return { withNative, browser }; +} + +async function run(command, args) { + await new Promise((resolve, reject) => { + const child = spawn(command, args, { cwd: appRoot, stdio: 'inherit' }); + child.on('exit', (code) => { + if (code === 0) { + resolve(undefined); + return; + } + reject(new Error(`command failed (${command} ${args.join(' ')})`)); + }); + }); +} diff --git a/e2e/consumer-proof-app/scripts/run-browser.mjs b/e2e/consumer-proof-app/scripts/run-browser.mjs new file mode 100644 index 0000000..b9d9c12 --- /dev/null +++ b/e2e/consumer-proof-app/scripts/run-browser.mjs @@ -0,0 +1,123 @@ +#!/usr/bin/env node + +import { chromium, firefox, webkit } from '@playwright/test'; +import { createServer } from 'vite'; +import path from 'node:path'; +import { + appRoot, + artifactPath, + browserResultPath, + readJson, + writeJson, +} from './_helpers.mjs'; + +const args = parseArgs(process.argv.slice(2)); +const payload = await readJson(args.artifactPath ?? artifactPath); + +const viteServer = await createServer({ + configFile: path.join(appRoot, 'vite.config.mts'), + clearScreen: false, +}); +await viteServer.listen(); + +const browserType = resolveBrowserType(args.browser); +const browser = await browserType.launch({ headless: true }); +const context = await browser.newContext({ baseURL: args.baseUrl }); +try { + const page = await context.newPage(); + page.on('console', (message) => { + if (message.type() === 'error') { + console.error(`[browser-console] ${message.text()}`); + } + }); + page.on('pageerror', (error) => { + console.error(`[browser-pageerror] ${error.message}`); + }); + await page.addInitScript( + ({ artifact }) => { + window.__CONSUMER_ARTIFACT__ = artifact; + }, + { artifact: payload.artifact }, + ); + await page.goto('/'); + await page.waitForFunction( + () => typeof window.__runConsumerEvaluation === 'function', + undefined, + { + timeout: 120000, + }, + ); + const snapshot = await page.evaluate((gasLimit) => { + if (!window.__runConsumerEvaluation) { + throw new Error('window.__runConsumerEvaluation is not available'); + } + return window.__runConsumerEvaluation(gasLimit); + }, args.gasLimit); + + await page.waitForFunction( + () => Boolean(window.__CONSUMER_RESULT__), + undefined, + { + timeout: 120000, + }, + ); + await writeJson(browserResultPath, { + generatedAt: new Date().toISOString(), + browser: args.browser, + gasLimit: args.gasLimit, + snapshot, + }); + console.log(JSON.stringify({ browserResultPath, snapshot }, null, 2)); +} finally { + await context.close(); + await browser.close(); + await viteServer.close(); +} + +function parseArgs(argv) { + let gasLimit = '1000000'; + let artifact = null; + let baseUrl = 'http://127.0.0.1:4320'; + let browser = 'chromium'; + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--') { + continue; + } + if (arg === '--gas-limit') { + gasLimit = argv[index + 1] ?? gasLimit; + index += 1; + continue; + } + if (arg === '--artifact') { + artifact = argv[index + 1] ?? artifact; + index += 1; + continue; + } + if (arg === '--base-url') { + baseUrl = argv[index + 1] ?? baseUrl; + index += 1; + continue; + } + if (arg === '--browser') { + browser = argv[index + 1] ?? browser; + index += 1; + continue; + } + throw new Error(`unknown argument: ${arg}`); + } + return { gasLimit, artifactPath: artifact, baseUrl, browser }; +} + +function resolveBrowserType(browserName) { + if (browserName === 'chromium') { + return chromium; + } + if (browserName === 'firefox') { + return firefox; + } + if (browserName === 'webkit') { + return webkit; + } + throw new Error(`unsupported browser: ${browserName}`); +} diff --git a/e2e/consumer-proof-app/scripts/run-native-diagnostic.mjs b/e2e/consumer-proof-app/scripts/run-native-diagnostic.mjs new file mode 100644 index 0000000..dfa4cce --- /dev/null +++ b/e2e/consumer-proof-app/scripts/run-native-diagnostic.mjs @@ -0,0 +1,92 @@ +#!/usr/bin/env node + +import { spawn } from 'node:child_process'; +import path from 'node:path'; +import process from 'node:process'; +import { appRoot, reportsDir, writeJson } from './_helpers.mjs'; + +const args = parseArgs(process.argv.slice(2)); +const repoRoot = path.resolve(appRoot, '..', '..'); +const binaryPath = path.resolve( + repoRoot, + 'tools/quickjs-native-harness/dist/quickjs-native-harness', +); + +const report = { + generatedAt: new Date().toISOString(), + diagnosticOnly: true, + command: binaryPath, + status: 'skipped', + output: null, + error: null, +}; + +try { + await run('pnpm', ['nx', 'build', 'quickjs-native-harness'], repoRoot); + const runResult = await run( + binaryPath, + [ + '--eval', + "(() => ({ runtime: 'native-diagnostic', value: 40 + 2 }))()", + '--execution-profile', + 'compat-general-v1', + '--gas-limit', + '200000', + '--report-gas', + ], + repoRoot, + ); + report.status = 'ok'; + report.output = runResult.stdout.trim(); + report.error = runResult.stderr.trim() || null; +} catch (error) { + report.status = 'failed'; + report.error = error instanceof Error ? error.message : String(error); +} + +const outputPath = path.join(reportsDir, args.outputFile); +await writeJson(outputPath, report); + +console.log(JSON.stringify({ outputPath, status: report.status }, null, 2)); + +function parseArgs(argv) { + let outputFile = 'native-diagnostic.json'; + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--output-file') { + outputFile = argv[index + 1] ?? outputFile; + index += 1; + continue; + } + throw new Error(`unknown argument: ${arg}`); + } + return { outputFile }; +} + +async function run(command, args, cwd) { + return new Promise((resolve, reject) => { + const child = spawn(command, args, { + cwd, + stdio: ['ignore', 'pipe', 'pipe'], + }); + let stdout = ''; + let stderr = ''; + child.stdout.on('data', (chunk) => { + stdout += chunk.toString(); + }); + child.stderr.on('data', (chunk) => { + stderr += chunk.toString(); + }); + child.on('exit', (code) => { + if (code === 0) { + resolve({ stdout, stderr }); + return; + } + reject( + new Error( + `command failed (${command} ${args.join(' ')}): ${code}\n${stderr}`, + ), + ); + }); + }); +} diff --git a/e2e/consumer-proof-app/scripts/run-node.mjs b/e2e/consumer-proof-app/scripts/run-node.mjs new file mode 100644 index 0000000..525240e --- /dev/null +++ b/e2e/consumer-proof-app/scripts/run-node.mjs @@ -0,0 +1,58 @@ +#!/usr/bin/env node + +import { HOST_V1_MANIFEST } from '@blue-quickjs/abi-manifest'; +import { encodeDv } from '@blue-quickjs/dv'; +import { evaluate } from '@blue-quickjs/quickjs-runtime'; +import { + artifactPath, + createInputEnvelope, + nodeResultPath, + readJson, + snapshotFromResult, + writeJson, +} from './_helpers.mjs'; +import { createConsumerHost } from './consumer-host.mjs'; + +const args = parseArgs(process.argv.slice(2)); +const payload = await readJson(args.artifactPath ?? artifactPath); + +const host = createConsumerHost(); +const result = await evaluate({ + program: payload.artifact, + input: createInputEnvelope(), + gasLimit: BigInt(args.gasLimit), + manifest: HOST_V1_MANIFEST, + handlers: host.handlers, + tape: { capacity: 32 }, +}); + +const snapshot = snapshotFromResult(result, encodeDv); +const output = { + generatedAt: new Date().toISOString(), + gasLimit: args.gasLimit, + snapshot, + emitted: host.emitted, +}; + +await writeJson(nodeResultPath, output); +console.log(JSON.stringify({ nodeResultPath, snapshot }, null, 2)); + +function parseArgs(argv) { + let gasLimit = '1000000'; + let targetArtifactPath = null; + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--gas-limit') { + gasLimit = argv[index + 1] ?? gasLimit; + index += 1; + continue; + } + if (arg === '--artifact') { + targetArtifactPath = argv[index + 1] ?? targetArtifactPath; + index += 1; + continue; + } + throw new Error(`unknown argument: ${arg}`); + } + return { gasLimit, artifactPath: targetArtifactPath }; +} diff --git a/e2e/consumer-proof-app/src/browser/main.ts b/e2e/consumer-proof-app/src/browser/main.ts new file mode 100644 index 0000000..4aa25cc --- /dev/null +++ b/e2e/consumer-proof-app/src/browser/main.ts @@ -0,0 +1,116 @@ +import { HOST_V1_MANIFEST } from '@blue-quickjs/abi-manifest'; +import { encodeDv } from '@blue-quickjs/dv'; +import { evaluate } from '@blue-quickjs/quickjs-runtime'; +import { createConsumerHost } from '../shared/host.js'; + +declare global { + interface Window { + __CONSUMER_ARTIFACT__?: unknown; + __CONSUMER_GAS_LIMIT__?: string; + __CONSUMER_RESULT__?: unknown; + __runConsumerEvaluation?: (gasLimit: string) => Promise; + } +} + +const app = document.querySelector('[data-app]'); +if (app) { + app.innerHTML = + '

Consumer Proof Browser Runner

Idle
'; +} + +window.__runConsumerEvaluation = async (gasLimit: string) => { + if (!window.__CONSUMER_ARTIFACT__) { + throw new Error('missing __CONSUMER_ARTIFACT__ payload'); + } + const host = createConsumerHost(); + const result = await evaluate({ + program: window.__CONSUMER_ARTIFACT__ as never, + input: { + event: { type: 'consumer-proof' }, + eventCanonical: { type: 'consumer-proof' }, + steps: [], + currentContract: { id: 'consumer-proof' }, + currentContractCanonical: { id: { value: 'consumer-proof' } }, + }, + gasLimit: BigInt(gasLimit), + manifest: HOST_V1_MANIFEST, + handlers: host.handlers, + tape: { capacity: 32 }, + }); + + const tape = result.tape ?? []; + const snapshot = result.ok + ? { + stage: 'success', + resultHash: await sha256Hex(encodeDv(result.value)), + errorCode: null, + errorTag: null, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + tapeHash: + tape.length > 0 + ? await sha256Hex( + new TextEncoder().encode(stringifyWithBigInt(tape)), + ) + : null, + tapeLength: tape.length, + } + : { + stage: 'error', + resultHash: null, + errorCode: result.error.code, + errorTag: 'tag' in result.error ? result.error.tag : null, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + tapeHash: + tape.length > 0 + ? await sha256Hex( + new TextEncoder().encode(stringifyWithBigInt(tape)), + ) + : null, + tapeLength: tape.length, + }; + window.__CONSUMER_RESULT__ = snapshot; + return snapshot; +}; + +const gasLimit = window.__CONSUMER_GAS_LIMIT__; +if (window.__CONSUMER_ARTIFACT__ && gasLimit) { + void window + .__runConsumerEvaluation(gasLimit) + .then((snapshot) => { + const out = document.querySelector('[data-output]'); + if (out) { + out.textContent = JSON.stringify(snapshot, null, 2); + } + }) + .catch((error) => { + const out = document.querySelector('[data-output]'); + if (out) { + out.textContent = + error instanceof Error + ? (error.stack ?? error.message) + : String(error); + } + }); +} + +async function sha256Hex(bytes: Uint8Array): Promise { + const digest = await crypto.subtle.digest('SHA-256', toArrayBuffer(bytes)); + return [...new Uint8Array(digest)] + .map((chunk) => chunk.toString(16).padStart(2, '0')) + .join(''); +} + +function toArrayBuffer(data: Uint8Array): ArrayBuffer { + if (data.byteOffset === 0 && data.byteLength === data.buffer.byteLength) { + return data.buffer as ArrayBuffer; + } + return data.slice().buffer; +} + +function stringifyWithBigInt(value: unknown): string { + return JSON.stringify(value, (_key, item) => + typeof item === 'bigint' ? item.toString() : item, + ); +} diff --git a/e2e/consumer-proof-app/src/shared/consumer-workload.ts b/e2e/consumer-proof-app/src/shared/consumer-workload.ts new file mode 100644 index 0000000..eafefc0 --- /dev/null +++ b/e2e/consumer-proof-app/src/shared/consumer-workload.ts @@ -0,0 +1,26 @@ +import he from 'he'; +import { match } from 'path-to-regexp'; +import { satisfies } from 'semver'; + +const version = Host.v1.document.get('consumer/version'); +const encoded = Host.v1.document.get('consumer/encoded'); +const routePattern = Host.v1.document.get('consumer/route'); + +const releaseChecks = ['>=1.2.0 <2.0.0', '^1.2.0'].map((range) => + satisfies(version, range), +); +const routeMatch = match(routePattern)('/contract/42/release/1.2.3'); + +const summary = { + version, + releaseChecks, + decoded: he.decode(encoded), + routeParams: routeMatch?.params ?? null, +}; + +Host.v1.emit({ + type: 'consumer-proof-summary', + releaseOk: releaseChecks.every(Boolean), +}); + +export default summary; diff --git a/e2e/consumer-proof-app/src/shared/host.ts b/e2e/consumer-proof-app/src/shared/host.ts new file mode 100644 index 0000000..b6d1abb --- /dev/null +++ b/e2e/consumer-proof-app/src/shared/host.ts @@ -0,0 +1,32 @@ +export function createConsumerHost() { + const emitted = []; + return { + emitted, + handlers: { + document: { + get(path) { + switch (path) { + case 'consumer/version': + return { ok: '1.2.3', units: 1 }; + case 'consumer/encoded': + return { ok: '<b>deterministic</b>', units: 1 }; + case 'consumer/route': + return { ok: '/contract/:id/release/:version', units: 1 }; + default: + return { + err: { code: 'NOT_FOUND', tag: 'host/not_found' }, + units: 1, + }; + } + }, + getCanonical(path) { + return this.get(path); + }, + }, + emit(value) { + emitted.push(value); + return { ok: null, units: 1 }; + }, + }, + }; +} diff --git a/e2e/consumer-proof-app/vite.config.mts b/e2e/consumer-proof-app/vite.config.mts new file mode 100644 index 0000000..2300eab --- /dev/null +++ b/e2e/consumer-proof-app/vite.config.mts @@ -0,0 +1,48 @@ +import path from 'node:path'; +import { defineConfig } from 'vite'; + +export default defineConfig({ + root: import.meta.dirname, + resolve: { + alias: [ + { + // quickjs-wasm needs its built dist entry so import.meta.url resolves + // against packaged wasm assets instead of raw source files. + find: '@blue-quickjs/quickjs-wasm', + replacement: path.resolve( + import.meta.dirname, + '..', + '..', + 'libs', + 'quickjs-wasm', + 'dist', + 'index.js', + ), + }, + { + // This app lives outside the pnpm workspace, so local Nx/Vite builds + // need an explicit path back into repo source packages. + find: /^@blue-quickjs\/(.+)$/, + replacement: + path.resolve(import.meta.dirname, '..', '..', 'libs') + + '/$1/src/index.ts', + }, + ], + }, + server: { + host: '127.0.0.1', + port: 4320, + strictPort: true, + fs: { + allow: [path.resolve(import.meta.dirname, '..', '..')], + }, + }, + preview: { + host: '127.0.0.1', + port: 4320, + strictPort: true, + }, + optimizeDeps: { + exclude: ['@blue-quickjs/quickjs-wasm'], + }, +}); diff --git a/examples/01-basic-script/program.js b/examples/01-basic-script/program.js new file mode 100644 index 0000000..c0df6c9 --- /dev/null +++ b/examples/01-basic-script/program.js @@ -0,0 +1 @@ +(() => 1)(); diff --git a/examples/02-module-pack/entry.js b/examples/02-module-pack/entry.js new file mode 100644 index 0000000..e747934 --- /dev/null +++ b/examples/02-module-pack/entry.js @@ -0,0 +1,3 @@ +import { base } from './values.js'; + +export default base + 1; diff --git a/examples/02-module-pack/values.js b/examples/02-module-pack/values.js new file mode 100644 index 0000000..1a69880 --- /dev/null +++ b/examples/02-module-pack/values.js @@ -0,0 +1 @@ +export const base = 6; diff --git a/examples/03-library-reuse/binary-base64-entry.ts b/examples/03-library-reuse/binary-base64-entry.ts new file mode 100644 index 0000000..88caf05 --- /dev/null +++ b/examples/03-library-reuse/binary-base64-entry.ts @@ -0,0 +1,14 @@ +import { fromByteArray, toByteArray } from 'base64-js'; + +const payload = Uint8Array.from([1, 2, 3, 4, 5, 6, 7, 8]); +const encoded = fromByteArray(payload); +const decoded = toByteArray(encoded); +const sum = decoded.reduce((acc, value) => acc + value, 0); + +export default { + length: decoded.length, + sum, + first: decoded[0], + last: decoded[decoded.length - 1], + reencoded: encoded, +}; diff --git a/examples/03-library-reuse/chess-entry.ts b/examples/03-library-reuse/chess-entry.ts new file mode 100644 index 0000000..1c8596e --- /dev/null +++ b/examples/03-library-reuse/chess-entry.ts @@ -0,0 +1,7 @@ +import { Chess } from 'chess.js'; + +const game = new Chess(); +game.move('e4'); +game.move('e5'); + +export default game.move('e2e6') !== null; diff --git a/examples/04-promises-async/program.js b/examples/04-promises-async/program.js new file mode 100644 index 0000000..23ff68c --- /dev/null +++ b/examples/04-promises-async/program.js @@ -0,0 +1 @@ +(() => Promise.resolve(40).then((value) => value + 2))(); diff --git a/examples/05-promises-library-host/entry.js b/examples/05-promises-library-host/entry.js new file mode 100644 index 0000000..38d340b --- /dev/null +++ b/examples/05-promises-library-host/entry.js @@ -0,0 +1,6 @@ +import { plusOne } from './lib.js'; + +export default Promise.resolve(plusOne(41)).then((value) => { + Host.v1.emit({ phase: 'async-lib', value }); + return value; +}); diff --git a/examples/05-promises-library-host/lib.js b/examples/05-promises-library-host/lib.js new file mode 100644 index 0000000..c6d621c --- /dev/null +++ b/examples/05-promises-library-host/lib.js @@ -0,0 +1 @@ +export const plusOne = (value) => value + 1; diff --git a/examples/06-binary-host-v2/program.js b/examples/06-binary-host-v2/program.js new file mode 100644 index 0000000..1382340 --- /dev/null +++ b/examples/06-binary-host-v2/program.js @@ -0,0 +1,14 @@ +(() => { + const payload = Host.v2.document.get('bytes/payload'); + Host.v2.emit(payload); + let sum = 0; + for (const byte of payload) { + sum += byte; + } + return { + length: payload.byteLength, + first: payload[0], + last: payload[payload.byteLength - 1], + sum, + }; +})(); diff --git a/examples/07-console-shim/program.js b/examples/07-console-shim/program.js new file mode 100644 index 0000000..b196e20 --- /dev/null +++ b/examples/07-console-shim/program.js @@ -0,0 +1,4 @@ +(() => { + console.info('deterministic', 7); + return { ok: true }; +})(); diff --git a/examples/08-stable-sort/program.js b/examples/08-stable-sort/program.js new file mode 100644 index 0000000..f3d3ade --- /dev/null +++ b/examples/08-stable-sort/program.js @@ -0,0 +1,10 @@ +(() => { + const records = [ + { id: 'a', group: 1 }, + { id: 'b', group: 1 }, + { id: 'c', group: 2 }, + { id: 'd', group: 1 }, + ]; + records.sort((left, right) => left.group - right.group); + return records.map((record) => record.id); +})(); diff --git a/examples/09-kitchen-sink/entry.js b/examples/09-kitchen-sink/entry.js new file mode 100644 index 0000000..3e70a36 --- /dev/null +++ b/examples/09-kitchen-sink/entry.js @@ -0,0 +1,9 @@ +import { summarize } from './workflow.js'; + +export default (async () => { + const doc = document('path/to/doc'); + const canonical = document.canonical('path/to/doc'); + const result = await summarize(doc.path, canonical.canonical); + Host.v1.emit({ kind: 'kitchen', result }); + return result; +})(); diff --git a/examples/09-kitchen-sink/workflow.js b/examples/09-kitchen-sink/workflow.js new file mode 100644 index 0000000..87d0a4b --- /dev/null +++ b/examples/09-kitchen-sink/workflow.js @@ -0,0 +1,17 @@ +export async function summarize(path, canonical) { + const queue = []; + queueMicrotask(() => queue.push('micro')); + await Promise.resolve(); + const records = [ + { id: 'b', rank: 2 }, + { id: 'a', rank: 1 }, + { id: 'c', rank: 2 }, + ]; + records.sort((left, right) => left.rank - right.rank); + return { + path, + canonical, + order: records.map((record) => record.id).join(','), + queue: queue.join(','), + }; +} diff --git a/examples/10-max-gas-policy/program.js b/examples/10-max-gas-policy/program.js new file mode 100644 index 0000000..272e2c8 --- /dev/null +++ b/examples/10-max-gas-policy/program.js @@ -0,0 +1,7 @@ +(() => { + let sum = 0; + for (let i = 0; i < 10000; i += 1) { + sum += i; + } + return sum; +})(); diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..bfa18cf --- /dev/null +++ b/examples/README.md @@ -0,0 +1,82 @@ +# Deterministic examples corpus + +This corpus maps product-facing deterministic examples to runnable fixture +coverage already exercised by `smoke-node`, `smoke-web`, and the consensus +reproducibility report pipeline. + +## Run once (build + parity evidence) + +```bash +source tools/emsdk/emsdk_env.sh +pnpm nx test smoke-node +pnpm nx run smoke-web:e2e +node tools/consensus-parity/scripts/archive-consensus-reproducibility-report.mjs \ + --out-dir artifacts/reproducibility-consensus +``` + +Native diagnostic parity evidence (optional, non-consensus): + +```bash +pnpm nx build quickjs-native-harness +pnpm nx test quickjs-native-harness +node tools/quickjs-native-harness/scripts/archive-reproducibility-report.mjs +``` + +## Example matrix + +Canonical source snippets for each category live under `examples/0*/`. +Exact parity values come from the consensus report (`wasm-node` vs +`wasm-browser`). + +Consensus metadata snapshot (from latest local report run): + +- `engineBuildHash`: `f91091cb7feb788df340305a877a9cadb0c6f4d13aea8a7da4040b6367d178ea` +- `gasVersion`: `8` +- `executionProfile`: fixture-defined per example + +| # | Scenario | Profile | Source file(s) | Fixture key(s) | Expected result / gas evidence | +|---|---|---|---|---|---| +| 1 | Basic deterministic script | `baseline-v1` | `examples/01-basic-script/program.js` | `gas-sample-fixtures:return-1` | `resultHash=4bf5…459a`, `gasUsed=74`, `gasRemaining=999926` | +| 2 | Standard ESM module-pack | `baseline-v1` | `examples/02-module-pack/entry.js`, `examples/02-module-pack/values.js` | `module-pack-fixtures:module-pack-default-export` | `ok=true`, `valueHash=ca35…e879`, `gasUsed=204`, `gasRemaining=49796` | +| 3 | Real npm library reuse (`chess.js` + `base64-js`) | `compat-general-v1`, `compat-binary-v1` | `examples/03-library-reuse/chess-entry.ts`, `examples/03-library-reuse/binary-base64-entry.ts` | `chess-library:chess-e2e6`, `binary-library:base64-js-roundtrip` | chess: `value=false`, `gasUsed=2070610`; base64: `value.sum=36`, `gasUsed=3542` | +| 4 | Promises / async / microtasks | `compat-general-v1` | `examples/04-promises-async/program.js` | `determinism-fixtures:async-promise-chain` | `resultHash=7f83…5c53`, `gasUsed=128`, `gasRemaining=49872` | +| 5 | Promises + imported lib + host call | `compat-general-v1` | `examples/05-promises-library-host/entry.js`, `examples/05-promises-library-host/lib.js` | `module-pack-fixtures:module-pack-async-import-host-call` | `valueHash=7f83…5c53`, `tapeLength=1`, `gasUsed=345`, `gasRemaining=49655` | +| 6 | Binary / typed arrays / Host.v2 DV2 | `compat-binary-v1` | `examples/06-binary-host-v2/program.js` | `determinism-fixtures:compat-binary-host-v2-bytes-roundtrip` | `resultHash=a538…b2f8`, `tapeLength=2`, `gasUsed=253`, `gasRemaining=49747` | +| 7 | Console shim determinism | `compat-general-v1` | `examples/07-console-shim/program.js` | `determinism-fixtures:compat-console-shim` | `resultHash=20a9…cd02`, `tapeLength=1`, `gasUsed=139`, `gasRemaining=49861` | +| 8 | Stable sort determinism | `compat-general-v1` | `examples/08-stable-sort/program.js` | `determinism-fixtures:compat-stable-sort` | `resultHash=950f…3c04`, `gasUsed=1020`, `gasRemaining=48980` | +| 9 | Kitchen sink app | `compat-general-v1` | `examples/09-kitchen-sink/entry.js`, `examples/09-kitchen-sink/workflow.js` | `module-pack-fixtures:module-pack-kitchen-sink` | `valueHash=81c4…ee75`, `tapeLength=3`, `gasUsed=1444`, `gasRemaining=48556` | +| 10 | Max-gas / DoS boundary policy | `baseline-v1` | `examples/10-max-gas-policy/program.js` | `gas-boundary-fixtures:loop-10k` | success at `N=170099`, fail at `N-1=170098`, both `gasRemaining=0`, fail code `OOG` | + +### Per-example build/run validation commands + +All examples are validated by fixture-driven parity tests: + +```bash +source tools/emsdk/emsdk_env.sh +pnpm nx test smoke-node +pnpm nx run smoke-web:e2e +node tools/consensus-parity/scripts/archive-consensus-reproducibility-report.mjs \ + --out-dir artifacts/reproducibility-consensus +``` + +For native diagnostic comparison (non-consensus): + +```bash +pnpm nx build quickjs-native-harness +pnpm nx test quickjs-native-harness +node tools/quickjs-native-harness/scripts/archive-reproducibility-report.mjs +``` + +## Reading exact gas / boundary values + +- Consensus executor parity report: + - `node tools/consensus-parity/scripts/archive-consensus-reproducibility-report.mjs` +- Report includes: + - `metadata.engineBuildHash` + - `metadata.gasVersion` + - per-fixture `gasUsed`, `gasRemaining` + - per-boundary fixture `firstSuccessGas` and `lastFailureGas` + - mismatch counters for wasm-node vs wasm-browser. + +For release, treat wasm-node/wasm-browser report as normative consensus +evidence and native reports as diagnostic unless explicitly promoted by policy. diff --git a/libs/abi-manifest/src/index.ts b/libs/abi-manifest/src/index.ts index 35b9f04..252534c 100644 --- a/libs/abi-manifest/src/index.ts +++ b/libs/abi-manifest/src/index.ts @@ -1,2 +1,3 @@ export * from './lib/abi-manifest.js'; export * from './lib/host-v1-manifest.js'; +export * from './lib/host-v2-manifest.js'; diff --git a/libs/abi-manifest/src/lib/abi-manifest.spec.ts b/libs/abi-manifest/src/lib/abi-manifest.spec.ts index 480a055..fe82eb1 100644 --- a/libs/abi-manifest/src/lib/abi-manifest.spec.ts +++ b/libs/abi-manifest/src/lib/abi-manifest.spec.ts @@ -14,8 +14,35 @@ import { HOST_V1_HASH, HOST_V1_MANIFEST, } from './host-v1-manifest.js'; +import { + HOST_V2_BYTES, + HOST_V2_BYTES_HEX, + HOST_V2_HASH, + HOST_V2_MANIFEST, +} from './host-v2-manifest.js'; +import * as publicApi from '../index.js'; + +const expectAbiCode = ( + fn: () => unknown, + code: AbiManifestError['code'], +): void => { + try { + fn(); + throw new Error('expected function to throw'); + } catch (err) { + expect(err).toBeInstanceOf(AbiManifestError); + expect((err as AbiManifestError).code).toBe(code); + } +}; describe('abi-manifest', () => { + it('exposes the documented public API from the package index', () => { + expect(publicApi.HOST_V1_HASH).toBe(HOST_V1_HASH); + expect(publicApi.HOST_V2_HASH).toBe(HOST_V2_HASH); + expect(publicApi.validateAbiManifest).toBe(validateAbiManifest); + expect(publicApi.hashAbiManifestBytes).toBe(hashAbiManifestBytes); + }); + it('produces canonical bytes and hash for the Host.v1 manifest', () => { const { bytes, hash, manifest } = hashAbiManifest(HOST_V1_MANIFEST); expect(manifest).toEqual(validateAbiManifest(HOST_V1_MANIFEST)); @@ -24,6 +51,14 @@ describe('abi-manifest', () => { expect(hash).toEqual(HOST_V1_HASH); }); + it('produces canonical bytes and hash for the Host.v2 manifest', () => { + const { bytes, hash, manifest } = hashAbiManifest(HOST_V2_MANIFEST); + expect(manifest).toEqual(validateAbiManifest(HOST_V2_MANIFEST)); + expect(new Uint8Array(bytes)).toEqual(HOST_V2_BYTES); + expect(bytesToHex(bytes)).toEqual(HOST_V2_BYTES_HEX); + expect(hash).toEqual(HOST_V2_HASH); + }); + it('hashes manifests deterministically regardless of key insertion order', () => { const reordered = { functions: HOST_V1_MANIFEST.functions.map((fn) => ({ @@ -71,7 +106,19 @@ describe('abi-manifest', () => { ...HOST_V1_MANIFEST, functions: [...HOST_V1_MANIFEST.functions].reverse(), }; - expect(() => validateAbiManifest(badManifest)).toThrow(AbiManifestError); + expectAbiCode(() => validateAbiManifest(badManifest), 'UNSORTED'); + }); + + it('rejects duplicate function ids before canonical encoding', () => { + const manifest: AbiManifest = { + ...HOST_V1_MANIFEST, + functions: [ + HOST_V1_MANIFEST.functions[0], + { ...HOST_V1_MANIFEST.functions[1], fn_id: 1 }, + ], + }; + + expectAbiCode(() => validateAbiManifest(manifest), 'DUPLICATE'); }); it('rejects js_path collisions', () => { @@ -92,7 +139,7 @@ describe('abi-manifest', () => { ], }; - expect(() => validateAbiManifest(manifest)).toThrow(AbiManifestError); + expectAbiCode(() => validateAbiManifest(manifest), 'PATH_CONFLICT'); }); it('requires arg_utf8_max only on string args', () => { @@ -125,7 +172,26 @@ describe('abi-manifest', () => { ], }; - expect(() => encodeAbiManifest(manifest)).toThrow(AbiManifestError); + expectAbiCode(() => encodeAbiManifest(manifest), 'INVALID_VALUE'); + }); + + it('requires arg_utf8_max to match arity', () => { + const manifest: AbiManifest = { + ...HOST_V1_MANIFEST, + functions: [ + { + ...HOST_V1_MANIFEST.functions[0], + arity: 1, + arg_schema: [{ type: 'string' }], + limits: { + ...HOST_V1_MANIFEST.functions[0].limits, + arg_utf8_max: [8, 16], + }, + }, + ], + }; + + expectAbiCode(() => validateAbiManifest(manifest), 'INVALID_VALUE'); }); it('rejects unsorted error_codes', () => { @@ -142,7 +208,24 @@ describe('abi-manifest', () => { ], }; - expect(() => validateAbiManifest(manifest)).toThrow(AbiManifestError); + expectAbiCode(() => validateAbiManifest(manifest), 'UNSORTED'); + }); + + it('rejects duplicate error_codes', () => { + const manifest: AbiManifest = { + ...HOST_V1_MANIFEST, + functions: [ + { + ...HOST_V1_MANIFEST.functions[0], + error_codes: [ + { code: 'INVALID_PATH', tag: 'host/invalid_path' }, + { code: 'INVALID_PATH', tag: 'host/invalid_path_again' }, + ], + }, + ], + }; + + expectAbiCode(() => validateAbiManifest(manifest), 'DUPLICATE'); }); it('rejects reserved host error codes', () => { @@ -158,7 +241,7 @@ describe('abi-manifest', () => { ], }; - expect(() => validateAbiManifest(manifest)).toThrow(AbiManifestError); + expectAbiCode(() => validateAbiManifest(manifest), 'INVALID_VALUE'); }); it('rejects forbidden js_path segments', () => { @@ -172,17 +255,66 @@ describe('abi-manifest', () => { ], }; - expect(() => validateAbiManifest(manifest)).toThrow(AbiManifestError); + expectAbiCode(() => validateAbiManifest(manifest), 'INVALID_VALUE'); + }); + + it('rejects malformed js_path segments', () => { + const manifest: AbiManifest = { + ...HOST_V1_MANIFEST, + functions: [ + { + ...HOST_V1_MANIFEST.functions[0], + js_path: ['emit.value'], + }, + ], + }; + + expectAbiCode(() => validateAbiManifest(manifest), 'INVALID_VALUE'); }); it('rejects unknown fields in function entries', () => { const manifest: AbiManifest = { ...HOST_V1_MANIFEST, - // @ts-expect-error extra field for validation test - functions: [{ ...HOST_V1_MANIFEST.functions[0], extra: true }], + functions: [ + { + ...HOST_V1_MANIFEST.functions[0], + extra: true, + } as unknown as AbiManifest['functions'][number], + ], }; - expect(() => validateAbiManifest(manifest)).toThrow(AbiManifestError); + expectAbiCode(() => validateAbiManifest(manifest), 'UNKNOWN_FIELD'); + }); + + it('rejects missing manifest fields and non-plain manifest roots', () => { + expectAbiCode( + () => + validateAbiManifest({ + abi_id: 'Host.v1', + abi_version: 1, + } as AbiManifest), + 'MISSING_FIELD', + ); + expectAbiCode( + () => validateAbiManifest([] as unknown as AbiManifest), + 'INVALID_TYPE', + ); + expectAbiCode( + () => + validateAbiManifest({ + ...HOST_V1_MANIFEST, + abi_id: '', + }), + 'INVALID_VALUE', + ); + expectAbiCode( + () => + validateAbiManifest({ + ...HOST_V1_MANIFEST, + abi_id: 1, + } as unknown as AbiManifest), + 'INVALID_TYPE', + ); }); it('rejects -0 in uint32 fields', () => { @@ -190,7 +322,78 @@ describe('abi-manifest', () => { ...HOST_V1_MANIFEST, abi_version: -0, }; - expect(() => validateAbiManifest(manifest)).toThrow(AbiManifestError); + expectAbiCode(() => validateAbiManifest(manifest), 'INVALID_VALUE'); + }); + + it('rejects invalid function values with precise validation codes', () => { + expectAbiCode( + () => + validateAbiManifest({ + ...HOST_V1_MANIFEST, + functions: [ + { + ...HOST_V1_MANIFEST.functions[0], + effect: 'WRITE', + }, + ], + } as unknown as AbiManifest), + 'INVALID_VALUE', + ); + expectAbiCode( + () => + validateAbiManifest({ + ...HOST_V1_MANIFEST, + functions: [ + { + ...HOST_V1_MANIFEST.functions[0], + arity: 2, + }, + ], + }), + 'INVALID_VALUE', + ); + expectAbiCode( + () => + validateAbiManifest({ + ...HOST_V1_MANIFEST, + functions: [ + { + ...HOST_V1_MANIFEST.functions[0], + return_schema: { type: 'bytes' }, + }, + ], + } as unknown as AbiManifest), + 'INVALID_VALUE', + ); + expectAbiCode( + () => + validateAbiManifest({ + ...HOST_V1_MANIFEST, + functions: [ + { + ...HOST_V1_MANIFEST.functions[0], + limits: { + ...HOST_V1_MANIFEST.functions[0].limits, + max_request_bytes: DV_LIMIT_DEFAULTS.maxEncodedBytes + 1, + }, + }, + ], + }), + 'OUT_OF_RANGE', + ); + expectAbiCode( + () => + validateAbiManifest({ + ...HOST_V1_MANIFEST, + functions: [ + { + ...HOST_V1_MANIFEST.functions[0], + fn_id: 1.5, + }, + ], + }), + 'INVALID_TYPE', + ); }); it('rejects manifests whose gas charges overflow uint64 bounds', () => { @@ -222,7 +425,7 @@ describe('abi-manifest', () => { ], }; - expect(() => validateAbiManifest(manifest)).toThrow(AbiManifestError); + expectAbiCode(() => validateAbiManifest(manifest), 'OUT_OF_RANGE'); }); it('hashes existing bytes directly', () => { @@ -231,5 +434,11 @@ describe('abi-manifest', () => { const bytes = encodeAbiManifest(HOST_V1_MANIFEST); expect(new Uint8Array(bytes)).toEqual(HOST_V1_BYTES); expect(hashAbiManifestBytes(bytes)).toEqual(HOST_V1_HASH); + + const padded = Uint8Array.from([0xff, ...HOST_V1_BYTES, 0xff]); + const view = new DataView(padded.buffer, 1, HOST_V1_BYTES.length); + expect(hashAbiManifestBytes(view)).toEqual(HOST_V1_HASH); + const buffer = HOST_V1_BYTES.buffer.slice(0) as ArrayBuffer; + expect(hashAbiManifestBytes(buffer)).toEqual(HOST_V1_HASH); }); }); diff --git a/libs/abi-manifest/src/lib/host-v2-manifest.ts b/libs/abi-manifest/src/lib/host-v2-manifest.ts new file mode 100644 index 0000000..69c60a0 --- /dev/null +++ b/libs/abi-manifest/src/lib/host-v2-manifest.ts @@ -0,0 +1,16 @@ +import { bytesToHex } from '@noble/hashes/utils'; +import type { AbiManifest } from './abi-manifest.js'; +import { hashAbiManifest } from './abi-manifest.js'; +import { HOST_V1_MANIFEST } from './host-v1-manifest.js'; + +export const HOST_V2_MANIFEST: AbiManifest = { + ...HOST_V1_MANIFEST, + abi_id: 'Host.v2', + abi_version: 2, +}; + +const HOST_V2_CANONICAL = hashAbiManifest(HOST_V2_MANIFEST); + +export const HOST_V2_BYTES = HOST_V2_CANONICAL.bytes; +export const HOST_V2_HASH = HOST_V2_CANONICAL.hash; +export const HOST_V2_BYTES_HEX = bytesToHex(HOST_V2_BYTES); diff --git a/libs/abi-manifest/vite.config.ts b/libs/abi-manifest/vite.config.ts index 97a1d87..2de5f7a 100644 --- a/libs/abi-manifest/vite.config.ts +++ b/libs/abi-manifest/vite.config.ts @@ -19,6 +19,15 @@ export default defineConfig(() => ({ coverage: { reportsDirectory: './test-output/vitest/coverage', provider: 'v8' as const, + all: true, + include: ['src/**/*.{ts,mts}'], + exclude: ['src/**/*.{test,spec}.{ts,mts}'], + thresholds: { + lines: 40, + functions: 40, + branches: 40, + statements: 40, + }, }, }, })); diff --git a/libs/deterministic-builder/README.md b/libs/deterministic-builder/README.md new file mode 100644 index 0000000..c29037e --- /dev/null +++ b/libs/deterministic-builder/README.md @@ -0,0 +1,15 @@ +# @blue-quickjs/deterministic-builder + +Facade package for deterministic builder APIs. + +This package re-exports the builder functionality currently implemented in +`@blue-quickjs/deterministic-bundler`: + +- `buildDeterministicModulePack(...)` +- `bundleDeterministicProgram(...)` +- `scanCompatibility(...)` + +Build/test: + +- `pnpm nx build deterministic-builder` +- `pnpm nx test deterministic-builder` diff --git a/libs/deterministic-builder/eslint.config.mjs b/libs/deterministic-builder/eslint.config.mjs new file mode 100644 index 0000000..0a23ec0 --- /dev/null +++ b/libs/deterministic-builder/eslint.config.mjs @@ -0,0 +1,25 @@ +import baseConfig from '../../eslint.config.mjs'; + +export default [ + ...baseConfig, + { + files: ['**/*.json'], + rules: { + '@nx/dependency-checks': [ + 'error', + { + ignoredFiles: [ + '{projectRoot}/eslint.config.{js,cjs,mjs,ts,cts,mts}', + '{projectRoot}/vite.config.{js,ts,mjs,mts}', + ], + }, + ], + }, + languageOptions: { + parser: await import('jsonc-eslint-parser'), + }, + }, + { + ignores: ['**/out-tsc'], + }, +]; diff --git a/libs/deterministic-builder/package.json b/libs/deterministic-builder/package.json new file mode 100644 index 0000000..ab32939 --- /dev/null +++ b/libs/deterministic-builder/package.json @@ -0,0 +1,36 @@ +{ + "name": "@blue-quickjs/deterministic-builder", + "version": "0.4.1", + "type": "module", + "main": "./dist/index.js", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + "./package.json": "./package.json", + ".": { + "@blue-quickjs/source": "./src/index.ts", + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" + } + }, + "files": [ + "dist", + "!**/*.tsbuildinfo" + ], + "nx": { + "name": "deterministic-builder" + }, + "dependencies": { + "@blue-quickjs/deterministic-bundler": "workspace:*", + "tslib": "^2.3.0" + }, + "license": "MIT", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/bluecontract/blue-quickjs.git" + } +} diff --git a/libs/deterministic-builder/src/index.ts b/libs/deterministic-builder/src/index.ts new file mode 100644 index 0000000..0053b9a --- /dev/null +++ b/libs/deterministic-builder/src/index.ts @@ -0,0 +1,18 @@ +export { + buildDeterministicModulePack, + bundleDeterministicProgram, + scanCompatibility, + DeterministicBundlerError as DeterministicBuilderError, + type BuildDeterministicModulePackOptions, + type BuildDeterministicModulePackResult, + type BundleDeterministicProgramOptions, + type BundleDeterministicProgramResult, + type CompatibilityDiagnostic, + type CompatibilityReportV1, + type CompatibilityScanResult, + type DeterministicExecutionProfile, + type ModulePackModule, + type ModulePackOriginMeta, + type ModulePackV1, + type ProgramArtifactV2, +} from '@blue-quickjs/deterministic-bundler'; diff --git a/libs/deterministic-builder/src/lib/deterministic-builder.spec.ts b/libs/deterministic-builder/src/lib/deterministic-builder.spec.ts new file mode 100644 index 0000000..bd00ace --- /dev/null +++ b/libs/deterministic-builder/src/lib/deterministic-builder.spec.ts @@ -0,0 +1,23 @@ +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { buildDeterministicModulePack } from '../index.js'; + +describe('deterministic-builder facade', () => { + it('builds a module pack via deterministic-bundler implementation', async () => { + const fixtureDir = fs.mkdtempSync( + path.join(os.tmpdir(), 'det-builder-facade-fixture-'), + ); + const entryPath = path.join(fixtureDir, 'entry.ts'); + fs.writeFileSync(entryPath, 'export default 7;', 'utf8'); + + const built = await buildDeterministicModulePack({ + absWorkingDir: fixtureDir, + entryPath: 'entry.ts', + }); + + expect(built.modulePack.version).toBe(1); + expect(built.modulePack.graphHash).toMatch(/^[0-9a-f]{64}$/); + expect(built.compatibility.ok).toBe(true); + }); +}); diff --git a/libs/deterministic-builder/tsconfig.json b/libs/deterministic-builder/tsconfig.json new file mode 100644 index 0000000..62ebbd9 --- /dev/null +++ b/libs/deterministic-builder/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../tsconfig.base.json", + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/libs/deterministic-builder/tsconfig.lib.json b/libs/deterministic-builder/tsconfig.lib.json new file mode 100644 index 0000000..30128ee --- /dev/null +++ b/libs/deterministic-builder/tsconfig.lib.json @@ -0,0 +1,32 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "baseUrl": ".", + "rootDir": "src", + "outDir": "dist", + "tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo", + "emitDeclarationOnly": false, + "forceConsistentCasingInFileNames": true, + "types": ["node"] + }, + "include": ["src/**/*.ts"], + "references": [ + { + "path": "../deterministic-bundler/tsconfig.lib.json" + } + ], + "exclude": [ + "vite.config.ts", + "vite.config.mts", + "vitest.config.ts", + "vitest.config.mts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx" + ] +} diff --git a/libs/deterministic-builder/tsconfig.spec.json b/libs/deterministic-builder/tsconfig.spec.json new file mode 100644 index 0000000..f68d9d3 --- /dev/null +++ b/libs/deterministic-builder/tsconfig.spec.json @@ -0,0 +1,34 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "./out-tsc/vitest", + "types": [ + "vitest/globals", + "vitest/importMeta", + "vite/client", + "node", + "vitest" + ], + "forceConsistentCasingInFileNames": true + }, + "include": [ + "vite.config.ts", + "vite.config.mts", + "vitest.config.ts", + "vitest.config.mts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx", + "src/**/*.d.ts" + ], + "references": [ + { + "path": "./tsconfig.lib.json" + } + ] +} diff --git a/libs/deterministic-builder/vite.config.ts b/libs/deterministic-builder/vite.config.ts new file mode 100644 index 0000000..2744ba1 --- /dev/null +++ b/libs/deterministic-builder/vite.config.ts @@ -0,0 +1,29 @@ +/// +import { defineConfig } from 'vite'; + +export default defineConfig(() => ({ + root: import.meta.dirname, + cacheDir: '../../node_modules/.vite/libs/deterministic-builder', + plugins: [], + test: { + name: 'deterministic-builder', + watch: false, + globals: true, + environment: 'node', + include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], + reporters: ['default'], + coverage: { + reportsDirectory: './test-output/vitest/coverage', + provider: 'v8' as const, + all: true, + include: ['src/**/*.{ts,mts}'], + exclude: ['src/**/*.{test,spec}.{ts,mts}'], + thresholds: { + lines: 40, + functions: 40, + branches: 40, + statements: 40, + }, + }, + }, +})); diff --git a/libs/deterministic-bundler/README.md b/libs/deterministic-bundler/README.md new file mode 100644 index 0000000..68fc4a9 --- /dev/null +++ b/libs/deterministic-bundler/README.md @@ -0,0 +1,14 @@ +# @blue-quickjs/deterministic-bundler + +Deterministic build tooling for `blue-quickjs` artifacts. + +- `bundleDeterministicProgram(...)` flattens static module graphs into one + script string for transitional script-mode execution. +- `buildDeterministicModulePack(...)` emits canonical `ModulePack.v1` output, + compatibility diagnostics, and optional script artifacts. +- Both APIs produce stable SHA-256 hashes and deterministic compatibility scans. + +Build/test: + +- `pnpm nx build deterministic-bundler` +- `pnpm nx test deterministic-bundler` diff --git a/libs/deterministic-bundler/eslint.config.mjs b/libs/deterministic-bundler/eslint.config.mjs new file mode 100644 index 0000000..0a23ec0 --- /dev/null +++ b/libs/deterministic-bundler/eslint.config.mjs @@ -0,0 +1,25 @@ +import baseConfig from '../../eslint.config.mjs'; + +export default [ + ...baseConfig, + { + files: ['**/*.json'], + rules: { + '@nx/dependency-checks': [ + 'error', + { + ignoredFiles: [ + '{projectRoot}/eslint.config.{js,cjs,mjs,ts,cts,mts}', + '{projectRoot}/vite.config.{js,ts,mjs,mts}', + ], + }, + ], + }, + languageOptions: { + parser: await import('jsonc-eslint-parser'), + }, + }, + { + ignores: ['**/out-tsc'], + }, +]; diff --git a/libs/deterministic-bundler/package.json b/libs/deterministic-bundler/package.json new file mode 100644 index 0000000..659ee88 --- /dev/null +++ b/libs/deterministic-bundler/package.json @@ -0,0 +1,38 @@ +{ + "name": "@blue-quickjs/deterministic-bundler", + "version": "0.4.1", + "type": "module", + "main": "./dist/index.js", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + "./package.json": "./package.json", + ".": { + "@blue-quickjs/source": "./src/index.ts", + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" + } + }, + "files": [ + "dist", + "!**/*.tsbuildinfo" + ], + "nx": { + "name": "deterministic-bundler" + }, + "dependencies": { + "@blue-quickjs/execution-profiles": "workspace:*", + "acorn": "^8.15.0", + "esbuild": "^0.27.4", + "tslib": "^2.3.0" + }, + "license": "MIT", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/bluecontract/blue-quickjs.git" + } +} diff --git a/libs/deterministic-bundler/src/index.ts b/libs/deterministic-bundler/src/index.ts new file mode 100644 index 0000000..11efbac --- /dev/null +++ b/libs/deterministic-bundler/src/index.ts @@ -0,0 +1 @@ +export * from './lib/deterministic-bundler.js'; diff --git a/libs/deterministic-bundler/src/lib/deterministic-bundler.spec.ts b/libs/deterministic-bundler/src/lib/deterministic-bundler.spec.ts new file mode 100644 index 0000000..1d0c92d --- /dev/null +++ b/libs/deterministic-bundler/src/lib/deterministic-bundler.spec.ts @@ -0,0 +1,472 @@ +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { + buildDeterministicModulePack, + bundleDeterministicProgram, + DeterministicBundlerError, + scanCompatibility, +} from './deterministic-bundler.js'; + +describe('bundleDeterministicProgram', () => { + it('produces deterministic code and hash for the same inputs', async () => { + const fixtureDir = createFixtureDir(); + writeFixture(fixtureDir, 'util.ts', 'export const value = 7;'); + writeFixture( + fixtureDir, + 'entry.ts', + "import { value } from './util'; export default value;", + ); + + const first = await bundleDeterministicProgram({ + absWorkingDir: fixtureDir, + entryPath: 'entry.ts', + }); + const second = await bundleDeterministicProgram({ + absWorkingDir: fixtureDir, + entryPath: 'entry.ts', + }); + + expect(first.code).toBe(second.code); + expect(first.contentHash).toBe(second.contentHash); + expect(first.code).toContain(';__blueDeterministicBundle.default;'); + expect(first.meta.modulePaths).toEqual(second.meta.modulePaths); + expect(first.meta.modulePaths).toHaveLength(2); + expect(first.meta.compatibility.ok).toBe(true); + }); + + it('rejects baseline bundles that use RegExp literals', async () => { + const fixtureDir = createFixtureDir(); + writeFixture( + fixtureDir, + 'entry.ts', + "export default /a/.test('a') && Math.random() > -1;", + ); + + const error = await bundleDeterministicProgram({ + absWorkingDir: fixtureDir, + entryPath: 'entry.ts', + }) + .then(() => { + throw new Error('expected compatibility failure'); + }) + .catch((caught) => caught); + + expect(error).toBeInstanceOf(DeterministicBundlerError); + const bundlerError = error as DeterministicBundlerError; + expect( + bundlerError.diagnostics.some( + (diagnostic) => diagnostic.ruleId === 'regexp_literal_disabled', + ), + ).toBe(true); + expect( + bundlerError.diagnostics.some( + (diagnostic) => diagnostic.ruleId === 'math_random_disabled', + ), + ).toBe(true); + }); + + it('allows regexp usage under compat-general profile', async () => { + const fixtureDir = createFixtureDir(); + writeFixture(fixtureDir, 'entry.ts', "export default /a/.test('a');"); + + const bundled = await bundleDeterministicProgram({ + absWorkingDir: fixtureDir, + entryPath: 'entry.ts', + profile: 'compat-general-v1', + }); + + expect(bundled.meta.compatibility.ok).toBe(true); + expect(bundled.meta.profile).toBe('compat-general-v1'); + }); + + it('scans tree-shaken bundle output for compatibility', async () => { + const fixtureDir = createFixtureDir(); + writeFixture( + fixtureDir, + 'util.ts', + 'export const value = 7; export function unusedClock() { return Date.now(); }', + ); + writeFixture( + fixtureDir, + 'entry.ts', + "import { value } from './util'; export default value;", + ); + + const bundled = await bundleDeterministicProgram({ + absWorkingDir: fixtureDir, + entryPath: 'entry.ts', + }); + + expect(bundled.meta.compatibility.ok).toBe(true); + expect(bundled.code).not.toContain('Date.now'); + }); + + it('bundles chess.js fixture only under compat-general profile', async () => { + const workspaceRoot = path.resolve(process.cwd(), '../..'); + + await expect( + bundleDeterministicProgram({ + absWorkingDir: workspaceRoot, + entryPath: 'libs/test-harness/fixtures/library-reuse/chess-entry.ts', + }), + ).rejects.toBeInstanceOf(DeterministicBundlerError); + + const bundled = await bundleDeterministicProgram({ + absWorkingDir: workspaceRoot, + entryPath: 'libs/test-harness/fixtures/library-reuse/chess-entry.ts', + profile: 'compat-general-v1', + }); + + expect(bundled.meta.compatibility.ok).toBe(true); + expect(bundled.contentHash).toMatch(/^[0-9a-f]{64}$/); + expect(bundled.code.length).toBeGreaterThan(1000); + }); +}); + +describe('scanCompatibility', () => { + it('rejects unknown execution profiles', () => { + expect(() => + scanCompatibility({ + profile: 'baseline-typo-v1' as unknown as never, + sourceByPath: { + '/tmp/sample.ts': 'export default 1;', + }, + }), + ).toThrow(/profile must be one of/i); + }); + + it('detects dynamic import and node builtins deterministically', () => { + const scan = scanCompatibility({ + sourceByPath: { + '/tmp/sample.ts': + "import fs from 'node:fs'; const x = import('./next.js'); export default x;", + }, + }); + + expect(scan.ok).toBe(false); + expect(scan.diagnostics).toEqual([ + { + filePath: '/tmp/sample.ts', + ruleId: 'dynamic_import_disabled', + message: 'dynamic import() is disabled in deterministic mode', + }, + { + filePath: '/tmp/sample.ts', + ruleId: 'node_builtin_import', + message: 'node builtin import is disabled: node:fs', + }, + ]); + }); + + it('detects node builtin named re-exports', () => { + const scan = scanCompatibility({ + sourceByPath: { + '/tmp/sample.ts': "export { readFileSync } from 'node:fs';", + }, + }); + + expect(scan.ok).toBe(false); + expect(scan.diagnostics).toEqual([ + { + filePath: '/tmp/sample.ts', + ruleId: 'node_builtin_import', + message: 'node builtin import is disabled: node:fs', + }, + ]); + }); + + it('allows regexp and console usage under compat-general profile', () => { + const scan = scanCompatibility({ + profile: 'compat-general-v1', + sourceByPath: { + '/tmp/sample.ts': "console.log(/a/.test('a')); export default true;", + }, + }); + + expect(scan.ok).toBe(true); + }); + + it('allows typed arrays under compat-binary profile', () => { + const scan = scanCompatibility({ + profile: 'compat-binary-v1', + sourceByPath: { + '/tmp/sample.ts': 'export default new Uint8Array([1, 2, 3]).length;', + }, + }); + + expect(scan.ok).toBe(true); + }); + + it('detects forbidden member-call APIs under the baseline profile', () => { + const scan = scanCompatibility({ + sourceByPath: { + '/tmp/sample.ts': ` + Date.now(); + WebAssembly.instantiate(bytes); + Atomics.add(view, 0, 1); + Uint8Array.from([1, 2, 3]); + ArrayBuffer.isView(view); + `, + }, + }); + + expect(scan.ok).toBe(false); + expect(scan.diagnostics.map((diagnostic) => diagnostic.ruleId)).toEqual([ + 'arraybuffer_disabled', + 'atomics_disabled', + 'date_disabled', + 'typed_array_disabled', + 'webassembly_disabled', + ]); + }); +}); + +describe('buildDeterministicModulePack', () => { + it('rejects unknown execution profiles before building artifacts', async () => { + await expect( + buildDeterministicModulePack({ + absWorkingDir: createFixtureDir(), + entryPath: 'missing.ts', + profile: 'compat-typo-v1' as unknown as never, + emitProgramArtifact: true, + }), + ).rejects.toThrow(/profile must be one of/i); + }); + + it('builds deterministic module-pack output for workspace TS fixture', async () => { + const fixtureDir = createFixtureDir(); + writeFixture(fixtureDir, 'lib/util.ts', 'export const value = 11;'); + writeFixture( + fixtureDir, + 'entry.ts', + "import { value } from './lib/util'; export default value;", + ); + + const first = await buildDeterministicModulePack({ + absWorkingDir: fixtureDir, + entryPath: 'entry.ts', + emitScriptArtifact: true, + }); + const second = await buildDeterministicModulePack({ + absWorkingDir: fixtureDir, + entryPath: 'entry.ts', + emitScriptArtifact: true, + }); + + expect(first.modulePack.version).toBe(1); + expect(first.modulePack.entryExport).toBe('default'); + expect(first.modulePack.modules.length).toBeGreaterThanOrEqual(1); + expect(first.modulePack.graphHash).toMatch(/^[0-9a-f]{64}$/); + expect(second.modulePack.graphHash).toBe(first.modulePack.graphHash); + expect(second.modulePack.modules).toEqual(first.modulePack.modules); + expect(first.compatibility.ok).toBe(true); + expect(first.compatibilityReport.version).toBe(1); + expect(first.compatibilityReport.profile).toBe('baseline-v1'); + expect(first.compatibilityReport.moduleCount).toBe( + first.modulePack.modules.length, + ); + expect(first.scriptArtifact?.contentHash).toMatch(/^[0-9a-f]{64}$/); + }); + + it('builds module-pack for external npm ESM fixture', async () => { + const fixtureDir = createFixtureDir(); + writeFixture( + fixtureDir, + 'node_modules/esm-lib/package.json', + JSON.stringify( + { + name: 'esm-lib', + version: '1.0.0', + type: 'module', + exports: './index.js', + }, + null, + 2, + ), + ); + writeFixture( + fixtureDir, + 'node_modules/esm-lib/index.js', + 'export const value = 41; export default value;', + ); + writeFixture( + fixtureDir, + 'entry.ts', + "import { value } from 'esm-lib'; export default value + 1;", + ); + + const built = await buildDeterministicModulePack({ + absWorkingDir: fixtureDir, + entryPath: 'entry.ts', + profile: 'compat-general-v1', + dependencyIntegrity: SAMPLE_HASH, + }); + + expect(built.compatibility.ok).toBe(true); + expect( + built.modulePack.modules.some( + (module) => module.originMeta?.packageName === 'esm-lib', + ), + ).toBe(true); + expect( + built.modulePack.modules.every( + (module) => !module.source.includes(normalizePath(fixtureDir)), + ), + ).toBe(true); + }); + + it('builds module-pack for external npm CJS fixture', async () => { + const fixtureDir = createFixtureDir(); + writeFixture( + fixtureDir, + 'node_modules/cjs-lib/package.json', + JSON.stringify( + { + name: 'cjs-lib', + version: '2.0.0', + main: 'index.cjs', + }, + null, + 2, + ), + ); + writeFixture( + fixtureDir, + 'node_modules/cjs-lib/index.cjs', + "module.exports = { isValid: (value) => value === '1.2.3' };", + ); + writeFixture( + fixtureDir, + 'entry.ts', + "import lib from 'cjs-lib'; export default lib.isValid('1.2.3');", + ); + + const built = await buildDeterministicModulePack({ + absWorkingDir: fixtureDir, + entryPath: 'entry.ts', + profile: 'compat-general-v1', + dependencyIntegrity: SAMPLE_HASH, + }); + + expect(built.compatibility.ok).toBe(true); + expect( + built.modulePack.modules.some( + (module) => module.originMeta?.packageName === 'cjs-lib', + ), + ).toBe(true); + expect( + built.modulePack.modules.every((module) => + module.sourceMap + ? !module.sourceMap.includes(normalizePath(fixtureDir)) + : true, + ), + ).toBe(true); + }); + + it('emits ProgramArtifact.v2 when requested', async () => { + const fixtureDir = createFixtureDir(); + writeFixture(fixtureDir, 'entry.ts', 'export default 99;'); + + const built = await buildDeterministicModulePack({ + absWorkingDir: fixtureDir, + entryPath: 'entry.ts', + emitProgramArtifact: true, + abiManifestHash: SAMPLE_HASH, + engineBuildHash: SAMPLE_HASH, + }); + + expect(built.programArtifact).toEqual({ + version: 2, + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: SAMPLE_HASH, + engineBuildHash: SAMPLE_HASH, + executionProfile: 'baseline-v1', + sourceKind: 'module-pack', + source: { + modulePack: built.modulePack, + }, + }); + }); + + it('keeps graphHash stable for a golden fixture', async () => { + const fixtureDir = createFixtureDir(); + writeFixture(fixtureDir, 'lib/value.ts', 'export const value = 5;'); + writeFixture( + fixtureDir, + 'entry.ts', + "import { value } from './lib/value'; export default value * 2;", + ); + + const built = await buildDeterministicModulePack({ + absWorkingDir: fixtureDir, + entryPath: 'entry.ts', + builderVersion: 'golden-builder', + dependencyIntegrity: SAMPLE_HASH, + }); + + expect(built.modulePack.graphHash).toBe( + '191c77a4a6235a20f460887a4bdad13b09ab34bf0f841fcad68504e3e757b6b4', + ); + }); + + it('keeps dependency integrity stable across lockfile line endings', async () => { + const lfRoot = createFixtureDir(); + const crlfRoot = createFixtureDir(); + writeFixture(lfRoot, 'pnpm-lock.yaml', 'lockfileVersion: 9.0\n'); + writeFixture(crlfRoot, 'pnpm-lock.yaml', 'lockfileVersion: 9.0\r\n'); + writeFixture(lfRoot, 'fixture/entry.ts', 'export default 1;'); + writeFixture(crlfRoot, 'fixture/entry.ts', 'export default 1;'); + + const lfBuilt = await buildDeterministicModulePack({ + absWorkingDir: path.join(lfRoot, 'fixture'), + entryPath: 'entry.ts', + }); + const crlfBuilt = await buildDeterministicModulePack({ + absWorkingDir: path.join(crlfRoot, 'fixture'), + entryPath: 'entry.ts', + }); + + expect(crlfBuilt.modulePack.dependencyIntegrity).toBe( + lfBuilt.modulePack.dependencyIntegrity, + ); + expect(crlfBuilt.modulePack.graphHash).toBe(lfBuilt.modulePack.graphHash); + }); + + it('rejects non-hex dependencyIntegrity overrides', async () => { + const fixtureDir = createFixtureDir(); + writeFixture(fixtureDir, 'entry.ts', 'export default 1;'); + + await expect( + buildDeterministicModulePack({ + absWorkingDir: fixtureDir, + entryPath: 'entry.ts', + dependencyIntegrity: 'test-integrity', + }), + ).rejects.toThrow( + 'dependencyIntegrity must be a lowercase 64-char hex string', + ); + }); +}); + +function createFixtureDir(): string { + return fs.mkdtempSync(path.join(os.tmpdir(), 'det-bundler-fixture-')); +} + +function writeFixture( + dir: string, + relativePath: string, + contents: string, +): void { + const filePath = path.join(dir, relativePath); + fs.mkdirSync(path.dirname(filePath), { recursive: true }); + fs.writeFileSync(filePath, contents, 'utf8'); +} + +function normalizePath(input: string): string { + return input.split(path.sep).join('/'); +} + +const SAMPLE_HASH = + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'; diff --git a/libs/deterministic-bundler/src/lib/deterministic-bundler.ts b/libs/deterministic-bundler/src/lib/deterministic-bundler.ts new file mode 100644 index 0000000..e78d394 --- /dev/null +++ b/libs/deterministic-bundler/src/lib/deterministic-bundler.ts @@ -0,0 +1,1242 @@ +import { build } from 'esbuild'; +import { parse } from 'acorn'; +import { builtinModules } from 'node:module'; +import fs from 'node:fs'; +import path from 'node:path'; +import { createHash } from 'node:crypto'; +import { + executionProfileHasCapability, + isKnownExecutionProfile, + listExecutionProfiles, + type PublicExecutionProfile, +} from '@blue-quickjs/execution-profiles'; + +export type DeterministicExecutionProfile = PublicExecutionProfile; + +export interface BundleDeterministicProgramOptions { + entryPath: string; + absWorkingDir?: string; + profile?: DeterministicExecutionProfile; + globalName?: string; + rejectIncompatible?: boolean; +} + +export interface CompatibilityDiagnostic { + filePath: string; + ruleId: string; + message: string; +} + +export interface CompatibilityScanResult { + ok: boolean; + diagnostics: CompatibilityDiagnostic[]; +} + +export interface BundleDeterministicProgramResult { + code: string; + contentHash: string; + meta: { + entryPath: string; + modulePaths: string[]; + profile: DeterministicExecutionProfile; + compatibility: CompatibilityScanResult; + }; +} + +export interface ModulePackOriginMeta { + packageName?: string; + packageVersion?: string; + integrity?: string; + originalPath?: string; +} + +export interface ModulePackModule { + specifier: string; + source: string; + sourceMap?: string; + originMeta?: ModulePackOriginMeta; +} + +export interface ModulePackV1 { + version: 1; + entrySpecifier: string; + entryExport: string; + modules: ModulePackModule[]; + graphHash: string; + builderVersion: string; + dependencyIntegrity: string; + diagnosticsMeta?: { + entryPath: string; + modulePaths: string[]; + }; +} + +export interface BuildDeterministicModulePackOptions { + entryPath: string; + absWorkingDir?: string; + profile?: DeterministicExecutionProfile; + rejectIncompatible?: boolean; + entryExport?: string; + emitScriptArtifact?: boolean; + emitProgramArtifact?: boolean; + builderVersion?: string; + dependencyIntegrity?: string; + abiId?: string; + abiVersion?: number; + abiManifestHash?: string; + engineBuildHash?: string; + gasVersion?: number; +} + +export interface ProgramArtifactV2 { + version: 2; + abiId: string; + abiVersion: number; + abiManifestHash: string; + engineBuildHash?: string; + gasVersion?: number; + executionProfile: DeterministicExecutionProfile; + sourceKind: 'module-pack'; + source: { + modulePack: ModulePackV1; + }; +} + +export interface CompatibilityReportV1 { + version: 1; + profile: DeterministicExecutionProfile; + ok: boolean; + moduleCount: number; + diagnosticCounts: Record; + diagnostics: CompatibilityDiagnostic[]; +} + +export interface BuildDeterministicModulePackResult { + modulePack: ModulePackV1; + compatibility: CompatibilityScanResult; + compatibilityReport: CompatibilityReportV1; + scriptArtifact?: BundleDeterministicProgramResult; + programArtifact?: ProgramArtifactV2; +} + +export class DeterministicBundlerError extends Error { + constructor( + message: string, + public readonly diagnostics: CompatibilityDiagnostic[], + ) { + super(message); + this.name = 'DeterministicBundlerError'; + } +} + +const DEFAULT_PROFILE: DeterministicExecutionProfile = 'baseline-v1'; +const DEFAULT_GLOBAL_NAME = '__blueDeterministicBundle'; +const DEFAULT_ENTRY_EXPORT = 'default'; +const DEFAULT_BUILDER_VERSION = 'deterministic-builder-v1'; +const BUILDER_OUT_DIR = '__blue_deterministic_builder_out__'; + +const NODE_BUILTINS = new Set( + builtinModules.flatMap((name) => + name.startsWith('node:') ? [name, name.slice('node:'.length)] : [name], + ), +); + +const FORBIDDEN_IDENTIFIER_RULES = new Map([ + ['WebAssembly', 'webassembly_disabled'], + ['Atomics', 'atomics_disabled'], + ['Proxy', 'proxy_disabled'], + ['Date', 'date_disabled'], + ['setTimeout', 'timers_disabled'], + ['setInterval', 'timers_disabled'], +]); + +const BINARY_IDENTIFIER_RULES = new Map([ + ['ArrayBuffer', 'arraybuffer_disabled'], + ['SharedArrayBuffer', 'sharedarraybuffer_disabled'], + ['DataView', 'dataview_disabled'], +]); + +const FORBIDDEN_TYPED_ARRAYS = new Set([ + 'Uint8Array', + 'Uint8ClampedArray', + 'Int8Array', + 'Uint16Array', + 'Int16Array', + 'Uint32Array', + 'Int32Array', + 'BigInt64Array', + 'BigUint64Array', + 'Float16Array', + 'Float32Array', + 'Float64Array', +]); + +export async function bundleDeterministicProgram( + options: BundleDeterministicProgramOptions, +): Promise { + const absWorkingDir = path.resolve(options.absWorkingDir ?? process.cwd()); + const absEntryPath = path.resolve(absWorkingDir, options.entryPath); + const profile = expectExecutionProfile(options.profile ?? DEFAULT_PROFILE); + const globalName = options.globalName ?? DEFAULT_GLOBAL_NAME; + const rejectIncompatible = options.rejectIncompatible ?? true; + + const result = await build({ + absWorkingDir, + entryPoints: [absEntryPath], + bundle: true, + write: false, + outfile: 'bundle.js', + format: 'iife', + platform: 'neutral', + mainFields: ['module', 'main'], + target: 'es2020', + globalName, + legalComments: 'none', + sourcemap: false, + metafile: true, + charset: 'utf8', + }); + + const jsOutput = result.outputFiles?.find((file) => + file.path.endsWith('.js'), + ); + if (!jsOutput) { + throw new Error('Bundler did not produce a JavaScript output'); + } + + const modulePaths = collectNormalizedModulePaths( + result.metafile?.inputs ?? {}, + absWorkingDir, + ); + const normalizedBundleText = normalizeLineEndings(jsOutput.text).trimEnd(); + const compatibility = scanCompatibility({ + sourceByPath: { + [normalizePath(jsOutput.path)]: normalizedBundleText, + }, + profile, + }); + + if (rejectIncompatible && !compatibility.ok) { + throw new DeterministicBundlerError( + formatCompatibilityMessage(compatibility.diagnostics), + compatibility.diagnostics, + ); + } + + const code = `${normalizedBundleText}\n;${globalName}.default;\n`; + + return { + code, + contentHash: sha256Hex(code), + meta: { + entryPath: normalizePath(absEntryPath), + modulePaths, + profile, + compatibility, + }, + }; +} + +export async function buildDeterministicModulePack( + options: BuildDeterministicModulePackOptions, +): Promise { + const absWorkingDir = path.resolve(options.absWorkingDir ?? process.cwd()); + const absEntryPath = path.resolve(absWorkingDir, options.entryPath); + const profile = expectExecutionProfile(options.profile ?? DEFAULT_PROFILE); + const rejectIncompatible = options.rejectIncompatible ?? true; + const entryExport = options.entryExport ?? DEFAULT_ENTRY_EXPORT; + const builderVersion = options.builderVersion ?? DEFAULT_BUILDER_VERSION; + const outputDir = path.join(absWorkingDir, BUILDER_OUT_DIR); + const dependencyIntegrity = + options.dependencyIntegrity !== undefined + ? expectHexStringOption( + options.dependencyIntegrity, + 'dependencyIntegrity', + ) + : computeDependencyIntegrity(absWorkingDir); + + const result = await build({ + absWorkingDir, + entryPoints: [absEntryPath], + bundle: true, + splitting: true, + write: false, + outdir: BUILDER_OUT_DIR, + format: 'esm', + platform: 'neutral', + mainFields: ['module', 'main'], + target: 'es2020', + legalComments: 'none', + sourcemap: 'external', + metafile: true, + charset: 'utf8', + }); + + const outputMetaByAbsolutePath = buildOutputMetadataLookup( + result.metafile?.outputs ?? {}, + absWorkingDir, + ); + const sourceMapBySpecifier = collectOutputMaps(result.outputFiles ?? [], { + absWorkingDir, + }); + const modules = collectModulePackModules(result.outputFiles ?? [], { + absWorkingDir, + outputDir, + outputMetaByAbsolutePath, + sourceMapBySpecifier, + dependencyIntegrity, + }); + const entrySpecifier = resolveEntrySpecifier( + result.metafile?.outputs ?? {}, + absWorkingDir, + absEntryPath, + ); + + const sourceByPath = Object.fromEntries( + modules.map((module) => [module.specifier, module.source]), + ); + const compatibility = scanCompatibility({ + sourceByPath, + profile, + }); + + if (rejectIncompatible && !compatibility.ok) { + throw new DeterministicBundlerError( + formatCompatibilityMessage(compatibility.diagnostics), + compatibility.diagnostics, + ); + } + + const modulePackWithoutHash = { + version: 1 as const, + entrySpecifier, + entryExport, + modules, + builderVersion, + dependencyIntegrity, + diagnosticsMeta: { + entryPath: normalizePath(absEntryPath), + modulePaths: modules.map((module) => module.specifier), + }, + }; + const graphHash = computeModulePackGraphHash(modulePackWithoutHash); + const modulePack: ModulePackV1 = { + ...modulePackWithoutHash, + graphHash, + }; + const compatibilityReport = buildCompatibilityReport({ + profile, + compatibility, + moduleCount: modules.length, + }); + + const scriptArtifact = options.emitScriptArtifact + ? await bundleDeterministicProgram({ + entryPath: options.entryPath, + absWorkingDir, + profile, + rejectIncompatible, + }) + : undefined; + const programArtifact = options.emitProgramArtifact + ? buildProgramArtifactV2({ + modulePack, + profile, + abiId: options.abiId ?? 'Host.v1', + abiVersion: options.abiVersion ?? 1, + abiManifestHash: expectHexStringOption( + options.abiManifestHash, + 'abiManifestHash', + ), + engineBuildHash: options.engineBuildHash + ? expectHexStringOption(options.engineBuildHash, 'engineBuildHash') + : undefined, + gasVersion: + options.gasVersion !== undefined + ? expectUint32Option(options.gasVersion, 'gasVersion') + : undefined, + }) + : undefined; + + return { + modulePack, + compatibility, + compatibilityReport, + ...(scriptArtifact ? { scriptArtifact } : {}), + ...(programArtifact ? { programArtifact } : {}), + }; +} + +export interface ScanCompatibilityOptions { + sourceByPath: Record; + profile?: DeterministicExecutionProfile; +} + +export function scanCompatibility( + options: ScanCompatibilityOptions, +): CompatibilityScanResult { + const profile = expectExecutionProfile(options.profile ?? DEFAULT_PROFILE); + const diagnostics = new Map(); + + const paths = Object.keys(options.sourceByPath).sort(); + for (const filePath of paths) { + const source = options.sourceByPath[filePath] ?? ''; + const parsed = safeParseModule(source); + if (!parsed.ok) { + addDiagnostic( + diagnostics, + filePath, + 'parse_error', + `Failed to parse source (${parsed.message})`, + ); + continue; + } + + walk(parsed.ast, (node) => { + scanNode(node, filePath, profile, diagnostics); + }); + } + + const sortedDiagnostics = [...diagnostics.values()].sort((a, b) => { + if (a.filePath !== b.filePath) { + return a.filePath.localeCompare(b.filePath); + } + if (a.ruleId !== b.ruleId) { + return a.ruleId.localeCompare(b.ruleId); + } + return a.message.localeCompare(b.message); + }); + + return { + ok: sortedDiagnostics.length === 0, + diagnostics: sortedDiagnostics, + }; +} + +type AstNode = Record & { type: string }; + +function scanNode( + node: AstNode, + filePath: string, + profile: DeterministicExecutionProfile, + diagnostics: Map, +): void { + if (node.type === 'ImportExpression') { + addDiagnostic( + diagnostics, + filePath, + 'dynamic_import_disabled', + 'dynamic import() is disabled in deterministic mode', + ); + return; + } + + if ( + node.type === 'ImportDeclaration' || + node.type === 'ExportAllDeclaration' || + node.type === 'ExportNamedDeclaration' + ) { + const source = asString( + (node as { source?: { value?: unknown } }).source?.value, + ); + if (source && isNodeBuiltinSpecifier(source)) { + addDiagnostic( + diagnostics, + filePath, + 'node_builtin_import', + `node builtin import is disabled: ${source}`, + ); + } + return; + } + + if (node.type === 'CallExpression') { + const callee = asNode((node as { callee?: unknown }).callee); + if (callee?.type === 'Identifier') { + const identifier = asString((callee as { name?: unknown }).name); + if (identifier === 'require') { + const firstArg = asNode( + (node as { arguments?: unknown[] }).arguments?.[0], + ); + if (firstArg?.type === 'Literal') { + const required = asString((firstArg as { value?: unknown }).value); + if (required && isNodeBuiltinSpecifier(required)) { + addDiagnostic( + diagnostics, + filePath, + 'node_builtin_require', + `node builtin require() is disabled: ${required}`, + ); + } + } + } + + if ( + identifier && + identifier === 'queueMicrotask' && + !executionProfileHasCapability(profile, 'queueMicrotask') + ) { + addDiagnostic( + diagnostics, + filePath, + 'microtasks_disabled', + `forbidden API used: ${identifier}`, + ); + } + } + + const targetIdentifier = getCallTargetRootIdentifier(callee); + if (targetIdentifier) { + if ( + FORBIDDEN_TYPED_ARRAYS.has(targetIdentifier) && + !executionProfileHasCapability(profile, 'typedArrays') + ) { + addDiagnostic( + diagnostics, + filePath, + 'typed_array_disabled', + `typed array API is disabled: ${targetIdentifier}`, + ); + } + + if (FORBIDDEN_IDENTIFIER_RULES.has(targetIdentifier)) { + addDiagnostic( + diagnostics, + filePath, + FORBIDDEN_IDENTIFIER_RULES.get(targetIdentifier) ?? + 'forbidden_identifier', + `forbidden API used: ${targetIdentifier}`, + ); + } + + if ( + BINARY_IDENTIFIER_RULES.has(targetIdentifier) && + !executionProfileHasCapability(profile, 'typedArrays') + ) { + addDiagnostic( + diagnostics, + filePath, + BINARY_IDENTIFIER_RULES.get(targetIdentifier) ?? + 'binary_api_disabled', + `forbidden API used: ${targetIdentifier}`, + ); + } + } + + if (isMathRandomCall(callee)) { + addDiagnostic( + diagnostics, + filePath, + 'math_random_disabled', + 'Math.random() is disabled in deterministic mode', + ); + } + + if ( + isConsoleCall(callee) && + !executionProfileHasCapability(profile, 'consoleShim') + ) { + addDiagnostic( + diagnostics, + filePath, + 'console_disabled', + 'console APIs are disabled in deterministic mode', + ); + } + + if ( + isRegExpCall(callee) && + !executionProfileHasCapability(profile, 'regexp') + ) { + addDiagnostic( + diagnostics, + filePath, + 'regexp_disabled', + 'RegExp is disabled in baseline deterministic profile', + ); + } + + return; + } + + if (node.type === 'NewExpression') { + const callee = asNode((node as { callee?: unknown }).callee); + if (callee?.type === 'Identifier') { + const identifier = asString((callee as { name?: unknown }).name); + if (!identifier) { + return; + } + + if ( + FORBIDDEN_TYPED_ARRAYS.has(identifier) && + !executionProfileHasCapability(profile, 'typedArrays') + ) { + addDiagnostic( + diagnostics, + filePath, + 'typed_array_disabled', + `typed array constructor is disabled: ${identifier}`, + ); + return; + } + + if (FORBIDDEN_IDENTIFIER_RULES.has(identifier)) { + addDiagnostic( + diagnostics, + filePath, + FORBIDDEN_IDENTIFIER_RULES.get(identifier) ?? 'forbidden_identifier', + `forbidden API used: ${identifier}`, + ); + return; + } + + if ( + BINARY_IDENTIFIER_RULES.has(identifier) && + !executionProfileHasCapability(profile, 'typedArrays') + ) { + addDiagnostic( + diagnostics, + filePath, + BINARY_IDENTIFIER_RULES.get(identifier) ?? 'binary_api_disabled', + `forbidden API used: ${identifier}`, + ); + return; + } + + if ( + identifier === 'RegExp' && + !executionProfileHasCapability(profile, 'regexp') + ) { + addDiagnostic( + diagnostics, + filePath, + 'regexp_disabled', + 'RegExp is disabled in baseline deterministic profile', + ); + } + } + return; + } + + if ( + isRegExpLiteral(node) && + !executionProfileHasCapability(profile, 'regexp') + ) { + addDiagnostic( + diagnostics, + filePath, + 'regexp_literal_disabled', + 'RegExp literals are disabled in baseline deterministic profile', + ); + } +} + +function safeParseModule( + source: string, +): { ok: true; ast: AstNode } | { ok: false; message: string } { + try { + const ast = parse(source, { + ecmaVersion: 'latest', + sourceType: 'module', + allowHashBang: true, + }) as unknown as AstNode; + return { ok: true, ast }; + } catch (error) { + return { ok: false, message: stringifyError(error) }; + } +} + +function walk(node: AstNode, visit: (node: AstNode) => void): void { + visit(node); + const keys = Object.keys(node).sort(); + for (const key of keys) { + const value = (node as Record)[key]; + if (!value) { + continue; + } + + if (Array.isArray(value)) { + for (const item of value) { + if (isNode(item)) { + walk(item, visit); + } + } + continue; + } + + if (isNode(value)) { + walk(value, visit); + } + } +} + +function collectNormalizedModulePaths( + metafileInputs: Record, + absWorkingDir: string, +): string[] { + const paths = Object.keys(metafileInputs).map((input) => { + const absolute = path.isAbsolute(input) + ? input + : path.resolve(absWorkingDir, input); + return normalizePath(absolute); + }); + return [...new Set(paths)].sort(); +} + +function buildOutputMetadataLookup( + outputs: Record }>, + absWorkingDir: string, +): Map }> { + const lookup = new Map }>(); + for (const [outputPath, meta] of Object.entries(outputs)) { + const absolutePath = path.isAbsolute(outputPath) + ? outputPath + : path.resolve(absWorkingDir, outputPath); + lookup.set(normalizePath(absolutePath), meta); + } + return lookup; +} + +function collectOutputMaps( + outputFiles: Array<{ path: string; text: string }>, + options: { absWorkingDir: string }, +): Map { + const bySpecifier = new Map(); + const maps = outputFiles.filter((file) => file.path.endsWith('.map')); + for (const mapFile of maps) { + const mapPath = mapFile.path.slice(0, -'.map'.length); + const specifier = toModuleSpecifier(mapPath, { + absWorkingDir: options.absWorkingDir, + outputDir: path.join(options.absWorkingDir, BUILDER_OUT_DIR), + }); + bySpecifier.set( + specifier, + sanitizeSourceMap(mapFile.text, { + absWorkingDir: options.absWorkingDir, + }), + ); + } + return bySpecifier; +} + +function collectModulePackModules( + outputFiles: Array<{ path: string; text: string }>, + options: { + absWorkingDir: string; + outputDir: string; + outputMetaByAbsolutePath: Map }>; + sourceMapBySpecifier: Map; + dependencyIntegrity: string; + }, +): ModulePackModule[] { + const jsFiles = outputFiles.filter((file) => /\.m?js$/.test(file.path)); + const modules = jsFiles.map((file) => { + const specifier = toModuleSpecifier(file.path, { + absWorkingDir: options.absWorkingDir, + outputDir: options.outputDir, + }); + const normalizedSource = `${normalizeLineEndings(file.text).trimEnd()}\n`; + const meta = options.outputMetaByAbsolutePath.get(normalizePath(file.path)); + + const module: ModulePackModule = { + specifier, + source: normalizedSource, + }; + + const sourceMap = options.sourceMapBySpecifier.get(specifier); + if (sourceMap) { + module.sourceMap = sourceMap; + } + + const originMeta = resolveOriginMeta( + meta?.inputs ? Object.keys(meta.inputs) : [], + { + absWorkingDir: options.absWorkingDir, + dependencyIntegrity: options.dependencyIntegrity, + }, + ); + if (originMeta) { + module.originMeta = originMeta; + } + + return module; + }); + + return modules.sort((a, b) => compareUtf8ByteOrder(a.specifier, b.specifier)); +} + +function resolveEntrySpecifier( + outputs: Record, + absWorkingDir: string, + absEntryPath: string, +): string { + const normalizedEntry = normalizePath(absEntryPath); + const entryOutputPath = Object.entries(outputs) + .map(([outputPath, meta]) => { + const absoluteOutput = path.isAbsolute(outputPath) + ? outputPath + : path.resolve(absWorkingDir, outputPath); + const absoluteEntry = meta.entryPoint + ? path.resolve(absWorkingDir, meta.entryPoint) + : null; + return { + absoluteOutput, + absoluteEntry: absoluteEntry ? normalizePath(absoluteEntry) : null, + }; + }) + .find( + (candidate) => candidate.absoluteEntry === normalizedEntry, + )?.absoluteOutput; + + if (!entryOutputPath) { + throw new Error( + `Unable to resolve entry output for ${normalizePath(absEntryPath)}`, + ); + } + + return toModuleSpecifier(entryOutputPath, { + absWorkingDir, + outputDir: path.join(absWorkingDir, BUILDER_OUT_DIR), + }); +} + +function toModuleSpecifier( + outputPath: string, + options: { absWorkingDir: string; outputDir: string }, +): string { + const absoluteOutputPath = path.isAbsolute(outputPath) + ? outputPath + : path.resolve(options.absWorkingDir, outputPath); + const relative = normalizePath( + path.relative(options.outputDir, absoluteOutputPath), + ); + return relative.startsWith('.') ? relative : `./${relative}`; +} + +function sanitizeSourceMap( + sourceMap: string, + options: { absWorkingDir: string }, +): string { + const parsed = JSON.parse(sourceMap) as Record; + if (Array.isArray(parsed.sources)) { + parsed.sources = parsed.sources.map((source) => { + if (typeof source !== 'string') { + return source; + } + const normalized = normalizePath(source); + if (path.isAbsolute(source)) { + return normalizePath(path.relative(options.absWorkingDir, source)); + } + return normalized; + }); + } + if ( + typeof parsed.sourceRoot === 'string' && + path.isAbsolute(parsed.sourceRoot) + ) { + parsed.sourceRoot = normalizePath( + path.relative(options.absWorkingDir, parsed.sourceRoot), + ); + } + if (typeof parsed.file === 'string' && path.isAbsolute(parsed.file)) { + parsed.file = normalizePath( + path.relative(options.absWorkingDir, parsed.file), + ); + } + return stableStringify(parsed); +} + +function resolveOriginMeta( + inputPaths: string[], + options: { absWorkingDir: string; dependencyIntegrity: string }, +): ModulePackOriginMeta | undefined { + if (inputPaths.length === 0) { + return undefined; + } + const normalizedInputs = inputPaths + .map((inputPath) => + path.isAbsolute(inputPath) + ? inputPath + : path.resolve(options.absWorkingDir, inputPath), + ) + .map((inputPath) => normalizePath(inputPath)) + .sort(); + const selectedInputPath = + normalizedInputs.find((inputPath) => + inputPath.includes('/node_modules/'), + ) ?? normalizedInputs[0]; + + const originMeta: ModulePackOriginMeta = { + originalPath: normalizePath( + path.relative(options.absWorkingDir, selectedInputPath), + ), + }; + + const packageInfo = resolvePackageInfoFromInputPath(selectedInputPath); + if (packageInfo) { + originMeta.packageName = packageInfo.packageName; + originMeta.packageVersion = packageInfo.packageVersion; + originMeta.integrity = options.dependencyIntegrity; + } + + return originMeta; +} + +function resolvePackageInfoFromInputPath( + inputPath: string, +): { packageName: string; packageVersion?: string } | null { + const marker = '/node_modules/'; + const markerIndex = inputPath.lastIndexOf(marker); + if (markerIndex < 0) { + return null; + } + const fromNodeModules = inputPath.slice(markerIndex + marker.length); + const segments = fromNodeModules.split('/').filter(Boolean); + if (segments.length === 0) { + return null; + } + + let packageName: string; + if (segments[0].startsWith('@')) { + if (segments.length < 2) { + return null; + } + packageName = `${segments[0]}/${segments[1]}`; + } else { + packageName = segments[0]; + } + + const packageRoot = inputPath.slice( + 0, + markerIndex + marker.length + packageName.length, + ); + const packageJsonPath = path.join(packageRoot, 'package.json'); + if (!fs.existsSync(packageJsonPath)) { + return { packageName }; + } + + try { + const packageJson = JSON.parse( + fs.readFileSync(packageJsonPath, 'utf8'), + ) as { + version?: string; + }; + return { + packageName, + ...(typeof packageJson.version === 'string' + ? { packageVersion: packageJson.version } + : {}), + }; + } catch { + return { packageName }; + } +} + +function computeDependencyIntegrity(absWorkingDir: string): string { + const lockfilePath = findNearestLockfile(absWorkingDir); + if (!lockfilePath) { + return sha256Hex('no-lockfile'); + } + const contents = fs.readFileSync(lockfilePath, 'utf8'); + return sha256Hex(normalizeLineEndings(contents)); +} + +function findNearestLockfile(startDir: string): string | null { + const lockfiles = ['pnpm-lock.yaml', 'package-lock.json', 'yarn.lock']; + let cursor = path.resolve(startDir); + + while (true) { + for (const lockfile of lockfiles) { + const candidate = path.join(cursor, lockfile); + if (fs.existsSync(candidate)) { + return candidate; + } + } + const parent = path.dirname(cursor); + if (parent === cursor) { + return null; + } + cursor = parent; + } +} + +function computeModulePackGraphHash(pack: { + version: 1; + entrySpecifier: string; + entryExport: string; + modules: ModulePackModule[]; + builderVersion: string; + dependencyIntegrity: string; +}): string { + const canonical = { + version: pack.version, + entrySpecifier: pack.entrySpecifier, + entryExport: pack.entryExport, + modules: pack.modules.map((module) => ({ + specifier: module.specifier, + source: module.source, + ...(module.sourceMap ? { sourceMap: module.sourceMap } : {}), + })), + builderVersion: pack.builderVersion, + dependencyIntegrity: pack.dependencyIntegrity, + }; + return sha256Hex(stableStringify(canonical)); +} + +function buildCompatibilityReport(options: { + profile: DeterministicExecutionProfile; + compatibility: CompatibilityScanResult; + moduleCount: number; +}): CompatibilityReportV1 { + const diagnosticCounts = options.compatibility.diagnostics.reduce< + Record + >((accumulator, diagnostic) => { + accumulator[diagnostic.ruleId] = (accumulator[diagnostic.ruleId] ?? 0) + 1; + return accumulator; + }, {}); + + return { + version: 1, + profile: options.profile, + ok: options.compatibility.ok, + moduleCount: options.moduleCount, + diagnosticCounts, + diagnostics: options.compatibility.diagnostics, + }; +} + +function buildProgramArtifactV2(options: { + modulePack: ModulePackV1; + profile: DeterministicExecutionProfile; + abiId: string; + abiVersion: number; + abiManifestHash: string; + engineBuildHash?: string; + gasVersion?: number; +}): ProgramArtifactV2 { + return { + version: 2, + abiId: options.abiId, + abiVersion: options.abiVersion, + abiManifestHash: options.abiManifestHash, + ...(options.engineBuildHash + ? { + engineBuildHash: options.engineBuildHash, + } + : {}), + ...(options.gasVersion !== undefined + ? { + gasVersion: options.gasVersion, + } + : {}), + executionProfile: options.profile, + sourceKind: 'module-pack', + source: { + modulePack: options.modulePack, + }, + }; +} + +function expectHexStringOption( + value: string | undefined, + fieldName: string, +): string { + if (!value) { + throw new Error(`buildDeterministicModulePack requires ${fieldName}`); + } + if (!/^[0-9a-f]{64}$/.test(value)) { + throw new Error(`${fieldName} must be a lowercase 64-char hex string`); + } + return value; +} + +function expectExecutionProfile( + value: unknown, +): DeterministicExecutionProfile { + if (!isKnownExecutionProfile(value)) { + throw new Error( + `profile must be one of ${listExecutionProfiles().join(', ')}`, + ); + } + return value; +} + +function expectUint32Option(value: number, fieldName: string): number { + if (!Number.isInteger(value) || value < 0 || value > 0xffffffff) { + throw new Error(`${fieldName} must be a uint32 integer`); + } + return value; +} + +function stableStringify(value: unknown): string { + if (value === null || typeof value !== 'object') { + return JSON.stringify(value); + } + if (Array.isArray(value)) { + return `[${value.map((item) => stableStringify(item)).join(',')}]`; + } + + const entries = Object.entries(value as Record) + .filter(([, item]) => item !== undefined) + .sort(([left], [right]) => compareUtf8ByteOrder(left, right)) + .map(([key, item]) => `${JSON.stringify(key)}:${stableStringify(item)}`); + return `{${entries.join(',')}}`; +} + +const UTF8_ENCODER = new TextEncoder(); + +function compareUtf8ByteOrder(left: string, right: string): number { + if (left === right) { + return 0; + } + + const leftBytes = UTF8_ENCODER.encode(left); + const rightBytes = UTF8_ENCODER.encode(right); + const limit = Math.min(leftBytes.length, rightBytes.length); + + for (let index = 0; index < limit; index += 1) { + const delta = leftBytes[index] - rightBytes[index]; + if (delta !== 0) { + return delta; + } + } + + return leftBytes.length - rightBytes.length; +} + +function addDiagnostic( + diagnostics: Map, + filePath: string, + ruleId: string, + message: string, +): void { + const normalizedPath = normalizePath(filePath); + const key = `${normalizedPath}::${ruleId}::${message}`; + if (diagnostics.has(key)) { + return; + } + diagnostics.set(key, { + filePath: normalizedPath, + ruleId, + message, + }); +} + +function isMathRandomCall(node: AstNode | null): boolean { + if (!node || node.type !== 'MemberExpression') { + return false; + } + const object = asNode((node as { object?: unknown }).object); + const property = asNode((node as { property?: unknown }).property); + if (!object || !property) { + return false; + } + return ( + object.type === 'Identifier' && + asString((object as { name?: unknown }).name) === 'Math' && + property.type === 'Identifier' && + asString((property as { name?: unknown }).name) === 'random' + ); +} + +function getCallTargetRootIdentifier(node: AstNode | null): string | null { + if (!node) { + return null; + } + + if (node.type === 'Identifier') { + return asString((node as { name?: unknown }).name); + } + + if (node.type === 'MemberExpression') { + return getCallTargetRootIdentifier( + asNode((node as { object?: unknown }).object), + ); + } + + if (node.type === 'ChainExpression') { + return getCallTargetRootIdentifier( + asNode((node as { expression?: unknown }).expression), + ); + } + + return null; +} + +function isConsoleCall(node: AstNode | null): boolean { + if (!node || node.type !== 'MemberExpression') { + return false; + } + const object = asNode((node as { object?: unknown }).object); + return ( + object?.type === 'Identifier' && + asString((object as { name?: unknown }).name) === 'console' + ); +} + +function isRegExpCall(node: AstNode | null): boolean { + return ( + !!node && + node.type === 'Identifier' && + asString((node as { name?: unknown }).name) === 'RegExp' + ); +} + +function isRegExpLiteral(node: AstNode): boolean { + if (node.type !== 'Literal') { + return false; + } + return Boolean((node as { regex?: unknown }).regex); +} + +function isNode(value: unknown): value is AstNode { + return ( + value !== null && + typeof value === 'object' && + typeof (value as { type?: unknown }).type === 'string' + ); +} + +function asNode(value: unknown): AstNode | null { + return isNode(value) ? value : null; +} + +function asString(value: unknown): string | null { + return typeof value === 'string' ? value : null; +} + +function isNodeBuiltinSpecifier(specifier: string): boolean { + if (specifier.startsWith('node:')) { + return true; + } + return NODE_BUILTINS.has(specifier); +} + +function normalizePath(input: string): string { + return input.split(path.sep).join('/'); +} + +function normalizeLineEndings(input: string): string { + return input.replace(/\r\n/g, '\n').replace(/\r/g, '\n'); +} + +function sha256Hex(input: string): string { + return createHash('sha256').update(input, 'utf8').digest('hex'); +} + +function stringifyError(error: unknown): string { + if (error instanceof Error) { + return error.message; + } + return String(error); +} + +function formatCompatibilityMessage( + diagnostics: CompatibilityDiagnostic[], +): string { + const lines = diagnostics.map( + (diagnostic) => + `- [${diagnostic.ruleId}] ${diagnostic.filePath}: ${diagnostic.message}`, + ); + return `Compatibility scan failed:\n${lines.join('\n')}`; +} diff --git a/libs/deterministic-bundler/tsconfig.json b/libs/deterministic-bundler/tsconfig.json new file mode 100644 index 0000000..62ebbd9 --- /dev/null +++ b/libs/deterministic-bundler/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../tsconfig.base.json", + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/libs/deterministic-bundler/tsconfig.lib.json b/libs/deterministic-bundler/tsconfig.lib.json new file mode 100644 index 0000000..c24c7a8 --- /dev/null +++ b/libs/deterministic-bundler/tsconfig.lib.json @@ -0,0 +1,32 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "baseUrl": ".", + "rootDir": "src", + "outDir": "dist", + "tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo", + "emitDeclarationOnly": false, + "forceConsistentCasingInFileNames": true, + "types": ["node"] + }, + "include": ["src/**/*.ts"], + "references": [ + { + "path": "../execution-profiles/tsconfig.lib.json" + } + ], + "exclude": [ + "vite.config.ts", + "vite.config.mts", + "vitest.config.ts", + "vitest.config.mts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx" + ] +} diff --git a/libs/deterministic-bundler/tsconfig.spec.json b/libs/deterministic-bundler/tsconfig.spec.json new file mode 100644 index 0000000..f68d9d3 --- /dev/null +++ b/libs/deterministic-bundler/tsconfig.spec.json @@ -0,0 +1,34 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "./out-tsc/vitest", + "types": [ + "vitest/globals", + "vitest/importMeta", + "vite/client", + "node", + "vitest" + ], + "forceConsistentCasingInFileNames": true + }, + "include": [ + "vite.config.ts", + "vite.config.mts", + "vitest.config.ts", + "vitest.config.mts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx", + "src/**/*.d.ts" + ], + "references": [ + { + "path": "./tsconfig.lib.json" + } + ] +} diff --git a/libs/deterministic-bundler/vite.config.ts b/libs/deterministic-bundler/vite.config.ts new file mode 100644 index 0000000..5e614a8 --- /dev/null +++ b/libs/deterministic-bundler/vite.config.ts @@ -0,0 +1,29 @@ +/// +import { defineConfig } from 'vite'; + +export default defineConfig(() => ({ + root: import.meta.dirname, + cacheDir: '../../node_modules/.vite/libs/deterministic-bundler', + plugins: [], + test: { + name: 'deterministic-bundler', + watch: false, + globals: true, + environment: 'node', + include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], + reporters: ['default'], + coverage: { + reportsDirectory: './test-output/vitest/coverage', + provider: 'v8' as const, + all: true, + include: ['src/**/*.{ts,mts}'], + exclude: ['src/**/*.{test,spec}.{ts,mts}'], + thresholds: { + lines: 40, + functions: 40, + branches: 40, + statements: 40, + }, + }, + }, +})); diff --git a/libs/dv/src/lib/dv.spec.ts b/libs/dv/src/lib/dv.spec.ts index 5a4a894..daa4442 100644 --- a/libs/dv/src/lib/dv.spec.ts +++ b/libs/dv/src/lib/dv.spec.ts @@ -7,8 +7,13 @@ import { DvError, DvErrorCode, decodeDv, + decodeDv2, encodeDv, + encodeDv2, isDv, + isDv2, + validateDv, + validateDv2, } from './dv.js'; const hex = (bytes: Uint8Array): string => @@ -61,10 +66,52 @@ describe('encodeDv / decodeDv', () => { () => encodeDv('abcd', { limits: { maxEncodedBytes: 3 } }), 'ENCODED_TOO_LARGE', ); + expectCode( + () => encodeDv([1, 2], { limits: { maxArrayLength: 1 } }), + 'ARRAY_TOO_LONG', + ); + expectCode( + () => encodeDv({ a: 1, b: 2 }, { limits: { maxMapLength: 1 } }), + 'MAP_TOO_LONG', + ); + expectCode( + () => + decodeDv(Uint8Array.from([0x82, 0x01, 0x02]), { + limits: { maxArrayLength: 1 }, + }), + 'ARRAY_TOO_LONG', + ); + expectCode( + () => + decodeDv(Uint8Array.from([0xa2, 0x61, 0x61, 0x01, 0x61, 0x62, 0x02]), { + limits: { maxMapLength: 1 }, + }), + 'MAP_TOO_LONG', + ); + expectCode( + () => + decodeDv(Uint8Array.from([0x64, 0x61, 0x62, 0x63, 0x64]), { + limits: { maxStringBytes: 3 }, + }), + 'STRING_TOO_LONG', + ); + expectCode( + () => + decodeDv(Uint8Array.from([0x81, 0x80]), { limits: { maxDepth: 1 } }), + 'DEPTH_EXCEEDED', + ); + expectCode( + () => + decodeDv(Uint8Array.from([0xa1, 0x61, 0x61, 0xa0]), { + limits: { maxDepth: 1 }, + }), + 'DEPTH_EXCEEDED', + ); }); it('rejects invalid UTF-8 and malformed strings', () => { expectCode(() => encodeDv('a\uD800'), 'INVALID_STRING'); + expectCode(() => encodeDv('a\uDC00'), 'INVALID_STRING'); expectCode(() => decodeDv(Uint8Array.from([0x61])), 'TRUNCATED'); const invalidBytes = Uint8Array.from([0x62, 0xc3, 0x28]); expect(() => decodeDv(invalidBytes)).toThrowError( @@ -130,6 +177,185 @@ describe('encodeDv / decodeDv', () => { decodeDv(Uint8Array.from([0xa2, 0x61, 0x61, 0x01, 0x61, 0x61, 0x02])), 'DUPLICATE_KEY', ); + expectCode(() => decodeDv(Uint8Array.from([0x9f])), 'NON_CANONICAL_LENGTH'); + expectCode(() => decodeDv(Uint8Array.from([0xe0])), 'UNSUPPORTED_CBOR'); + expectCode(() => decodeDv(Uint8Array.from([0xf0])), 'UNSUPPORTED_CBOR'); + expectCode( + () => decodeDv(Uint8Array.from([0xf8, 0x00])), + 'NON_CANONICAL_FLOAT', + ); + expectCode( + () => + decodeDv( + Uint8Array.from([ + 0xfb, 0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ]), + ), + 'NAN_OR_INF', + ); + expectCode(() => decodeDv(Uint8Array.from([0xfb, 0x3f])), 'TRUNCATED'); + expectCode(() => decodeDv(Uint8Array.from([0xff])), 'NON_CANONICAL_LENGTH'); + expectCode(() => decodeDv(Uint8Array.from([0xc0])), 'UNSUPPORTED_CBOR'); + expectCode( + () => decodeDv(Uint8Array.from([0x19, 0x00, 0xff])), + 'NON_CANONICAL_LENGTH', + ); + expectCode(() => decodeDv(Uint8Array.from([0x19, 0x01])), 'TRUNCATED'); + expectCode( + () => decodeDv(Uint8Array.from([0x1a, 0x00, 0x00, 0xff, 0xff])), + 'NON_CANONICAL_LENGTH', + ); + expectCode( + () => decodeDv(Uint8Array.from([0x1a, 0x00, 0x01])), + 'TRUNCATED', + ); + expectCode( + () => + decodeDv( + Uint8Array.from([ + 0x1b, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + ]), + ), + 'NON_CANONICAL_LENGTH', + ); + expectCode(() => decodeDv(Uint8Array.from([0x1c])), 'UNSUPPORTED_CBOR'); + expectCode( + () => + decodeDv( + Uint8Array.from([ + 0x7b, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ]), + ), + 'NON_CANONICAL_LENGTH', + ); + expectCode( + () => decodeDv(Uint8Array.from([0x1b, 0x00, 0x00, 0x00, 0x00, 0x00])), + 'TRUNCATED', + ); + expectCode( + () => + decodeDv( + Uint8Array.from([ + 0x3b, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ]), + ), + 'INTEGER_OUT_OF_RANGE', + ); + expectCode( + () => + decodeDv( + Uint8Array.from([ + 0x1b, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ]), + ), + 'INTEGER_OUT_OF_RANGE', + ); + expectCode( + () => decodeDv(Uint8Array.from([0xa1, 0x01, 0x02])), + 'UNSUPPORTED_CBOR', + ); + }); + + it('supports all canonical CBOR integer and length widths', () => { + expect(hex(encodeDv(23))).toBe('17'); + expect(hex(encodeDv(24))).toBe('1818'); + expect(hex(encodeDv(256))).toBe('190100'); + expect(hex(encodeDv(65_536))).toBe('1a00010000'); + expect(hex(encodeDv(4_294_967_296))).toBe('1b0000000100000000'); + expect(hex(encodeDv(-24))).toBe('37'); + expect(hex(encodeDv(-25))).toBe('3818'); + + expect(decodeDv(Uint8Array.from([0x18, 0x18]))).toBe(24); + expect(decodeDv(Uint8Array.from([0x19, 0x01, 0x00]))).toBe(256); + expect(decodeDv(Uint8Array.from([0x1a, 0x00, 0x01, 0x00, 0x00]))).toBe( + 65_536, + ); + expect( + decodeDv( + Uint8Array.from([0x1b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00]), + ), + ).toBe(4_294_967_296); + expect(decodeDv(Uint8Array.from([0x38, 0x18]))).toBe(-25); + }); + + it('accepts ArrayBuffer and offset ArrayBufferView inputs', () => { + const encoded = encodeDv({ ok: true }); + const buffer = encoded.buffer.slice(0) as ArrayBuffer; + expect(decodeDv(buffer)).toEqual({ ok: true }); + + const padded = Uint8Array.from([0xff, ...encoded, 0xff]); + const view = new DataView(padded.buffer, 1, encoded.length); + expect(decodeDv(view)).toEqual({ ok: true }); + }); + + it('rejects encoded payloads above maxEncodedBytes before parsing', () => { + expectCode( + () => + decodeDv(Uint8Array.from([0x01, 0x02]), { + limits: { maxEncodedBytes: 1 }, + }), + 'ENCODED_TOO_LARGE', + ); + expectCode( + () => + decodeDv2(Uint8Array.from([0x41, 0x00]), { + limits: { maxEncodedBytes: 1 }, + }), + 'ENCODED_TOO_LARGE', + ); + }); + + it('validates and narrows DV and DV2 values', () => { + const dvValue: unknown = { nested: [null, true, 1.25, 'ok'] }; + expect(() => validateDv(dvValue)).not.toThrow(); + expect(isDv(dvValue)).toBe(true); + expect(isDv({ payload: Uint8Array.from([1]) })).toBe(false); + + const dv2Value: unknown = { payload: Uint8Array.from([1, 2, 3]) }; + expect(() => validateDv2(dv2Value)).not.toThrow(); + expect(isDv2(dv2Value)).toBe(true); + expect(isDv2({ bad: () => undefined })).toBe(false); + }); + + it('supports byte-string values in DV2 mode', () => { + const bytes = Uint8Array.from([0xde, 0xad, 0xbe, 0xef]); + expect(hex(encodeDv2(bytes))).toBe('44deadbeef'); + + const decoded = decodeDv2(Uint8Array.from([0x44, 0xde, 0xad, 0xbe, 0xef])); + expect(decoded).toBeInstanceOf(Uint8Array); + expect(Array.from(decoded as Uint8Array)).toEqual([0xde, 0xad, 0xbe, 0xef]); + + const nested = decodeDv2( + Uint8Array.from([ + 0xa1, 0x65, 0x62, 0x79, 0x74, 0x65, 0x73, 0x44, 0x00, 0x01, 0x02, 0x03, + ]), + ) as { bytes: Uint8Array }; + expect(Array.from(nested.bytes)).toEqual([0, 1, 2, 3]); + + expect(isDv2({ payload: bytes })).toBe(true); + expect(isDv({ payload: bytes })).toBe(false); + }); + + it('keeps DV1 byte strings unsupported and enforces DV2 byte limits', () => { + expectCode(() => encodeDv(Uint8Array.from([1, 2, 3])), 'UNSUPPORTED_TYPE'); + expectCode( + () => decodeDv(Uint8Array.from([0x41, 0x01])), + 'UNSUPPORTED_CBOR', + ); + expectCode( + () => + encodeDv2(Uint8Array.from([1, 2, 3]), { + limits: { maxByteStringBytes: 2 }, + }), + 'BYTE_STRING_TOO_LONG', + ); + expectCode( + () => + decodeDv2(Uint8Array.from([0x43, 0x01, 0x02, 0x03]), { + limits: { maxByteStringBytes: 2 }, + }), + 'BYTE_STRING_TOO_LONG', + ); }); it('roundtrips and canonicalizes under property-based generation', () => { @@ -178,4 +404,24 @@ describe('encodeDv / decodeDv', () => { { numRuns: 150 }, ); }); + + it('roundtrips DV2 values containing byte strings', () => { + const value = { + kind: 'bytes', + payload: Uint8Array.from([1, 2, 3, 4]), + nested: [Uint8Array.from([9, 8]), { ok: true }], + }; + const encoded = encodeDv2(value); + const decoded = decodeDv2(encoded) as { + kind: string; + payload: Uint8Array; + nested: [Uint8Array, { ok: boolean }]; + }; + + expect(decoded.kind).toBe('bytes'); + expect(Array.from(decoded.payload)).toEqual([1, 2, 3, 4]); + expect(Array.from(decoded.nested[0])).toEqual([9, 8]); + expect(decoded.nested[1]).toEqual({ ok: true }); + expect(hex(encodeDv2(decoded))).toBe(hex(encoded)); + }); }); diff --git a/libs/dv/src/lib/dv.ts b/libs/dv/src/lib/dv.ts index 2bddce2..826b6eb 100644 --- a/libs/dv/src/lib/dv.ts +++ b/libs/dv/src/lib/dv.ts @@ -6,6 +6,7 @@ const MIN_SAFE_INT = Number.MIN_SAFE_INTEGER; const CBOR_MAJOR_UINT = 0; const CBOR_MAJOR_NINT = 1; +const CBOR_MAJOR_BYTES = 2; const CBOR_MAJOR_TEXT = 3; const CBOR_MAJOR_ARRAY = 4; const CBOR_MAJOR_MAP = 5; @@ -15,11 +16,17 @@ export type DV = DVPrimitive | DVArray | DVObject; export type DVPrimitive = null | boolean | number | string; export type DVArray = DV[]; export type DVObject = { [key: string]: DV }; +export type DV2 = DV2Primitive | DV2Bytes | DV2Array | DV2Object; +export type DV2Primitive = null | boolean | number | string; +export type DV2Bytes = Uint8Array; +export type DV2Array = DV2[]; +export type DV2Object = { [key: string]: DV2 }; export interface DvLimits { maxDepth: number; maxEncodedBytes: number; maxStringBytes: number; + maxByteStringBytes: number; maxArrayLength: number; maxMapLength: number; } @@ -28,6 +35,7 @@ export const DV_LIMIT_DEFAULTS: Readonly = { maxDepth: 64, maxEncodedBytes: 5_242_880, maxStringBytes: 262_144, + maxByteStringBytes: 262_144, maxArrayLength: 65_535, maxMapLength: 65_535, }; @@ -47,6 +55,7 @@ export type DvErrorCode = | 'INTEGER_OUT_OF_RANGE' | 'INVALID_STRING' | 'STRING_TOO_LONG' + | 'BYTE_STRING_TOO_LONG' | 'ARRAY_TOO_LONG' | 'MAP_TOO_LONG' | 'DEPTH_EXCEEDED' @@ -77,7 +86,17 @@ export function encodeDv( ): Uint8Array { const limits = normalizeLimits(options?.limits); const builder = new ByteBuilder(limits.maxEncodedBytes); - encodeValue(value, builder, limits, 0); + encodeValue(value, builder, limits, 0, false); + return builder.toUint8Array(); +} + +export function encodeDv2( + value: unknown, + options?: DvEncodeOptions, +): Uint8Array { + const limits = normalizeLimits(options?.limits); + const builder = new ByteBuilder(limits.maxEncodedBytes); + encodeValue(value, builder, limits, 0, true); return builder.toUint8Array(); } @@ -101,7 +120,36 @@ export function decodeDv( } const reader = new CborReader(bytes); - const value = readValue(reader, limits, 0); + const value = readValue(reader, limits, 0, false) as DV; + + if (!reader.isEOF()) { + throw dvError('TRAILING_BYTES', 'unexpected trailing bytes after DV value'); + } + + return value; +} + +export function decodeDv2( + input: ArrayBufferView | ArrayBuffer | Uint8Array, + options?: DvDecodeOptions, +): DV2 { + const limits = normalizeLimits(options?.limits); + const bytes = + input instanceof Uint8Array + ? input + : input instanceof ArrayBuffer + ? new Uint8Array(input) + : new Uint8Array(input.buffer, input.byteOffset, input.byteLength); + + if (bytes.length > limits.maxEncodedBytes) { + throw dvError( + 'ENCODED_TOO_LARGE', + `encoded DV exceeds maxEncodedBytes (${bytes.length} > ${limits.maxEncodedBytes})`, + ); + } + + const reader = new CborReader(bytes); + const value = readValue(reader, limits, 0, true); if (!reader.isEOF()) { throw dvError('TRAILING_BYTES', 'unexpected trailing bytes after DV value'); @@ -127,12 +175,33 @@ export function isDv(value: unknown, options?: DvValidateOptions): value is DV { } } +export function validateDv2( + value: unknown, + options?: DvValidateOptions, +): asserts value is DV2 { + encodeDv2(value, options); +} + +export function isDv2( + value: unknown, + options?: DvValidateOptions, +): value is DV2 { + try { + validateDv2(value, options); + return true; + } catch { + return false; + } +} + function normalizeLimits(limits?: PartialLimits): DvLimits { return { maxDepth: limits?.maxDepth ?? DV_LIMIT_DEFAULTS.maxDepth, maxEncodedBytes: limits?.maxEncodedBytes ?? DV_LIMIT_DEFAULTS.maxEncodedBytes, maxStringBytes: limits?.maxStringBytes ?? DV_LIMIT_DEFAULTS.maxStringBytes, + maxByteStringBytes: + limits?.maxByteStringBytes ?? DV_LIMIT_DEFAULTS.maxByteStringBytes, maxArrayLength: limits?.maxArrayLength ?? DV_LIMIT_DEFAULTS.maxArrayLength, maxMapLength: limits?.maxMapLength ?? DV_LIMIT_DEFAULTS.maxMapLength, }; @@ -216,12 +285,18 @@ function encodeValue( builder: ByteBuilder, limits: DvLimits, depth: number, + allowBytes: boolean, ): void { if (value === null) { builder.pushByte(0xf6); return; } + if (allowBytes && value instanceof Uint8Array) { + encodeByteString(value, builder, limits); + return; + } + const type = describeUnsupportedType(value); if (type === 'boolean') { builder.pushByte(value ? 0xf5 : 0xf4); @@ -239,12 +314,18 @@ function encodeValue( } if (Array.isArray(value)) { - encodeArray(value as DVArray, builder, limits, depth); + encodeArray(value as unknown[], builder, limits, depth, allowBytes); return; } if (isPlainObject(value)) { - encodeMap(value as Record, builder, limits, depth); + encodeMap( + value as Record, + builder, + limits, + depth, + allowBytes, + ); return; } @@ -305,11 +386,27 @@ function encodeString( builder.pushBytes(bytes); } +function encodeByteString( + value: Uint8Array, + builder: ByteBuilder, + limits: DvLimits, +): void { + if (value.length > limits.maxByteStringBytes) { + throw dvError( + 'BYTE_STRING_TOO_LONG', + `byte string exceeds maxByteStringBytes (${value.length} > ${limits.maxByteStringBytes})`, + ); + } + encodeTypeAndLength(builder, CBOR_MAJOR_BYTES, value.length); + builder.pushBytes(value); +} + function encodeArray( - value: DVArray, + value: unknown[], builder: ByteBuilder, limits: DvLimits, depth: number, + allowBytes: boolean, ): void { const nextDepth = depth + 1; if (nextDepth > limits.maxDepth) { @@ -324,7 +421,7 @@ function encodeArray( encodeTypeAndLength(builder, CBOR_MAJOR_ARRAY, value.length); for (const element of value) { - encodeValue(element, builder, limits, nextDepth); + encodeValue(element, builder, limits, nextDepth, allowBytes); } } @@ -333,6 +430,7 @@ function encodeMap( builder: ByteBuilder, limits: DvLimits, depth: number, + allowBytes: boolean, ): void { const keys = Object.keys(value); const nextDepth = depth + 1; @@ -373,7 +471,7 @@ function encodeMap( encodeTypeAndLength(builder, CBOR_MAJOR_MAP, encodedKeys.length); for (const entry of encodedKeys) { builder.pushBytes(entry.encoded); - encodeValue(value[entry.key], builder, limits, nextDepth); + encodeValue(value[entry.key], builder, limits, nextDepth, allowBytes); } } @@ -547,7 +645,12 @@ class CborReader { } } -function readValue(reader: CborReader, limits: DvLimits, depth: number): DV { +function readValue( + reader: CborReader, + limits: DvLimits, + depth: number, + allowBytes: boolean, +): DV2 { const initial = reader.readByte(); const major = initial >> 5; const additional = initial & 0x1f; @@ -557,12 +660,20 @@ function readValue(reader: CborReader, limits: DvLimits, depth: number): DV { return readUnsigned(additional, reader); case CBOR_MAJOR_NINT: return readNegative(additional, reader); + case CBOR_MAJOR_BYTES: + if (!allowBytes) { + throw dvError( + 'UNSUPPORTED_CBOR', + `unsupported CBOR major type ${major}`, + ); + } + return readByteString(additional, reader, limits); case CBOR_MAJOR_TEXT: return readText(additional, reader, limits); case CBOR_MAJOR_ARRAY: - return readArray(additional, reader, limits, depth); + return readArray(additional, reader, limits, depth, allowBytes); case CBOR_MAJOR_MAP: - return readMap(additional, reader, limits, depth); + return readMap(additional, reader, limits, depth, allowBytes); case CBOR_MAJOR_SIMPLE: return readSimpleOrFloat(additional, reader); default: @@ -570,6 +681,25 @@ function readValue(reader: CborReader, limits: DvLimits, depth: number): DV { } } +function readByteString( + additional: number, + reader: CborReader, + limits: DvLimits, +): Uint8Array { + const length = readLength(additional, reader); + if (length > limits.maxByteStringBytes) { + throw dvError( + 'BYTE_STRING_TOO_LONG', + `byte string exceeds maxByteStringBytes (${length} > ${limits.maxByteStringBytes})`, + ); + } + const start = reader.position(); + for (let i = 0; i < length; i += 1) { + reader.readByte(); + } + return reader.takeSlice(start, start + length); +} + function readUnsigned(additional: number, reader: CborReader): number { const value = readLengthValue(additional, reader); if (value > MAX_SAFE_INT) { @@ -627,7 +757,8 @@ function readArray( reader: CborReader, limits: DvLimits, depth: number, -): DVArray { + allowBytes: boolean, +): DV2Array { const length = readLength(additional, reader); const nextDepth = depth + 1; if (nextDepth > limits.maxDepth) { @@ -639,9 +770,9 @@ function readArray( `array length exceeds maxArrayLength (${length} > ${limits.maxArrayLength})`, ); } - const result: DVArray = []; + const result: DV2Array = []; for (let i = 0; i < length; i += 1) { - result.push(readValue(reader, limits, nextDepth)); + result.push(readValue(reader, limits, nextDepth, allowBytes)); } return result; } @@ -651,7 +782,8 @@ function readMap( reader: CborReader, limits: DvLimits, depth: number, -): DVObject { + allowBytes: boolean, +): DV2Object { const length = readLength(additional, reader); const nextDepth = depth + 1; @@ -665,7 +797,7 @@ function readMap( ); } - const result: DVObject = Object.create(null); + const result: DV2Object = Object.create(null); let previousKey: Uint8Array | undefined; for (let i = 0; i < length; i += 1) { @@ -690,7 +822,7 @@ function readMap( } previousKey = encodedKey; - result[key] = readValue(reader, limits, nextDepth); + result[key] = readValue(reader, limits, nextDepth, allowBytes); } return result; diff --git a/libs/execution-profiles/README.md b/libs/execution-profiles/README.md new file mode 100644 index 0000000..6a43dfd --- /dev/null +++ b/libs/execution-profiles/README.md @@ -0,0 +1,10 @@ +# @blue-quickjs/execution-profiles + +Canonical execution-profile registry shared by runtime and builder surfaces. + +Exports: + +- profile identifiers (`baseline-v1`, `compat-general-v1`, + `compat-binary-v1`) +- capability lookup helpers +- profile membership checks diff --git a/libs/execution-profiles/eslint.config.mjs b/libs/execution-profiles/eslint.config.mjs new file mode 100644 index 0000000..0a23ec0 --- /dev/null +++ b/libs/execution-profiles/eslint.config.mjs @@ -0,0 +1,25 @@ +import baseConfig from '../../eslint.config.mjs'; + +export default [ + ...baseConfig, + { + files: ['**/*.json'], + rules: { + '@nx/dependency-checks': [ + 'error', + { + ignoredFiles: [ + '{projectRoot}/eslint.config.{js,cjs,mjs,ts,cts,mts}', + '{projectRoot}/vite.config.{js,ts,mjs,mts}', + ], + }, + ], + }, + languageOptions: { + parser: await import('jsonc-eslint-parser'), + }, + }, + { + ignores: ['**/out-tsc'], + }, +]; diff --git a/libs/execution-profiles/package.json b/libs/execution-profiles/package.json new file mode 100644 index 0000000..a8aa8b0 --- /dev/null +++ b/libs/execution-profiles/package.json @@ -0,0 +1,35 @@ +{ + "name": "@blue-quickjs/execution-profiles", + "version": "0.4.1", + "type": "module", + "main": "./dist/index.js", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + "./package.json": "./package.json", + ".": { + "@blue-quickjs/source": "./src/index.ts", + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" + } + }, + "files": [ + "dist", + "!**/*.tsbuildinfo" + ], + "nx": { + "name": "execution-profiles" + }, + "dependencies": { + "tslib": "^2.3.0" + }, + "license": "MIT", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/bluecontract/blue-quickjs.git" + } +} diff --git a/libs/execution-profiles/src/index.ts b/libs/execution-profiles/src/index.ts new file mode 100644 index 0000000..07d6d8d --- /dev/null +++ b/libs/execution-profiles/src/index.ts @@ -0,0 +1 @@ +export * from './lib/execution-profiles.js'; diff --git a/libs/execution-profiles/src/lib/execution-profiles.spec.ts b/libs/execution-profiles/src/lib/execution-profiles.spec.ts new file mode 100644 index 0000000..19f184f --- /dev/null +++ b/libs/execution-profiles/src/lib/execution-profiles.spec.ts @@ -0,0 +1,53 @@ +import { + executionProfileHasCapability, + getExecutionProfileCapabilities, + isKnownExecutionProfile, + listExecutionProfiles, +} from './execution-profiles.js'; + +describe('execution profile registry', () => { + it('recognizes known public profiles', () => { + expect(isKnownExecutionProfile('baseline-v1')).toBe(true); + expect(isKnownExecutionProfile('compat-general-v1')).toBe(true); + expect(isKnownExecutionProfile('compat-binary-v1')).toBe(true); + expect(isKnownExecutionProfile('compat-unknown-v1')).toBe(false); + }); + + it('returns deterministic capability sets per profile', () => { + expect(getExecutionProfileCapabilities('baseline-v1')).toEqual([]); + expect(getExecutionProfileCapabilities('compat-general-v1')).toEqual([ + 'regexp', + 'promiseJobs', + 'queueMicrotask', + 'stableSort', + 'consoleShim', + ]); + expect(getExecutionProfileCapabilities('compat-binary-v1')).toEqual([ + 'regexp', + 'promiseJobs', + 'queueMicrotask', + 'stableSort', + 'consoleShim', + 'typedArrays', + 'dvBytes', + ]); + }); + + it('checks individual capability membership', () => { + expect(executionProfileHasCapability('baseline-v1', 'regexp')).toBe(false); + expect(executionProfileHasCapability('compat-general-v1', 'regexp')).toBe( + true, + ); + expect( + executionProfileHasCapability('compat-binary-v1', 'typedArrays'), + ).toBe(true); + }); + + it('lists all profiles in deterministic order', () => { + expect(listExecutionProfiles()).toEqual([ + 'baseline-v1', + 'compat-general-v1', + 'compat-binary-v1', + ]); + }); +}); diff --git a/libs/execution-profiles/src/lib/execution-profiles.ts b/libs/execution-profiles/src/lib/execution-profiles.ts new file mode 100644 index 0000000..e045917 --- /dev/null +++ b/libs/execution-profiles/src/lib/execution-profiles.ts @@ -0,0 +1,86 @@ +export type DeterministicCapability = + | 'regexp' + | 'promiseJobs' + | 'queueMicrotask' + | 'stableSort' + | 'consoleShim' + | 'typedArrays' + | 'dvBytes'; + +export type PublicExecutionProfile = + | 'baseline-v1' + | 'compat-general-v1' + | 'compat-binary-v1'; + +export interface ExecutionProfileDefinition { + id: PublicExecutionProfile; + capabilities: readonly DeterministicCapability[]; +} + +const PROFILE_CAPABILITIES: Record< + PublicExecutionProfile, + readonly DeterministicCapability[] +> = { + 'baseline-v1': [], + 'compat-general-v1': [ + 'regexp', + 'promiseJobs', + 'queueMicrotask', + 'stableSort', + 'consoleShim', + ], + 'compat-binary-v1': [ + 'regexp', + 'promiseJobs', + 'queueMicrotask', + 'stableSort', + 'consoleShim', + 'typedArrays', + 'dvBytes', + ], +}; + +export const EXECUTION_PROFILE_REGISTRY: Record< + PublicExecutionProfile, + ExecutionProfileDefinition +> = Object.freeze( + Object.fromEntries( + Object.entries(PROFILE_CAPABILITIES).map(([id, capabilities]) => [ + id, + { + id: id as PublicExecutionProfile, + capabilities, + }, + ]), + ) as Record, +); + +const KNOWN_PROFILES = Object.freeze( + new Set(Object.keys(PROFILE_CAPABILITIES) as PublicExecutionProfile[]), +); + +export function isKnownExecutionProfile( + value: unknown, +): value is PublicExecutionProfile { + return ( + typeof value === 'string' && + KNOWN_PROFILES.has(value as PublicExecutionProfile) + ); +} + +export function getExecutionProfileCapabilities( + profile: PublicExecutionProfile, +): readonly DeterministicCapability[] { + return PROFILE_CAPABILITIES[profile]; +} + +export function executionProfileHasCapability( + profile: PublicExecutionProfile, + capability: DeterministicCapability, +): boolean { + return PROFILE_CAPABILITIES[profile].includes(capability); +} + +export function listExecutionProfiles(): readonly PublicExecutionProfile[] { + return Object.keys(PROFILE_CAPABILITIES) as PublicExecutionProfile[]; +} diff --git a/libs/execution-profiles/tsconfig.json b/libs/execution-profiles/tsconfig.json new file mode 100644 index 0000000..62ebbd9 --- /dev/null +++ b/libs/execution-profiles/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../tsconfig.base.json", + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/libs/execution-profiles/tsconfig.lib.json b/libs/execution-profiles/tsconfig.lib.json new file mode 100644 index 0000000..d30b75b --- /dev/null +++ b/libs/execution-profiles/tsconfig.lib.json @@ -0,0 +1,28 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "baseUrl": ".", + "rootDir": "src", + "outDir": "dist", + "tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo", + "emitDeclarationOnly": false, + "forceConsistentCasingInFileNames": true, + "types": ["node"] + }, + "include": ["src/**/*.ts"], + "references": [], + "exclude": [ + "vite.config.ts", + "vite.config.mts", + "vitest.config.ts", + "vitest.config.mts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx" + ] +} diff --git a/libs/execution-profiles/tsconfig.spec.json b/libs/execution-profiles/tsconfig.spec.json new file mode 100644 index 0000000..f68d9d3 --- /dev/null +++ b/libs/execution-profiles/tsconfig.spec.json @@ -0,0 +1,34 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "./out-tsc/vitest", + "types": [ + "vitest/globals", + "vitest/importMeta", + "vite/client", + "node", + "vitest" + ], + "forceConsistentCasingInFileNames": true + }, + "include": [ + "vite.config.ts", + "vite.config.mts", + "vitest.config.ts", + "vitest.config.mts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx", + "src/**/*.d.ts" + ], + "references": [ + { + "path": "./tsconfig.lib.json" + } + ] +} diff --git a/libs/execution-profiles/vite.config.ts b/libs/execution-profiles/vite.config.ts new file mode 100644 index 0000000..9cecec2 --- /dev/null +++ b/libs/execution-profiles/vite.config.ts @@ -0,0 +1,20 @@ +/// +import { defineConfig } from 'vite'; + +export default defineConfig(() => ({ + root: import.meta.dirname, + cacheDir: '../../node_modules/.vite/libs/execution-profiles', + plugins: [], + test: { + name: 'execution-profiles', + watch: false, + globals: true, + environment: 'node', + include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], + reporters: ['default'], + coverage: { + reportsDirectory: './test-output/vitest/coverage', + provider: 'v8' as const, + }, + }, +})); diff --git a/libs/quickjs-runtime/README.md b/libs/quickjs-runtime/README.md index ebdf2f0..003d23f 100644 --- a/libs/quickjs-runtime/README.md +++ b/libs/quickjs-runtime/README.md @@ -9,7 +9,7 @@ TypeScript runtime SDK for **deterministic QuickJS-in-Wasm** evaluation with: If you are looking for the conceptual architecture and contracts, start with: - `docs/README.md` -- `docs/implementation-summary.md` +- `docs/concepts.md` --- @@ -46,6 +46,10 @@ const result = await evaluate({ // Optional observability: tape: { capacity: 32 }, gasTrace: true, + + // Release-mode pin validation: + releaseMode: true, + expectedExecutionProfile: 'baseline-v1', }); if (!result.ok) { @@ -60,7 +64,7 @@ console.log(result.value, result.gasUsed, result.gasRemaining); ## Docs - SDK guide: `docs/sdk.md` -- Implementation overview: `docs/implementation-summary.md` +- Implementation overview: `docs/concepts.md` - ABI + DV reference: - `docs/baseline-2.md` - `docs/abi-manifest.md` diff --git a/libs/quickjs-runtime/eslint.config.mjs b/libs/quickjs-runtime/eslint.config.mjs index 0a23ec0..36fab11 100644 --- a/libs/quickjs-runtime/eslint.config.mjs +++ b/libs/quickjs-runtime/eslint.config.mjs @@ -2,6 +2,28 @@ import baseConfig from '../../eslint.config.mjs'; export default [ ...baseConfig, + { + files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'], + rules: { + '@nx/enforce-module-boundaries': [ + 'error', + { + enforceBuildableLibDependency: true, + allow: ['^.*/eslint(\\.base)?\\.config\\.[cm]?[jt]s$'], + ignoredCircularDependencies: [ + ['quickjs-runtime', 'test-harness'], + ['quickjs-runtime', 'quickjs-wasm'], + ], + depConstraints: [ + { + sourceTag: '*', + onlyDependOnLibsWithTags: ['*'], + }, + ], + }, + ], + }, + }, { files: ['**/*.json'], rules: { @@ -11,7 +33,9 @@ export default [ ignoredFiles: [ '{projectRoot}/eslint.config.{js,cjs,mjs,ts,cts,mts}', '{projectRoot}/vite.config.{js,ts,mjs,mts}', + '{projectRoot}/src/test/**/*', ], + ignoredDependencies: ['vitest'], }, ], }, diff --git a/libs/quickjs-runtime/package.json b/libs/quickjs-runtime/package.json index 9bc661b..3b5f89d 100644 --- a/libs/quickjs-runtime/package.json +++ b/libs/quickjs-runtime/package.json @@ -24,10 +24,13 @@ "dependencies": { "@blue-quickjs/abi-manifest": "workspace:*", "@blue-quickjs/dv": "workspace:*", + "@blue-quickjs/execution-profiles": "workspace:*", "@blue-quickjs/quickjs-wasm": "workspace:*", + "@jridgewell/trace-mapping": "^0.3.31", "tslib": "^2.3.0" }, "devDependencies": { + "@blue-quickjs/deterministic-bundler": "workspace:*", "@blue-quickjs/test-harness": "workspace:*" }, "license": "MIT", diff --git a/libs/quickjs-runtime/src/lib/deterministic-init.spec.ts b/libs/quickjs-runtime/src/lib/deterministic-init.spec.ts deleted file mode 100644 index 9b6ff14..0000000 --- a/libs/quickjs-runtime/src/lib/deterministic-init.spec.ts +++ /dev/null @@ -1,152 +0,0 @@ -import { decodeDv } from '@blue-quickjs/dv'; -import { HOST_V1_HASH, HOST_V1_MANIFEST } from '@blue-quickjs/abi-manifest'; -import { initializeDeterministicVm } from './deterministic-init.js'; -import type { HostDispatcherHandlers } from './host-dispatcher.js'; -import { parseHexToBytes } from './hex-utils.js'; -import { createRuntime } from './runtime.js'; -import type { InputEnvelope, ProgramArtifact } from './quickjs-runtime.js'; - -const BASE_PROGRAM: ProgramArtifact = { - code: 'export default 1;', - abiId: 'Host.v1', - abiVersion: 1, - abiManifestHash: HOST_V1_HASH, -}; -const TEST_GAS_LIMIT = 10_000n; - -const BASE_INPUT: InputEnvelope = { - event: { type: 'create', payload: { id: 1 } }, - eventCanonical: { type: 'create', payload: { id: 1 } }, - steps: [{ name: 'first' }], - currentContract: { id: 'contract-1', kind: 'workflow' }, - currentContractCanonical: { id: { value: 'contract-1' }, kind: 'workflow' }, -}; - -describe('initializeDeterministicVm', () => { - it('installs ergonomic globals and freezes injected values', async () => { - const runtime = await createRuntime({ - manifest: HOST_V1_MANIFEST, - handlers: createHandlers(), - }); - - const vm = initializeDeterministicVm( - runtime, - BASE_PROGRAM, - BASE_INPUT, - TEST_GAS_LIMIT, - ); - try { - const output = vm.eval(` - (() => { - const docResult = document("path/to/doc"); - return { - docType: typeof document, - docCanonicalType: typeof document.canonical, - documentExtensible: Object.isExtensible(document), - canonExtensible: Object.isExtensible(canon), - eventFrozen: Object.isFrozen(event), - stepsFrozen: Object.isFrozen(steps), - currentContractFrozen: Object.isFrozen(currentContract), - currentContractCanonicalFrozen: Object.isFrozen(currentContractCanonical), - currentContract, - currentContractCanonical, - docResult - }; - })() - `); - - const parsed = parseEvalOutput(output); - if (parsed.kind === 'ERROR') { - throw new Error(`eval failed: ${parsed.message}`); - } - expect(parsed.kind).toBe('RESULT'); - expect(parsed.value).toMatchObject({ - docType: 'function', - docCanonicalType: 'function', - documentExtensible: false, - canonExtensible: false, - eventFrozen: true, - stepsFrozen: true, - currentContractFrozen: true, - currentContractCanonicalFrozen: true, - currentContract: { id: 'contract-1', kind: 'workflow' }, - currentContractCanonical: { - id: { value: 'contract-1' }, - kind: 'workflow', - }, - docResult: { path: 'path/to/doc' }, - }); - } finally { - vm.dispose(); - } - }); - - it('fails when the provided manifest hash does not match the bytes', async () => { - const runtime = await createRuntime({ - manifest: HOST_V1_MANIFEST, - handlers: createHandlers(), - }); - const badProgram: ProgramArtifact = { - ...BASE_PROGRAM, - abiManifestHash: '0'.repeat(64), - }; - - expect(() => - initializeDeterministicVm( - runtime, - badProgram, - BASE_INPUT, - TEST_GAS_LIMIT, - ), - ).toThrow(/manifest hash/i); - }); -}); - -function createHandlers( - overrides?: Partial, -): HostDispatcherHandlers { - return { - document: { - get: - overrides?.document?.get ?? - ((path: string) => ({ ok: { path }, units: 5 })), - getCanonical: - overrides?.document?.getCanonical ?? - ((path: string) => ({ ok: { canonical: path }, units: 3 })), - }, - emit: - overrides?.emit ?? - (() => ({ - ok: null, - units: 1, - })), - }; -} - -function parseEvalOutput(raw: string): { - kind: 'RESULT' | 'ERROR'; - message: string; - value: unknown; - gasRemaining: number; - gasUsed: number; -} { - const match = - /^(RESULT|ERROR)\s+(.+?)\s+GAS\s+remaining=(\d+)\s+used=(\d+)/.exec( - raw.trim(), - ); - if (!match) { - throw new Error(`Unable to parse eval output: ${raw}`); - } - - const [, kind, payload, remaining, used] = match; - const value = - kind === 'RESULT' ? decodeDv(parseHexToBytes(payload)) : payload.trim(); - - return { - kind: kind as 'RESULT' | 'ERROR', - message: payload, - value, - gasRemaining: Number(remaining), - gasUsed: Number(used), - }; -} diff --git a/libs/quickjs-runtime/src/lib/deterministic-init.ts b/libs/quickjs-runtime/src/lib/deterministic-init.ts index ecddee4..2f066fa 100644 --- a/libs/quickjs-runtime/src/lib/deterministic-init.ts +++ b/libs/quickjs-runtime/src/lib/deterministic-init.ts @@ -1,7 +1,9 @@ import { encodeAbiManifest } from '@blue-quickjs/abi-manifest'; import { encodeDv } from '@blue-quickjs/dv'; +import { executionProfileHasCapability } from '@blue-quickjs/execution-profiles'; import type { QuickjsWasmModule } from './runtime.js'; import { + type ExecutionProfile, type InputEnvelope, type ProgramArtifact, validateInputEnvelope, @@ -19,36 +21,60 @@ type DetInitFn = ( contextPtr: number, contextLength: number, gasLimit: bigint, + featureFlags: number, ) => number; type DetEvalFn = (code: string) => number; +type DetEvalModulePackFn = ( + modulePackJson: string, + entrySpecifier: string, + entryExport: string, +) => number; type DetSetGasLimitFn = (gasLimit: bigint) => number; type EnableTapeFn = (capacity: number) => number; type ReadTapeFn = () => number; +type EnableChargeTapeFn = (capacity: number) => number; +type ReadChargeTapeFn = () => number; type EnableTraceFn = (enabled: number) => number; type ReadTraceFn = () => number; interface DeterministicExports { init: DetInitFn; eval: DetEvalFn; + evalModulePack: DetEvalModulePackFn; setGasLimit: DetSetGasLimitFn; freeRuntime: () => void; enableTape: EnableTapeFn; readTape: ReadTapeFn; + enableChargeTape: EnableChargeTapeFn; + readChargeTape: ReadChargeTapeFn; enableTrace: EnableTraceFn; readTrace: ReadTraceFn; } export interface DeterministicVm { eval(code: string): string; + evalModulePack( + modulePackJson: string, + entrySpecifier: string, + entryExport: string, + ): string; setGasLimit(limit: bigint | number): void; enableTape(capacity: number): void; readTape(): string; + enableGasChargeTape(capacity: number): void; + readGasChargeTape(): string; enableGasTrace(enabled: boolean): void; readGasTrace(): string; dispose(): void; } +const DETERMINISTIC_FEATURE_REGEXP = 1 << 0; +const DETERMINISTIC_FEATURE_PROMISE_JOBS = 1 << 1; +const DETERMINISTIC_FEATURE_CONSOLE_SHIM = 1 << 2; +const DETERMINISTIC_FEATURE_STABLE_SORT = 1 << 3; +const DETERMINISTIC_FEATURE_TYPED_ARRAYS = 1 << 4; + export function initializeDeterministicVm( runtime: RuntimeInstance, program: ProgramArtifact, @@ -85,6 +111,7 @@ export function initializeDeterministicVm( contextPtr, contextBlob.length, normalizedGasLimit, + executionProfileToFeatureFlags(validatedProgram.executionProfile), ); if (errorPtr !== 0) { const message = readAndFreeCString(runtime.module, errorPtr); @@ -107,6 +134,21 @@ export function initializeDeterministicVm( } return readAndFreeCString(runtime.module, ptr); }, + evalModulePack( + modulePackJson: string, + entrySpecifier: string, + entryExport: string, + ): string { + const ptr = ffi.evalModulePack( + modulePackJson, + entrySpecifier, + entryExport, + ); + if (ptr === 0) { + throw new Error('qjs_det_eval_module_pack returned a null pointer'); + } + return readAndFreeCString(runtime.module, ptr); + }, setGasLimit(limit: bigint | number): void { const normalized = normalizeGasLimit(limit); const rc = ffi.setGasLimit(normalized); @@ -132,6 +174,24 @@ export function initializeDeterministicVm( } return readAndFreeCString(runtime.module, ptr); }, + enableGasChargeTape(capacity: number): void { + if (!Number.isInteger(capacity) || capacity < 0) { + throw new Error( + `charge tape capacity must be a non-negative integer (received ${capacity})`, + ); + } + const rc = ffi.enableChargeTape(capacity >>> 0); + if (rc !== 0) { + throw new Error('failed to enable gas charge tape'); + } + }, + readGasChargeTape(): string { + const ptr = ffi.readChargeTape(); + if (ptr === 0) { + throw new Error('qjs_det_read_charge_tape returned a null pointer'); + } + return readAndFreeCString(runtime.module, ptr); + }, enableGasTrace(enabled: boolean): void { const rc = ffi.enableTrace(enabled ? 1 : 0); if (rc !== 0) { @@ -161,11 +221,17 @@ function createDeterministicExports( 'number', 'number', 'bigint', + 'number', ]) as unknown as DetInitFn; const evalFn = module.cwrap('qjs_det_eval', 'number', [ 'string', ]) as unknown as DetEvalFn; + const evalModulePack = module.cwrap('qjs_det_eval_module_pack', 'number', [ + 'string', + 'string', + 'string', + ]) as unknown as DetEvalModulePackFn; const setGasLimit = module.cwrap('qjs_det_set_gas_limit', 'number', [ 'bigint', ]) as unknown as DetSetGasLimitFn; @@ -183,6 +249,16 @@ function createDeterministicExports( 'number', [], ) as unknown as ReadTapeFn; + const enableChargeTape = module.cwrap( + 'qjs_det_enable_charge_tape', + 'number', + ['number'], + ) as unknown as EnableChargeTapeFn; + const readChargeTape = module.cwrap( + 'qjs_det_read_charge_tape', + 'number', + [], + ) as unknown as ReadChargeTapeFn; const enableTrace = module.cwrap('qjs_det_enable_trace', 'number', [ 'number', ]) as unknown as EnableTraceFn; @@ -195,10 +271,13 @@ function createDeterministicExports( return { init, eval: evalFn, + evalModulePack, setGasLimit, freeRuntime, enableTape, readTape, + enableChargeTape, + readChargeTape, enableTrace, readTrace, }; @@ -212,7 +291,11 @@ function normalizeGasLimit(value: bigint | number): bigint { if (value < 0) { throw new Error('gasLimit must be non-negative'); } - return BigInt(value); + const normalized = BigInt(value); + if (normalized > UINT64_MAX) { + throw new Error(`gasLimit exceeds uint64 range (${value})`); + } + return normalized; } if (typeof value !== 'bigint') { @@ -230,6 +313,32 @@ function normalizeGasLimit(value: bigint | number): bigint { return value; } +function executionProfileToFeatureFlags(profile?: ExecutionProfile): number { + if (!profile) { + return 0; + } + let flags = 0; + if (executionProfileHasCapability(profile, 'regexp')) { + flags |= DETERMINISTIC_FEATURE_REGEXP; + } + if ( + executionProfileHasCapability(profile, 'promiseJobs') || + executionProfileHasCapability(profile, 'queueMicrotask') + ) { + flags |= DETERMINISTIC_FEATURE_PROMISE_JOBS; + } + if (executionProfileHasCapability(profile, 'consoleShim')) { + flags |= DETERMINISTIC_FEATURE_CONSOLE_SHIM; + } + if (executionProfileHasCapability(profile, 'stableSort')) { + flags |= DETERMINISTIC_FEATURE_STABLE_SORT; + } + if (executionProfileHasCapability(profile, 'typedArrays')) { + flags |= DETERMINISTIC_FEATURE_TYPED_ARRAYS; + } + return flags; +} + function writeBytes(module: QuickjsWasmModule, data: Uint8Array): number { const ptr = module._malloc(data.length); if (ptr === 0) { diff --git a/libs/quickjs-runtime/src/lib/evaluate-errors.ts b/libs/quickjs-runtime/src/lib/evaluate-errors.ts index 29e2ff4..9ad70f6 100644 --- a/libs/quickjs-runtime/src/lib/evaluate-errors.ts +++ b/libs/quickjs-runtime/src/lib/evaluate-errors.ts @@ -26,6 +26,24 @@ export type EvaluateVmErrorDetail = name: string; message: string; } + | { + kind: 'execution-surface-mismatch'; + code: 'EXECUTION_SURFACE_MISMATCH'; + tag: 'vm/execution_surface'; + name: string; + message: string; + } + | { + kind: 'module-pack'; + code: + | 'MODULE_PACK_HASH_MISMATCH' + | 'MODULE_SPECIFIER_NOT_FOUND' + | 'MODULE_EXPORT_MISSING' + | 'MODULE_RESOLUTION_ERROR' + | 'MODULE_EVALUATION_ERROR'; + tag: 'vm/module_pack'; + message: string; + } | { kind: 'unknown'; code: 'UNKNOWN'; @@ -78,6 +96,21 @@ export function mapVmError( }; } + if (isExecutionSurfaceMismatch(name, normalizedMessage)) { + return { + kind: 'execution-surface-mismatch', + code: 'EXECUTION_SURFACE_MISMATCH', + tag: 'vm/execution_surface', + name: name || 'SyntaxError', + message: normalizedMessage, + }; + } + + const modulePackError = parseModulePackError(name, normalizedMessage); + if (modulePackError) { + return modulePackError; + } + if (name && name !== 'Error') { return { kind: 'js-exception', @@ -97,6 +130,72 @@ export function mapVmError( }; } +function parseModulePackError( + name: string, + message: string, +): EvaluateVmErrorDetail | null { + if ( + name === 'ModulePackHashMismatch' || + message.startsWith('MODULE_PACK_HASH_MISMATCH') + ) { + return { + kind: 'module-pack', + code: 'MODULE_PACK_HASH_MISMATCH', + tag: 'vm/module_pack', + message, + }; + } + + if ( + name === 'ModuleSpecifierNotFound' || + message.startsWith('ModuleSpecifierNotFound') || + message.includes('ModuleSpecifierNotFound') + ) { + return { + kind: 'module-pack', + code: 'MODULE_SPECIFIER_NOT_FOUND', + tag: 'vm/module_pack', + message, + }; + } + + if ( + name === 'ModuleExportMissing' || + message.startsWith('ModuleExportMissing') || + message.includes('ModuleExportMissing') + ) { + return { + kind: 'module-pack', + code: 'MODULE_EXPORT_MISSING', + tag: 'vm/module_pack', + message, + }; + } + + if ( + message.startsWith('ModuleResolutionError') || + message.includes('ModuleResolutionError') + ) { + return { + kind: 'module-pack', + code: 'MODULE_RESOLUTION_ERROR', + tag: 'vm/module_pack', + message, + }; + } + + if (name === 'ModuleEvaluationError') { + return { + kind: 'module-pack', + code: 'MODULE_EVALUATION_ERROR', + tag: 'vm/module_pack', + message, + }; + } + + return null; +} + export function createInvalidOutputError( message: string, cause: unknown, @@ -150,3 +249,16 @@ function deriveManifestErrorCode(message: string): string { } return 'MANIFEST_ERROR'; } + +function isExecutionSurfaceMismatch(name: string, message: string): boolean { + if (name !== 'SyntaxError') { + return false; + } + + const normalized = message.toLowerCase(); + return ( + normalized.includes('return not in a function') || + normalized.includes('illegal return') || + normalized.includes('return outside of function') + ); +} diff --git a/libs/quickjs-runtime/src/lib/evaluate.spec.ts b/libs/quickjs-runtime/src/lib/evaluate.spec.ts deleted file mode 100644 index 3b01370..0000000 --- a/libs/quickjs-runtime/src/lib/evaluate.spec.ts +++ /dev/null @@ -1,556 +0,0 @@ -import { HOST_V1_HASH, HOST_V1_MANIFEST } from '@blue-quickjs/abi-manifest'; -import { vi } from 'vitest'; -import { evaluate } from './evaluate.js'; -import type { HostDispatcherHandlers } from './host-dispatcher.js'; -import type { InputEnvelope, ProgramArtifact } from './quickjs-runtime.js'; - -const TEST_GAS_LIMIT = 50_000n; - -const BASE_PROGRAM: ProgramArtifact = { - code: 'document("path/to/doc")', - abiId: 'Host.v1', - abiVersion: 1, - abiManifestHash: HOST_V1_HASH, -}; - -const BASE_INPUT: InputEnvelope = { - event: { type: 'create', payload: { id: 1 } }, - eventCanonical: { type: 'create', payload: { id: 1 } }, - steps: [{ name: 'first' }], - currentContract: { id: 'contract-1' }, - currentContractCanonical: { id: { value: 'contract-1' } }, -}; - -describe('evaluate', () => { - it('returns DV results with gas accounting', async () => { - const handlers = createHandlers(); - const result = await evaluate({ - program: BASE_PROGRAM, - input: BASE_INPUT, - gasLimit: TEST_GAS_LIMIT, - manifest: HOST_V1_MANIFEST, - handlers, - }); - - expect(result.ok).toBe(true); - if (!result.ok) { - throw new Error(result.message); - } - - expect(result.value).toEqual({ path: 'path/to/doc' }); - expect(typeof result.gasUsed).toBe('bigint'); - expect(typeof result.gasRemaining).toBe('bigint'); - expect(handlers.document.get).toHaveBeenCalledTimes(1); - }); - - it('maps VM errors to a structured failure', async () => { - const handlers = createHandlers(); - const result = await evaluate({ - program: { ...BASE_PROGRAM, code: 'document(123)' }, - input: BASE_INPUT, - gasLimit: TEST_GAS_LIMIT, - manifest: HOST_V1_MANIFEST, - handlers, - }); - - expect(result.ok).toBe(false); - if (result.ok) { - throw new Error('expected VM failure'); - } - expect(result.type).toBe('vm-error'); - expect(result.error.kind).toBe('js-exception'); - expect(result.error.code).toBe('JS_EXCEPTION'); - expect(result.error.message).toMatch(/document/i); - expect(handlers.document.get).not.toHaveBeenCalled(); - }); - - it('rejects unsupported return types at the VM boundary', async () => { - const unsupported = ['undefined', '(() => {})', 'Symbol("x")', '1n']; - - for (const code of unsupported) { - const result = await evaluate({ - program: { ...BASE_PROGRAM, code }, - input: BASE_INPUT, - gasLimit: TEST_GAS_LIMIT, - manifest: HOST_V1_MANIFEST, - handlers: createHandlers(), - }); - - expect(result.ok).toBe(false); - if (result.ok) { - throw new Error('expected VM failure'); - } - expect(result.type).toBe('vm-error'); - expect(result.error.kind).toBe('js-exception'); - } - }); - - it('applies output DV limits to returned payloads', async () => { - const result = await evaluate({ - program: { ...BASE_PROGRAM, code: '"hello world"' }, - input: BASE_INPUT, - gasLimit: TEST_GAS_LIMIT, - manifest: HOST_V1_MANIFEST, - handlers: createHandlers(), - outputDvLimits: { maxEncodedBytes: 4 }, - }); - - expect(result.ok).toBe(false); - if (result.ok) { - throw new Error('expected invalid output'); - } - - expect(result.type).toBe('invalid-output'); - expect(result.error.code).toBe('INVALID_OUTPUT'); - expect(result.message).toMatch(/payload exceeds/i); - }); - - it('maps HostError failures to code/tag using the manifest', async () => { - const handlers = createHandlers({ - document: { - get: vi.fn(() => ({ - err: { code: 'NOT_FOUND', tag: 'host/not_found' }, - units: 2, - })), - }, - }); - - const result = await evaluate({ - program: BASE_PROGRAM, - input: BASE_INPUT, - gasLimit: TEST_GAS_LIMIT, - manifest: HOST_V1_MANIFEST, - handlers, - }); - - expect(result.ok).toBe(false); - if (result.ok) { - throw new Error('expected host error'); - } - - expect(result.type).toBe('vm-error'); - expect(result.error.kind).toBe('host-error'); - if (result.error.kind !== 'host-error') { - throw new Error('expected host-error'); - } - expect(result.error.code).toBe('NOT_FOUND'); - expect(result.error.tag).toBe('host/not_found'); - }); - - it('maps host transport failures to a stable code/tag', async () => { - const handlers = createHandlers({ - document: { - get: vi.fn( - () => - ({ - ok: { path: 'path/to/doc' }, - }) as unknown as ReturnType< - HostDispatcherHandlers['document']['get'] - >, - ), - }, - }); - - const result = await evaluate({ - program: BASE_PROGRAM, - input: BASE_INPUT, - gasLimit: TEST_GAS_LIMIT, - manifest: HOST_V1_MANIFEST, - handlers, - }); - - expect(result.ok).toBe(false); - if (result.ok) { - throw new Error('expected host transport error'); - } - - expect(result.type).toBe('vm-error'); - expect(result.error.kind).toBe('host-error'); - if (result.error.kind !== 'host-error') { - throw new Error('expected host-error'); - } - expect(result.error.code).toBe('HOST_TRANSPORT'); - expect(result.error.tag).toBe('host/transport'); - }); - - it('surfaces OutOfGas as a stable code/tag', async () => { - const result = await evaluate({ - program: { ...BASE_PROGRAM, code: 'let n = 0; while (true) { n += 1; }' }, - input: BASE_INPUT, - gasLimit: 50n, - manifest: HOST_V1_MANIFEST, - handlers: createHandlers(), - }); - - expect(result.ok).toBe(false); - if (result.ok) { - throw new Error('expected OOG'); - } - - expect(result.type).toBe('vm-error'); - expect(result.error.kind).toBe('out-of-gas'); - if (result.error.kind !== 'out-of-gas') { - throw new Error('expected out-of-gas'); - } - expect(result.error.code).toBe('OOG'); - expect(result.error.tag).toBe('vm/out_of_gas'); - }); - - it('rejects engine build hash mismatches', async () => { - const program: ProgramArtifact = { - ...BASE_PROGRAM, - engineBuildHash: '0'.repeat(64), - }; - - await expect( - evaluate({ - program, - input: BASE_INPUT, - gasLimit: TEST_GAS_LIMIT, - manifest: HOST_V1_MANIFEST, - handlers: createHandlers(), - }), - ).rejects.toThrow(/enginebuildhash/i); - }); - - it('returns host-call tape when requested', async () => { - const result = await evaluate({ - program: BASE_PROGRAM, - input: BASE_INPUT, - gasLimit: TEST_GAS_LIMIT, - manifest: HOST_V1_MANIFEST, - handlers: createHandlers(), - tape: { capacity: 8 }, - }); - - expect(result.ok).toBe(true); - if (!result.ok) { - throw new Error(result.message); - } - - expect(result.tape).toBeDefined(); - expect(result.tape?.length).toBeGreaterThan(0); - const [record] = result.tape ?? []; - expect(record.fnId).toBe(getFnId('document.get')); - expect(typeof record.gasPre).toBe('bigint'); - expect(typeof record.gasPost).toBe('bigint'); - expect(record.reqHash).toHaveLength(64); - expect(record.respHash).toHaveLength(64); - }); - - it('returns gas trace when requested', async () => { - const result = await evaluate({ - program: { ...BASE_PROGRAM, code: '1 + 2' }, - input: BASE_INPUT, - gasLimit: TEST_GAS_LIMIT, - manifest: HOST_V1_MANIFEST, - handlers: createHandlers(), - gasTrace: true, - }); - - expect(result.ok).toBe(true); - if (!result.ok) { - throw new Error(result.message); - } - - expect(result.gasTrace).toBeDefined(); - expect((result.gasTrace?.opcodeCount ?? 0n) >= 0n).toBe(true); - expect((result.gasTrace?.allocationBytes ?? 0n) >= 0n).toBe(true); - expect((result.gasTrace?.jsonParseCount ?? 0n) >= 0n).toBe(true); - expect((result.gasTrace?.jsonStringifyCount ?? 0n) >= 0n).toBe(true); - }); - - it('supports deterministic JSON parse and canonical stringify', async () => { - const result = await evaluate({ - program: { - ...BASE_PROGRAM, - code: `JSON.stringify(JSON.parse('{"aa":1,"b":2}'))`, - }, - input: BASE_INPUT, - gasLimit: TEST_GAS_LIMIT, - manifest: HOST_V1_MANIFEST, - handlers: createHandlers(), - gasTrace: true, - }); - - expect(result.ok).toBe(true); - if (!result.ok) { - throw new Error(result.message); - } - - expect(result.value).toBe('{"b":2,"aa":1}'); - expect((result.gasTrace?.jsonParseCount ?? 0n) > 0n).toBe(true); - expect((result.gasTrace?.jsonStringifyCount ?? 0n) > 0n).toBe(true); - }); - - it('rejects unsupported deterministic JSON options', async () => { - const cases = [ - { - code: `JSON.parse('[]', () => 1)`, - message: /reviver is not supported/i, - }, - { - code: `JSON.stringify({ aa: 1, b: 2 }, [])`, - message: /replacer is not supported/i, - }, - { - code: `JSON.stringify({ aa: 1, b: 2 }, null, 2)`, - message: /space is not supported/i, - }, - ]; - - for (const testCase of cases) { - const result = await evaluate({ - program: { ...BASE_PROGRAM, code: testCase.code }, - input: BASE_INPUT, - gasLimit: TEST_GAS_LIMIT, - manifest: HOST_V1_MANIFEST, - handlers: createHandlers(), - }); - - expect(result.ok).toBe(false); - if (result.ok) { - throw new Error('expected deterministic JSON option failure'); - } - expect(result.type).toBe('vm-error'); - expect(result.error.kind).toBe('js-exception'); - expect(result.message).toMatch(testCase.message); - } - }); - - it('rejects malformed deterministic JSON strings and keys', async () => { - const cases = [ - { - code: `JSON.parse('"\\ud800"')`, - message: /string contains lone surrogate code points/i, - }, - { - code: `JSON.parse('{"\\ud800":1}')`, - message: /key contains lone surrogate code points/i, - }, - { - code: `JSON.stringify('\\ud800')`, - message: /string contains lone surrogate code points/i, - }, - { - code: `(() => { - const key = '\\ud800'; - return JSON.stringify({ [key]: 1 }); - })()`, - message: /key contains lone surrogate code points/i, - }, - ]; - - for (const testCase of cases) { - const result = await evaluate({ - program: { ...BASE_PROGRAM, code: testCase.code }, - input: BASE_INPUT, - gasLimit: TEST_GAS_LIMIT, - manifest: HOST_V1_MANIFEST, - handlers: createHandlers(), - }); - - expect(result.ok).toBe(false); - if (result.ok) { - throw new Error('expected malformed deterministic JSON failure'); - } - expect(result.type).toBe('vm-error'); - expect(result.error.kind).toBe('js-exception'); - expect(result.message).toMatch(testCase.message); - } - }); - - it('rejects deeply nested deterministic JSON before parser stack overflow', async () => { - const depth = 10_000; - const json = '['.repeat(depth) + '0' + ']'.repeat(depth); - const result = await evaluate({ - program: { - ...BASE_PROGRAM, - code: `JSON.parse(${JSON.stringify(json)})`, - }, - input: BASE_INPUT, - gasLimit: 200_000n, - manifest: HOST_V1_MANIFEST, - handlers: createHandlers(), - }); - - expect(result.ok).toBe(false); - if (result.ok) { - throw new Error('expected deterministic JSON depth failure'); - } - expect(result.type).toBe('vm-error'); - expect(result.error.kind).toBe('js-exception'); - expect(result.message).toMatch(/maxDepth 64 exceeded/i); - }); - - it('rejects oversized deterministic JSON arrays before building the full parse result', async () => { - const length = 66_000; - const json = '[' + '0,'.repeat(length - 1) + '0]'; - const result = await evaluate({ - program: { - ...BASE_PROGRAM, - code: `JSON.parse(${JSON.stringify(json)})`, - }, - input: BASE_INPUT, - gasLimit: 2_000_000n, - manifest: HOST_V1_MANIFEST, - handlers: createHandlers(), - gasTrace: true, - }); - - expect(result.ok).toBe(false); - if (result.ok) { - throw new Error('expected deterministic JSON array length failure'); - } - expect(result.type).toBe('vm-error'); - expect(result.error.kind).toBe('js-exception'); - expect(result.message).toMatch( - /array length exceeds maxArrayLength \(\d+ > 65535\)/i, - ); - expect((result.gasTrace?.allocationBytes ?? 0n) < 3_500_000n).toBe(true); - }); - - it('rejects oversized deterministic JSON strings before materializing full tokens', async () => { - const cases = [ - { - code: `JSON.parse('"' + 'a'.repeat(262_145) + '"')`, - message: /string exceeds maxStringBytes \(\d+ > 262144\)/i, - }, - { - code: `JSON.parse('{"' + 'a'.repeat(262_145) + '":1}')`, - message: /key exceeds maxStringBytes \(\d+ > 262144\)/i, - }, - ]; - - for (const testCase of cases) { - const result = await evaluate({ - program: { - ...BASE_PROGRAM, - code: testCase.code, - }, - input: BASE_INPUT, - gasLimit: 2_000_000n, - manifest: HOST_V1_MANIFEST, - handlers: createHandlers(), - gasTrace: true, - }); - - expect(result.ok).toBe(false); - if (result.ok) { - throw new Error('expected deterministic JSON string length failure'); - } - expect(result.type).toBe('vm-error'); - expect(result.error.kind).toBe('js-exception'); - expect(result.message).toMatch(testCase.message); - expect((result.gasTrace?.allocationBytes ?? 0n) < 1_800_000n).toBe(true); - } - }); - - it('rejects accessor properties during deterministic JSON stringify', async () => { - const cases = [ - { - code: `JSON.stringify({ get a() { return 1; } })`, - message: /accessor properties/i, - }, - { - code: `(() => { - const arr = [1]; - Object.defineProperty(arr, 0, { - get() { - return 1; - }, - enumerable: true, - }); - return JSON.stringify(arr); - })()`, - message: /accessor properties/i, - }, - ]; - - for (const testCase of cases) { - const result = await evaluate({ - program: { ...BASE_PROGRAM, code: testCase.code }, - input: BASE_INPUT, - gasLimit: TEST_GAS_LIMIT, - manifest: HOST_V1_MANIFEST, - handlers: createHandlers(), - }); - - expect(result.ok).toBe(false); - if (result.ok) { - throw new Error('expected deterministic JSON accessor failure'); - } - expect(result.type).toBe('vm-error'); - expect(result.error.kind).toBe('js-exception'); - expect(result.message).toMatch(testCase.message); - } - }); - - it('serializes sparse arrays without consulting the prototype chain', async () => { - const result = await evaluate({ - program: { - ...BASE_PROGRAM, - code: `(() => { - let getterCalls = 0; - Object.defineProperty(Array.prototype, 0, { - get() { - getterCalls += 1; - return 1; - }, - configurable: true, - }); - try { - return [JSON.stringify([,]), getterCalls]; - } finally { - delete Array.prototype[0]; - } - })()`, - }, - input: BASE_INPUT, - gasLimit: TEST_GAS_LIMIT, - manifest: HOST_V1_MANIFEST, - handlers: createHandlers(), - }); - - expect(result.ok).toBe(true); - if (!result.ok) { - throw new Error(result.message); - } - - expect(result.value).toEqual(['[null]', 0]); - }); -}); - -function createHandlers( - overrides?: Partial<{ - document: Partial; - emit: HostDispatcherHandlers['emit']; - }>, -): HostDispatcherHandlers { - return { - document: { - get: - overrides?.document?.get ?? - vi.fn((path: string) => ({ ok: { path }, units: 5 })), - getCanonical: - overrides?.document?.getCanonical ?? - vi.fn((path: string) => ({ ok: { canonical: path }, units: 3 })), - }, - emit: - overrides?.emit ?? - vi.fn(() => ({ - ok: null, - units: 1, - })), - }; -} - -function getFnId(path: string): number { - const fn = HOST_V1_MANIFEST.functions.find( - (entry) => entry.js_path.join('.') === path, - ); - if (!fn) { - throw new Error(`missing fn_id for ${path}`); - } - return fn.fn_id; -} diff --git a/libs/quickjs-runtime/src/lib/evaluate.ts b/libs/quickjs-runtime/src/lib/evaluate.ts index 93c4316..dc75e8e 100644 --- a/libs/quickjs-runtime/src/lib/evaluate.ts +++ b/libs/quickjs-runtime/src/lib/evaluate.ts @@ -11,11 +11,15 @@ import type { HostDispatcherOptions, } from './host-dispatcher.js'; import { + type ExecutionProfile, type InputEnvelope, type InputValidationOptions, + type ModulePackV1, type ProgramArtifact, + type ProgramArtifactV2, validateInputEnvelope, validateProgramArtifact, + validateProgramArtifactV2, } from './quickjs-runtime.js'; import { type RuntimeArtifactSelection, @@ -29,10 +33,11 @@ import { type EvaluateVmErrorDetail, } from './evaluate-errors.js'; import { parseHexToBytes } from './hex-utils.js'; +import { remapModulePackErrorPayload } from './source-map-remap.js'; export interface EvaluateOptions extends RuntimeArtifactSelection, HostDispatcherOptions { - program: ProgramArtifact; + program: ProgramArtifact | ProgramArtifactV2; input: InputEnvelope; gasLimit: bigint | number; manifest: AbiManifest; @@ -50,6 +55,19 @@ export interface EvaluateOptions * Enable gas trace recording for the evaluation. */ gasTrace?: boolean; + /** + * Enable gas charge event tape recording (capacity defaults to 256; max 8192). + */ + gasChargeTape?: { capacity?: number }; + /** + * Enforce release-mode artifact pin requirements. + */ + releaseMode?: boolean; + /** + * Optional execution-profile pin asserted by the embedding runtime. + * When provided, evaluation rejects artifacts whose executionProfile differs. + */ + expectedExecutionProfile?: ExecutionProfile; } export type EvaluateSuccess = { @@ -59,6 +77,7 @@ export type EvaluateSuccess = { gasRemaining: bigint; raw: string; tape?: HostTapeRecord[]; + gasChargeTape?: GasChargeRecord[]; gasTrace?: GasTrace; }; @@ -70,6 +89,7 @@ type EvaluateFailureBase = { gasRemaining: bigint; raw: string; tape?: HostTapeRecord[]; + gasChargeTape?: GasChargeRecord[]; gasTrace?: GasTrace; }; @@ -88,12 +108,30 @@ export type EvaluateError = EvaluateVmError | EvaluateInvalidOutputError; export type EvaluateResult = EvaluateSuccess | EvaluateError; const HOST_TAPE_MAX_CAPACITY = 1024; +const GAS_CHARGE_TAPE_MAX_CAPACITY = 8192; export async function evaluate( options: EvaluateOptions, ): Promise { - const program = validateProgramArtifact(options.program); + const program = normalizeProgramForExecution(options.program); + if (program.mode === 'module-pack') { + await assertModulePackHash(program.modulePack); + } const input = validateInputEnvelope(options.input, options.inputValidation); + if (options.releaseMode) { + assertReleaseArtifactPins(program.legacyArtifact); + if (!options.expectedExecutionProfile) { + throw new Error( + 'release-mode requires expectedExecutionProfile to be provided', + ); + } + } + if (options.expectedExecutionProfile) { + assertExecutionProfile( + program.legacyArtifact, + options.expectedExecutionProfile, + ); + } const runtime = await createRuntime({ manifest: options.manifest, @@ -103,15 +141,16 @@ export async function evaluate( metadata: options.metadata, wasmBinary: options.wasmBinary, dvLimits: options.dvLimits, - expectedAbiId: program.abiId, - expectedAbiVersion: program.abiVersion, + expectedAbiId: program.legacyArtifact.abiId, + expectedAbiVersion: program.legacyArtifact.abiVersion, }); - assertEngineBuildHash(program, runtime); + assertEngineBuildHash(program.legacyArtifact, runtime); + assertGasVersion(program.legacyArtifact, runtime); const vm = initializeDeterministicVm( runtime, - program, + program.legacyArtifact, input, options.gasLimit, ); @@ -129,20 +168,50 @@ export async function evaluate( vm.enableTape(capacity); } + if (options.gasChargeTape) { + const capacity = options.gasChargeTape.capacity ?? 256; + if (!Number.isInteger(capacity) || capacity < 0) { + throw new Error( + 'gas charge tape capacity must be a non-negative integer', + ); + } + if (capacity > GAS_CHARGE_TAPE_MAX_CAPACITY) { + throw new Error( + `gas charge tape capacity exceeds max (${GAS_CHARGE_TAPE_MAX_CAPACITY}); received ${capacity}`, + ); + } + vm.enableGasChargeTape(capacity); + } + if (options.gasTrace) { vm.enableGasTrace(true); } try { - const raw = vm.eval(program.code); + const raw = + program.mode === 'script' + ? vm.eval(program.legacyArtifact.code) + : vm.evalModulePack( + serializeModulePackModules(program.modulePack), + program.modulePack.entrySpecifier, + program.entryExport, + ); const parsed = parseEvalOutput(raw); - const tape = options.tape ? parseTape(vm.readTape()) : undefined; const trace = options.gasTrace ? parseGasTrace(vm.readGasTrace()) : undefined; + const tape = options.tape ? parseTape(vm.readTape()) : undefined; + const gasChargeTape = options.gasChargeTape + ? parseGasChargeTape(vm.readGasChargeTape()) + : undefined; if (parsed.kind === 'error') { - const error = mapVmError(parsed.payload, runtime.manifest); + const payload = + program.mode === 'module-pack' + ? remapModulePackErrorPayload(parsed.payload, program.modulePack) + .payload + : parsed.payload; + const error = mapVmError(payload, runtime.manifest); return { ok: false, type: 'vm-error', @@ -152,6 +221,7 @@ export async function evaluate( gasRemaining: parsed.gasRemaining, raw, tape, + gasChargeTape, gasTrace: trace, }; } @@ -168,6 +238,7 @@ export async function evaluate( gasRemaining: parsed.gasRemaining, raw, tape, + gasChargeTape, gasTrace: trace, }; } @@ -179,6 +250,7 @@ export async function evaluate( gasRemaining: parsed.gasRemaining, raw, tape, + gasChargeTape, gasTrace: trace, }; } finally { @@ -277,6 +349,16 @@ export interface HostTapeRecord { respHash: string; } +export interface GasChargeRecord { + siteId: number; + kind: number; + flags: number; + amount: bigint; + logicalUnits: bigint; + gasBefore: bigint; + gasAfter: bigint; +} + function parseTape(raw: string): HostTapeRecord[] { const parsed = parseJson(raw, 'tape'); if (!Array.isArray(parsed)) { @@ -314,6 +396,49 @@ function parseTape(raw: string): HostTapeRecord[] { }); } +function parseGasChargeTape(raw: string): GasChargeRecord[] { + const parsed = parseJson(raw, 'gasChargeTape'); + if (!Array.isArray(parsed)) { + throw new Error('gasChargeTape payload is not an array'); + } + + return parsed.map((record, idx) => { + if (record === null || typeof record !== 'object') { + throw new Error(`gasChargeTape record ${idx} is not an object`); + } + + const siteId = expectUint32(record.siteId, `gasChargeTape[${idx}].siteId`); + const kind = expectUint32(record.kind, `gasChargeTape[${idx}].kind`); + const flags = expectUint32(record.flags, `gasChargeTape[${idx}].flags`); + const amount = expectBigIntString( + record.amount, + `gasChargeTape[${idx}].amount`, + ); + const logicalUnits = expectBigIntString( + record.logicalUnits, + `gasChargeTape[${idx}].logicalUnits`, + ); + const gasBefore = expectBigIntString( + record.gasBefore, + `gasChargeTape[${idx}].gasBefore`, + ); + const gasAfter = expectBigIntString( + record.gasAfter, + `gasChargeTape[${idx}].gasAfter`, + ); + + return { + siteId, + kind, + flags, + amount, + logicalUnits, + gasBefore, + gasAfter, + }; + }); +} + export interface GasTrace { opcodeCount: bigint; opcodeGas: bigint; @@ -322,6 +447,7 @@ export interface GasTrace { arrayCbPerElCount: bigint; arrayCbPerElGas: bigint; allocationCount: bigint; + allocationRequestedBytes: bigint; allocationBytes: bigint; allocationGas: bigint; jsonParseCount: bigint; @@ -337,6 +463,10 @@ export interface GasTrace { jsonStringifyObjectEntries: bigint; jsonStringifyArrayElements: bigint; jsonStringifySortComparisons: bigint; + hostCallPreCount: bigint; + hostCallPreGas: bigint; + hostCallPostCount: bigint; + hostCallPostGas: bigint; } function parseGasTrace(raw: string): GasTrace { @@ -365,6 +495,10 @@ function parseGasTrace(raw: string): GasTrace { obj.allocationCount, 'gasTrace.allocationCount', ), + allocationRequestedBytes: expectBigIntString( + obj.allocationRequestedBytes ?? obj.allocationBytes, + 'gasTrace.allocationRequestedBytes', + ), allocationBytes: expectBigIntString( obj.allocationBytes, 'gasTrace.allocationBytes', @@ -422,6 +556,22 @@ function parseGasTrace(raw: string): GasTrace { obj.jsonStringifySortComparisons, 'gasTrace.jsonStringifySortComparisons', ), + hostCallPreCount: expectBigIntString( + obj.hostCallPreCount, + 'gasTrace.hostCallPreCount', + ), + hostCallPreGas: expectBigIntString( + obj.hostCallPreGas, + 'gasTrace.hostCallPreGas', + ), + hostCallPostCount: expectBigIntString( + obj.hostCallPostCount, + 'gasTrace.hostCallPostCount', + ), + hostCallPostGas: expectBigIntString( + obj.hostCallPostGas, + 'gasTrace.hostCallPostGas', + ), }; } @@ -495,6 +645,8 @@ function normalizeDvLimits(overrides?: Partial): DvLimits { overrides?.maxEncodedBytes ?? DV_LIMIT_DEFAULTS.maxEncodedBytes, maxStringBytes: overrides?.maxStringBytes ?? DV_LIMIT_DEFAULTS.maxStringBytes, + maxByteStringBytes: + overrides?.maxByteStringBytes ?? DV_LIMIT_DEFAULTS.maxByteStringBytes, maxArrayLength: overrides?.maxArrayLength ?? DV_LIMIT_DEFAULTS.maxArrayLength, maxMapLength: overrides?.maxMapLength ?? DV_LIMIT_DEFAULTS.maxMapLength, @@ -516,7 +668,7 @@ function parseUint64(text: string, label: string): bigint { } function assertEngineBuildHash( - program: ProgramArtifact, + program: { engineBuildHash?: string }, runtime: RuntimeInstance, ): void { if (!program.engineBuildHash) { @@ -541,6 +693,246 @@ function assertEngineBuildHash( } } +function assertGasVersion( + program: { gasVersion?: number }, + runtime: RuntimeInstance, +): void { + if (program.gasVersion === undefined) { + return; + } + + const runtimeGasVersion = runtime.metadata.gasVersion; + if (runtimeGasVersion === null || runtimeGasVersion === undefined) { + throw new Error( + 'Runtime gasVersion is unavailable; cannot verify program.gasVersion', + ); + } + + if (runtimeGasVersion !== program.gasVersion) { + throw new Error( + `gasVersion mismatch: program=${program.gasVersion} runtime=${runtimeGasVersion}`, + ); + } +} + +function assertReleaseArtifactPins(program: { + engineBuildHash?: string; + gasVersion?: number; + executionProfile?: string; +}): void { + if (!program.engineBuildHash) { + throw new Error( + 'release-mode requires program.engineBuildHash to be provided', + ); + } + if (program.gasVersion === undefined) { + throw new Error('release-mode requires program.gasVersion to be provided'); + } + if (!program.executionProfile) { + throw new Error( + 'release-mode requires program.executionProfile to be provided', + ); + } +} + +function assertExecutionProfile( + program: { executionProfile?: string }, + expectedExecutionProfile: string, +): void { + if (!program.executionProfile) { + throw new Error( + 'executionProfile pin cannot be validated because program.executionProfile is missing', + ); + } + if (program.executionProfile !== expectedExecutionProfile) { + throw new Error( + `executionProfile mismatch: program=${program.executionProfile} runtime=${expectedExecutionProfile}`, + ); + } +} + +type NormalizedProgramForExecution = + | { + mode: 'script'; + legacyArtifact: ProgramArtifact; + } + | { + mode: 'module-pack'; + legacyArtifact: ProgramArtifact; + modulePack: ModulePackV1; + entryExport: string; + }; + +function normalizeProgramForExecution( + program: unknown, +): NormalizedProgramForExecution { + if (isProgramArtifactV2(program)) { + const validated = validateProgramArtifactV2(program); + if (validated.sourceKind === 'script') { + if (!('code' in validated.source)) { + throw new Error( + 'INVALID_PROGRAM: script source is missing code payload', + ); + } + + return { + mode: 'script', + legacyArtifact: { + code: validated.source.code, + abiId: validated.abiId, + abiVersion: validated.abiVersion, + abiManifestHash: validated.abiManifestHash, + ...(validated.engineBuildHash + ? { engineBuildHash: validated.engineBuildHash } + : {}), + ...(validated.gasVersion !== undefined + ? { gasVersion: validated.gasVersion } + : {}), + executionProfile: validated.executionProfile, + }, + }; + } + + if (!('modulePack' in validated.source)) { + throw new Error( + 'INVALID_PROGRAM: module-pack source is missing modulePack payload', + ); + } + + return { + mode: 'module-pack', + legacyArtifact: { + code: '', + abiId: validated.abiId, + abiVersion: validated.abiVersion, + abiManifestHash: validated.abiManifestHash, + ...(validated.engineBuildHash + ? { engineBuildHash: validated.engineBuildHash } + : {}), + ...(validated.gasVersion !== undefined + ? { gasVersion: validated.gasVersion } + : {}), + executionProfile: validated.executionProfile, + }, + modulePack: validated.source.modulePack, + entryExport: validated.source.modulePack.entryExport ?? 'default', + }; + } + + return { + mode: 'script', + legacyArtifact: validateProgramArtifact(program), + }; +} + +async function assertModulePackHash(modulePack: ModulePackV1): Promise { + const computed = await computeModulePackGraphHash(modulePack); + if (computed !== modulePack.graphHash) { + throw new Error( + `MODULE_PACK_HASH_MISMATCH: expected=${modulePack.graphHash} computed=${computed}`, + ); + } +} + +async function computeModulePackGraphHash( + modulePack: ModulePackV1, +): Promise { + const canonical = { + version: modulePack.version, + entrySpecifier: modulePack.entrySpecifier, + entryExport: modulePack.entryExport ?? 'default', + modules: [...modulePack.modules] + .sort((left, right) => + compareUtf8ByteOrder(left.specifier, right.specifier), + ) + .map((module) => ({ + specifier: module.specifier, + source: module.source, + ...(module.sourceMap ? { sourceMap: module.sourceMap } : {}), + })), + builderVersion: modulePack.builderVersion, + dependencyIntegrity: modulePack.dependencyIntegrity, + }; + const payload = new TextEncoder().encode(stableStringify(canonical)); + const subtle = getSubtleCrypto(); + const digest = await subtle.digest('SHA-256', payload); + return [...new Uint8Array(digest)] + .map((byte) => byte.toString(16).padStart(2, '0')) + .join(''); +} + +function serializeModulePackModules(modulePack: ModulePackV1): string { + return JSON.stringify( + modulePack.modules.map((module) => ({ + specifier: module.specifier, + source: module.source, + })), + ); +} + +function stableStringify(value: unknown): string { + if (value === null || typeof value !== 'object') { + return JSON.stringify(value); + } + if (Array.isArray(value)) { + return `[${value.map((item) => stableStringify(item)).join(',')}]`; + } + + const entries = Object.entries(value as Record) + .filter(([, item]) => item !== undefined) + .sort(([left], [right]) => compareUtf8ByteOrder(left, right)) + .map(([key, item]) => `${JSON.stringify(key)}:${stableStringify(item)}`); + return `{${entries.join(',')}}`; +} + +const UTF8_ENCODER = new TextEncoder(); + +function compareUtf8ByteOrder(left: string, right: string): number { + if (left === right) { + return 0; + } + + const leftBytes = UTF8_ENCODER.encode(left); + const rightBytes = UTF8_ENCODER.encode(right); + const limit = Math.min(leftBytes.length, rightBytes.length); + + for (let index = 0; index < limit; index += 1) { + const delta = leftBytes[index] - rightBytes[index]; + if (delta !== 0) { + return delta; + } + } + + return leftBytes.length - rightBytes.length; +} + +type SubtleDigestApi = { + digest( + algorithm: string, + data: ArrayBuffer | ArrayBufferView, + ): Promise; +}; + +function getSubtleCrypto(): SubtleDigestApi { + const subtle = + globalThis.crypto && 'subtle' in globalThis.crypto + ? globalThis.crypto.subtle + : null; + if (!subtle) { + throw new Error( + 'MODULE_PACK_HASH_MISMATCH: crypto.subtle is unavailable for graph hash verification', + ); + } + return subtle; +} + +function isProgramArtifactV2(value: unknown): value is ProgramArtifactV2 { + if (value === null || typeof value !== 'object' || Array.isArray(value)) { + return false; + } + return (value as { version?: unknown }).version === 2; +} + export type { EvaluateInvalidOutputDetail, EvaluateVmErrorDetail, diff --git a/libs/quickjs-runtime/src/lib/host-dispatcher.ts b/libs/quickjs-runtime/src/lib/host-dispatcher.ts index 5eaf158..5352071 100644 --- a/libs/quickjs-runtime/src/lib/host-dispatcher.ts +++ b/libs/quickjs-runtime/src/lib/host-dispatcher.ts @@ -5,13 +5,16 @@ import { validateAbiManifest, } from '@blue-quickjs/abi-manifest'; import { - type DV, + type DV2, DV_LIMIT_DEFAULTS, type DvLimits, DvError, decodeDv, + decodeDv2, encodeDv, + encodeDv2, validateDv, + validateDv2, } from '@blue-quickjs/dv'; const UINT32_MAX = 0xffffffff; @@ -20,20 +23,20 @@ const UTF8 = new TextEncoder(); export interface HostCallError { code: string; tag: string; - details?: DV; + details?: DV2; } -export type HostCallResult = +export type HostCallResult = | { ok: T; units: number } | { err: HostCallError; units: number }; export interface DocumentHostHandlers { - get(path: string): HostCallResult; - getCanonical(path: string): HostCallResult; + get(path: string): HostCallResult; + getCanonical(path: string): HostCallResult; } export interface EmitHostHandler { - emit(value: DV): HostCallResult; + emit(value: DV2): HostCallResult; } export interface HostDispatcherHandlers { @@ -118,6 +121,7 @@ export function createHostDispatcher( } const dvLimits = normalizeDvLimits(options?.dvLimits); + const dvCodec = selectDvCodec(canonical); const bindings = buildBindings(canonical.functions, handlers); return { @@ -138,6 +142,7 @@ export function createHostDispatcher( return encodeEnvelope( binding.fn, binding.limitExceededEnvelope, + dvCodec, dvLimits, ); } @@ -152,9 +157,9 @@ export function createHostDispatcher( ), }; - let args: DV; + let args: DV2; try { - args = decodeDv(request, { limits: decodeLimits }); + args = decodeRequest(request, decodeLimits, dvCodec); } catch (err) { return fatal( 'INVALID_REQUEST', @@ -177,7 +182,7 @@ export function createHostDispatcher( } try { - return binding.dispatch(args, dvLimits); + return binding.dispatch(args, dvLimits, dvCodec); } catch (err) { return fatal( 'HANDLER_ERROR', @@ -241,7 +246,7 @@ export function createHostCallImport( type HostFunctionBinding = { fn: CanonicalFunction; - dispatch(args: DV[], dvLimits: DvLimits): HostDispatchResult; + dispatch(args: DV2[], dvLimits: DvLimits, codec: DvCodec): HostDispatchResult; limitExceededEnvelope?: HostResponseEnvelope; }; @@ -250,8 +255,16 @@ type CanonicalFunction = AbiFunction & { }; type HostResponseEnvelope = - | { ok: DV; units: number } - | { err: { code: string; details?: DV }; units: number }; + | { ok: DV2; units: number } + | { err: { code: string; details?: DV2 }; units: number }; + +type DvCodec = 'dv1' | 'dv2'; + +function selectDvCodec(manifest: CanonicalAbiManifest): DvCodec { + return manifest.abi_id === 'Host.v2' && manifest.abi_version >= 2 + ? 'dv2' + : 'dv1'; +} function buildBindings( functions: AbiFunction[], @@ -269,7 +282,7 @@ function buildBindings( if (!documentGet || !documentGetCanonical) { throw new HostDispatcherError( 'INVALID_REQUEST', - 'Host.v1 manifest must include document.get and document.getCanonical', + 'manifest must include document.get and document.getCanonical', ); } @@ -321,7 +334,11 @@ function buildDocumentBinding( return { fn, limitExceededEnvelope, - dispatch(args: DV[], dvLimits: DvLimits): HostDispatchResult { + dispatch( + args: DV2[], + dvLimits: DvLimits, + codec: DvCodec, + ): HostDispatchResult { const [path] = args; if (typeof path !== 'string') { return fatal( @@ -335,7 +352,7 @@ function buildDocumentBinding( const byteLen = UTF8.encode(path).byteLength; if (byteLen > utf8Max) { if (limitExceededEnvelope) { - return encodeEnvelope(fn, limitExceededEnvelope, dvLimits); + return encodeEnvelope(fn, limitExceededEnvelope, codec, dvLimits); } return fatal( 'INVALID_ARGUMENTS', @@ -345,7 +362,7 @@ function buildDocumentBinding( } const result = handler(path); - return encodeResult(fn, result, dvLimits, limitExceededEnvelope); + return encodeResult(fn, result, dvLimits, codec, limitExceededEnvelope); }, }; } @@ -359,10 +376,14 @@ function buildEmitBinding( return { fn, limitExceededEnvelope, - dispatch(args: DV[], dvLimits: DvLimits): HostDispatchResult { + dispatch( + args: DV2[], + dvLimits: DvLimits, + codec: DvCodec, + ): HostDispatchResult { const [value] = args; const result = handler(value); - return encodeResult(fn, result, dvLimits, limitExceededEnvelope); + return encodeResult(fn, result, dvLimits, codec, limitExceededEnvelope); }, }; } @@ -371,6 +392,7 @@ function encodeResult( fn: CanonicalFunction, result: HostCallResult, dvLimits: DvLimits, + codec: DvCodec, limitExceededEnvelope?: HostResponseEnvelope, ): HostDispatchResult { if (result === null || typeof result !== 'object') { @@ -406,7 +428,7 @@ function encodeResult( } if (units === null) { if (limitExceededEnvelope) { - return encodeEnvelope(fn, limitExceededEnvelope, dvLimits); + return encodeEnvelope(fn, limitExceededEnvelope, codec, dvLimits); } return fatal( 'INVALID_ARGUMENTS', @@ -423,13 +445,14 @@ function encodeResult( } if (fn.return_schema.type === 'dv') { try { - validateDv(result.ok, { + validateHostValue(result.ok, codec, { limits: cappedDvLimits(dvLimits, fn.limits.max_response_bytes), }); } catch (err) { return handleDvValidationError( fn, err, + codec, limitExceededEnvelope, dvLimits, ); @@ -439,6 +462,7 @@ function encodeResult( return encodeEnvelope( fn, { ok: result.ok, units }, + codec, dvLimits, limitExceededEnvelope, ); @@ -471,11 +495,17 @@ function encodeResult( if (result.err.details !== undefined) { try { - validateDv(result.err.details, { + validateHostValue(result.err.details, codec, { limits: cappedDvLimits(dvLimits, fn.limits.max_response_bytes), }); } catch (err) { - return handleDvValidationError(fn, err, limitExceededEnvelope, dvLimits); + return handleDvValidationError( + fn, + err, + codec, + limitExceededEnvelope, + dvLimits, + ); } } @@ -488,6 +518,7 @@ function encodeResult( : { code: result.err.code, details: result.err.details }, units, }, + codec, dvLimits, limitExceededEnvelope, ); @@ -496,17 +527,20 @@ function encodeResult( function encodeEnvelope( fn: CanonicalFunction, envelope: HostResponseEnvelope, + codec: DvCodec, dvLimits: DvLimits, limitExceededEnvelope?: HostResponseEnvelope, ): HostDispatchResult { const encodeLimits = cappedDvLimits(dvLimits, fn.limits.max_response_bytes); try { - const bytes = encodeDv(envelope, { limits: encodeLimits }); + const bytes = encodeHostValue(envelope, codec, { limits: encodeLimits }); return { kind: 'response', envelope: bytes }; } catch (err) { if (limitExceededEnvelope && isSizeRelatedDvError(err)) { try { - const bytes = encodeDv(limitExceededEnvelope, { limits: encodeLimits }); + const bytes = encodeHostValue(limitExceededEnvelope, codec, { + limits: encodeLimits, + }); return { kind: 'response', envelope: bytes }; } catch (limitErr) { return fatal( @@ -579,11 +613,12 @@ function assertEmitShape(fn: CanonicalFunction): void { function handleDvValidationError( fn: CanonicalFunction, err: unknown, + codec: DvCodec, limitExceededEnvelope: HostResponseEnvelope | undefined, dvLimits: DvLimits, ): HostDispatchResult { if (limitExceededEnvelope && isSizeRelatedDvError(err)) { - return encodeEnvelope(fn, limitExceededEnvelope, dvLimits); + return encodeEnvelope(fn, limitExceededEnvelope, codec, dvLimits); } return fatal( 'HANDLER_ERROR', @@ -592,6 +627,36 @@ function handleDvValidationError( ); } +function decodeRequest( + bytes: Uint8Array, + limits: DvLimits, + codec: DvCodec, +): DV2 { + return codec === 'dv2' + ? decodeDv2(bytes, { limits }) + : (decodeDv(bytes, { limits }) as DV2); +} + +function validateHostValue( + value: unknown, + codec: DvCodec, + options: { limits: DvLimits }, +): void { + if (codec === 'dv2') { + validateDv2(value, options); + return; + } + validateDv(value, options); +} + +function encodeHostValue( + value: unknown, + codec: DvCodec, + options: { limits: DvLimits }, +): Uint8Array { + return codec === 'dv2' ? encodeDv2(value, options) : encodeDv(value, options); +} + function cappedDvLimits(limits: DvLimits, maxBytes: number): DvLimits { return { ...limits, @@ -605,6 +670,8 @@ function normalizeDvLimits(limits?: Partial): DvLimits { maxEncodedBytes: limits?.maxEncodedBytes ?? DV_LIMIT_DEFAULTS.maxEncodedBytes, maxStringBytes: limits?.maxStringBytes ?? DV_LIMIT_DEFAULTS.maxStringBytes, + maxByteStringBytes: + limits?.maxByteStringBytes ?? DV_LIMIT_DEFAULTS.maxByteStringBytes, maxArrayLength: limits?.maxArrayLength ?? DV_LIMIT_DEFAULTS.maxArrayLength, maxMapLength: limits?.maxMapLength ?? DV_LIMIT_DEFAULTS.maxMapLength, }; @@ -683,6 +750,7 @@ function isSizeRelatedDvError(err: unknown): boolean { err instanceof DvError && (err.code === 'ENCODED_TOO_LARGE' || err.code === 'STRING_TOO_LONG' || + err.code === 'BYTE_STRING_TOO_LONG' || err.code === 'ARRAY_TOO_LONG' || err.code === 'MAP_TOO_LONG' || err.code === 'DEPTH_EXCEEDED') diff --git a/libs/quickjs-runtime/src/lib/quickjs-runtime.ts b/libs/quickjs-runtime/src/lib/quickjs-runtime.ts index 2320da5..787576a 100644 --- a/libs/quickjs-runtime/src/lib/quickjs-runtime.ts +++ b/libs/quickjs-runtime/src/lib/quickjs-runtime.ts @@ -5,16 +5,68 @@ import { DvLimits, validateDv, } from '@blue-quickjs/dv'; +import { + isKnownExecutionProfile, + type PublicExecutionProfile, +} from '@blue-quickjs/execution-profiles'; const UINT32_MAX = 0xffffffff; const SHA256_HEX_LENGTH = 64; const HEX_RE = /^[0-9a-f]+$/; + +export type ExecutionProfile = PublicExecutionProfile; + +export interface ModulePackV1Module { + specifier: string; + source: string; + sourceMap?: string; + originMeta?: { + packageName?: string; + packageVersion?: string; + integrity?: string; + originalPath?: string; + }; +} + +export interface ModulePackV1 { + version: 1; + entrySpecifier: string; + entryExport?: string; + modules: ModulePackV1Module[]; + graphHash: string; + builderVersion: string; + dependencyIntegrity: string; + diagnosticsMeta?: Record; +} + +export interface ProgramArtifactV2ScriptSource { + code: string; +} + +export interface ProgramArtifactV2ModulePackSource { + modulePack: ModulePackV1; +} + +export interface ProgramArtifactV2 { + version: 2; + abiId: string; + abiVersion: number; + abiManifestHash: string; + engineBuildHash?: string; + gasVersion?: number; + executionProfile: ExecutionProfile; + sourceKind: 'script' | 'module-pack'; + source: ProgramArtifactV2ScriptSource | ProgramArtifactV2ModulePackSource; +} + export interface ProgramArtifact { code: string; abiId: string; abiVersion: number; abiManifestHash: string; engineBuildHash?: string; + gasVersion?: number; + executionProfile?: ExecutionProfile; } export interface ProgramArtifactLimits { @@ -45,6 +97,7 @@ export interface InputValidationOptions { export type RuntimeValidationErrorCode = | 'INVALID_TYPE' + | 'INVALID_VALUE' | 'MISSING_FIELD' | 'UNKNOWN_FIELD' | 'EMPTY_STRING' @@ -73,8 +126,17 @@ export function validateProgramArtifact( const program = expectPlainObject(value, 'program'); enforceExactKeys( program, - ['code', 'abiId', 'abiVersion', 'abiManifestHash', 'engineBuildHash'], + [ + 'code', + 'abiId', + 'abiVersion', + 'abiManifestHash', + 'engineBuildHash', + 'gasVersion', + 'executionProfile', + ], 'program', + ['engineBuildHash', 'gasVersion', 'executionProfile'], ); const code = expectString(program.code, 'program.code', { @@ -101,6 +163,17 @@ export function validateProgramArtifact( exactLength: SHA256_HEX_LENGTH, }) : undefined; + const gasVersion = + program.gasVersion !== undefined + ? expectUint(program.gasVersion, 0, UINT32_MAX, 'program.gasVersion') + : undefined; + const executionProfile = + program.executionProfile !== undefined + ? expectExecutionProfile( + program.executionProfile, + 'program.executionProfile', + ) + : undefined; return { code, @@ -108,6 +181,84 @@ export function validateProgramArtifact( abiVersion, abiManifestHash, engineBuildHash, + gasVersion, + executionProfile, + }; +} + +export function validateProgramArtifactV2( + value: unknown, + options?: ProgramValidationOptions, +): ProgramArtifactV2 { + const limits = normalizeProgramLimits(options?.limits); + const artifact = expectPlainObject(value, 'program'); + enforceExactKeys( + artifact, + [ + 'version', + 'abiId', + 'abiVersion', + 'abiManifestHash', + 'engineBuildHash', + 'gasVersion', + 'executionProfile', + 'sourceKind', + 'source', + ], + 'program', + ['engineBuildHash', 'gasVersion'], + ); + + const version = expectUint(artifact.version, 2, 2, 'program.version') as 2; + const abiId = expectString(artifact.abiId, 'program.abiId', { + maxLength: limits.maxAbiIdLength, + }); + const abiVersion = expectUint( + artifact.abiVersion, + 1, + UINT32_MAX, + 'program.abiVersion', + ); + const abiManifestHash = expectHexString( + artifact.abiManifestHash, + 'program.abiManifestHash', + { exactLength: SHA256_HEX_LENGTH }, + ); + const engineBuildHash = + artifact.engineBuildHash !== undefined + ? expectHexString(artifact.engineBuildHash, 'program.engineBuildHash', { + exactLength: SHA256_HEX_LENGTH, + }) + : undefined; + const gasVersion = + artifact.gasVersion !== undefined + ? expectUint(artifact.gasVersion, 0, UINT32_MAX, 'program.gasVersion') + : undefined; + const executionProfile = expectExecutionProfile( + artifact.executionProfile, + 'program.executionProfile', + ); + const sourceKind = expectSourceKind( + artifact.sourceKind, + 'program.sourceKind', + ); + const source = validateProgramV2Source( + artifact.source, + sourceKind, + limits, + 'program.source', + ); + + return { + version, + abiId, + abiVersion, + abiManifestHash, + ...(engineBuildHash ? { engineBuildHash } : {}), + ...(gasVersion !== undefined ? { gasVersion } : {}), + executionProfile, + sourceKind, + source, }; } @@ -127,6 +278,7 @@ export function validateInputEnvelope( 'currentContractCanonical', ], 'input', + ['currentContract', 'currentContractCanonical'], ); const event = validateDvField(input.event, dvLimits, 'input.event'); @@ -198,7 +350,21 @@ function enforceExactKeys( value: Record, allowed: string[], path: string, + optional: string[] = [], ): void { + for (const requiredKey of allowed) { + if (optional.includes(requiredKey)) { + continue; + } + if (!(requiredKey in value)) { + throw runtimeError( + 'MISSING_FIELD', + `${path} is missing required field "${requiredKey}"`, + `${path}.${requiredKey}`, + ); + } + } + for (const key of Object.keys(value)) { if (!allowed.includes(key)) { throw runtimeError( @@ -286,6 +452,192 @@ function expectUint( return value; } +function expectExecutionProfile( + value: unknown, + path: string, +): ExecutionProfile { + if (!isKnownExecutionProfile(value)) { + throw runtimeError( + 'INVALID_VALUE', + `${path} must be one of baseline-v1, compat-general-v1, compat-binary-v1`, + path, + ); + } + return value; +} + +function expectSourceKind( + value: unknown, + path: string, +): 'script' | 'module-pack' { + if (value !== 'script' && value !== 'module-pack') { + throw runtimeError( + 'INVALID_VALUE', + `${path} must be "script" or "module-pack"`, + path, + ); + } + return value; +} + +function validateProgramV2Source( + value: unknown, + sourceKind: 'script' | 'module-pack', + limits: ProgramArtifactLimits, + path: string, +): ProgramArtifactV2ScriptSource | ProgramArtifactV2ModulePackSource { + const source = expectPlainObject(value, path); + if (sourceKind === 'script') { + enforceExactKeys(source, ['code'], path); + return { + code: expectString(source.code, `${path}.code`, { + maxLength: limits.maxCodeUnits, + allowEmpty: true, + }), + }; + } + + enforceExactKeys(source, ['modulePack'], path); + return { + modulePack: validateModulePackV1(source.modulePack, `${path}.modulePack`), + }; +} + +function validateModulePackV1(value: unknown, path: string): ModulePackV1 { + const pack = expectPlainObject(value, path); + enforceExactKeys( + pack, + [ + 'version', + 'entrySpecifier', + 'entryExport', + 'modules', + 'graphHash', + 'builderVersion', + 'dependencyIntegrity', + 'diagnosticsMeta', + ], + path, + ['entryExport', 'diagnosticsMeta'], + ); + + const version = expectUint(pack.version, 1, 1, `${path}.version`) as 1; + const entrySpecifier = expectString( + pack.entrySpecifier, + `${path}.entrySpecifier`, + ); + const entryExport = + pack.entryExport !== undefined + ? expectString(pack.entryExport, `${path}.entryExport`) + : undefined; + const modules = expectArray(pack.modules, `${path}.modules`).map( + (moduleValue, index) => + validateModulePackModule(moduleValue, `${path}.modules[${index}]`), + ); + const graphHash = expectHexString(pack.graphHash, `${path}.graphHash`, { + exactLength: SHA256_HEX_LENGTH, + }); + const builderVersion = expectString( + pack.builderVersion, + `${path}.builderVersion`, + ); + const dependencyIntegrity = expectHexString( + pack.dependencyIntegrity, + `${path}.dependencyIntegrity`, + { + exactLength: SHA256_HEX_LENGTH, + }, + ); + + return { + version, + entrySpecifier, + ...(entryExport ? { entryExport } : {}), + modules, + graphHash, + builderVersion, + dependencyIntegrity, + ...(pack.diagnosticsMeta !== undefined + ? { + diagnosticsMeta: expectRecord( + pack.diagnosticsMeta, + `${path}.diagnosticsMeta`, + ), + } + : {}), + }; +} + +function validateModulePackModule( + value: unknown, + path: string, +): ModulePackV1Module { + const module = expectPlainObject(value, path); + enforceExactKeys( + module, + ['specifier', 'source', 'sourceMap', 'originMeta'], + path, + ['sourceMap', 'originMeta'], + ); + + const originMeta = + module.originMeta !== undefined + ? validateModulePackOriginMeta(module.originMeta, `${path}.originMeta`) + : undefined; + + return { + specifier: expectString(module.specifier, `${path}.specifier`), + source: expectString(module.source, `${path}.source`, { allowEmpty: true }), + ...(module.sourceMap !== undefined + ? { sourceMap: expectString(module.sourceMap, `${path}.sourceMap`) } + : {}), + ...(originMeta ? { originMeta } : {}), + }; +} + +function validateModulePackOriginMeta( + value: unknown, + path: string, +): NonNullable { + const originMeta = expectPlainObject(value, path); + enforceExactKeys( + originMeta, + ['packageName', 'packageVersion', 'integrity', 'originalPath'], + path, + ['packageName', 'packageVersion', 'integrity', 'originalPath'], + ); + + return { + ...(originMeta.packageName !== undefined + ? { + packageName: expectString( + originMeta.packageName, + `${path}.packageName`, + ), + } + : {}), + ...(originMeta.packageVersion !== undefined + ? { + packageVersion: expectString( + originMeta.packageVersion, + `${path}.packageVersion`, + ), + } + : {}), + ...(originMeta.integrity !== undefined + ? { integrity: expectString(originMeta.integrity, `${path}.integrity`) } + : {}), + ...(originMeta.originalPath !== undefined + ? { + originalPath: expectString( + originMeta.originalPath, + `${path}.originalPath`, + ), + } + : {}), + }; +} + function normalizeProgramLimits( overrides?: Partial, ): ProgramArtifactLimits { @@ -297,6 +649,20 @@ function normalizeProgramLimits( }; } +function expectArray(value: unknown, path: string): unknown[] { + if (!Array.isArray(value)) { + throw runtimeError('INVALID_TYPE', `${path} must be an array`, path); + } + return value; +} + +function expectRecord(value: unknown, path: string): Record { + if (value === null || typeof value !== 'object' || Array.isArray(value)) { + throw runtimeError('INVALID_TYPE', `${path} must be an object`, path); + } + return value as Record; +} + function normalizeDvLimits(overrides?: Partial): DvLimits { return { maxDepth: overrides?.maxDepth ?? DV_LIMIT_DEFAULTS.maxDepth, @@ -304,6 +670,8 @@ function normalizeDvLimits(overrides?: Partial): DvLimits { overrides?.maxEncodedBytes ?? DV_LIMIT_DEFAULTS.maxEncodedBytes, maxStringBytes: overrides?.maxStringBytes ?? DV_LIMIT_DEFAULTS.maxStringBytes, + maxByteStringBytes: + overrides?.maxByteStringBytes ?? DV_LIMIT_DEFAULTS.maxByteStringBytes, maxArrayLength: overrides?.maxArrayLength ?? DV_LIMIT_DEFAULTS.maxArrayLength, maxMapLength: overrides?.maxMapLength ?? DV_LIMIT_DEFAULTS.maxMapLength, diff --git a/libs/quickjs-runtime/src/lib/runtime.ts b/libs/quickjs-runtime/src/lib/runtime.ts index 41509ed..cd5fa38 100644 --- a/libs/quickjs-runtime/src/lib/runtime.ts +++ b/libs/quickjs-runtime/src/lib/runtime.ts @@ -107,8 +107,9 @@ export async function createRuntime( return hostCall(...args); }; - const moduleFactory = (await import(artifact.loaderUrl.href)) - .default as QuickjsWasmModuleFactory; + const moduleFactory = ( + await import(/* @vite-ignore */ artifact.loaderUrl.href) + ).default as QuickjsWasmModuleFactory; const module = await moduleFactory({ host: { host_call: guardedHostCall }, diff --git a/libs/quickjs-runtime/src/lib/source-map-remap.ts b/libs/quickjs-runtime/src/lib/source-map-remap.ts new file mode 100644 index 0000000..49145c7 --- /dev/null +++ b/libs/quickjs-runtime/src/lib/source-map-remap.ts @@ -0,0 +1,133 @@ +import { + TraceMap, + originalPositionFor, + type OriginalMapping, +} from '@jridgewell/trace-mapping'; +import type { ModulePackV1 } from './quickjs-runtime.js'; + +const GENERATED_LOCATION_RE = /(\.{0,2}\/[^\s:()]+\.m?js):(\d+):(\d+)/g; + +interface ParsedSourceMapShape { + version: number; + sources: string[]; + names: string[]; + mappings: string; + [key: string]: unknown; +} + +export interface RemappedStackLocation { + generatedSpecifier: string; + generatedLine: number; + generatedColumn: number; + source: string; + line: number; + column: number; +} + +export interface RemapPayloadResult { + payload: string; + locations: RemappedStackLocation[]; +} + +export function remapModulePackErrorPayload( + payload: string, + modulePack: ModulePackV1, +): RemapPayloadResult { + const traceMapsBySpecifier = buildTraceMapLookup(modulePack); + if (traceMapsBySpecifier.size === 0) { + return { payload, locations: [] }; + } + + const locations: RemappedStackLocation[] = []; + const remappedPayload = payload.replace( + GENERATED_LOCATION_RE, + (match, specifier, lineText, columnText) => { + const generatedLine = Number(lineText); + const generatedColumn = Number(columnText); + if ( + !Number.isInteger(generatedLine) || + !Number.isInteger(generatedColumn) || + generatedLine <= 0 || + generatedColumn <= 0 + ) { + return match; + } + + const traceMap = + traceMapsBySpecifier.get(specifier) ?? + traceMapsBySpecifier.get(normalizeSpecifier(specifier)); + if (!traceMap) { + return match; + } + + const original = resolveOriginalPosition(traceMap, { + line: generatedLine, + column: generatedColumn, + }); + if (!original) { + return match; + } + + locations.push({ + generatedSpecifier: specifier, + generatedLine, + generatedColumn, + source: original.source, + line: original.line, + column: original.column, + }); + + return `${original.source}:${original.line}:${original.column}`; + }, + ); + + return { payload: remappedPayload, locations }; +} + +function buildTraceMapLookup(modulePack: ModulePackV1): Map { + const lookup = new Map(); + for (const module of modulePack.modules) { + if (!module.sourceMap) { + continue; + } + try { + const decodedMap = JSON.parse(module.sourceMap) as ParsedSourceMapShape; + const traceMap = new TraceMap( + decodedMap as unknown as ConstructorParameters[0], + ); + lookup.set(module.specifier, traceMap); + lookup.set(normalizeSpecifier(module.specifier), traceMap); + } catch { + // Ignore malformed source maps; leave payload unchanged. + } + } + return lookup; +} + +function normalizeSpecifier(specifier: string): string { + if (specifier.startsWith('./')) { + return specifier.slice(2); + } + return specifier; +} + +function resolveOriginalPosition( + traceMap: TraceMap, + generated: { line: number; column: number }, +): { source: string; line: number; column: number } | null { + const mapping = originalPositionFor(traceMap, { + line: generated.line, + column: Math.max(0, generated.column - 1), + }) as OriginalMapping | null; + + if (!mapping || mapping.line == null || mapping.column == null) { + return null; + } + + const source = mapping.source ?? ''; + return { + source, + line: mapping.line, + column: mapping.column + 1, + }; +} diff --git a/libs/quickjs-runtime/src/test/baseline-v1/evaluate.spec.ts b/libs/quickjs-runtime/src/test/baseline-v1/evaluate.spec.ts new file mode 100644 index 0000000..ba7633a --- /dev/null +++ b/libs/quickjs-runtime/src/test/baseline-v1/evaluate.spec.ts @@ -0,0 +1,114 @@ +import { + BASE_INPUT, + BASE_PROGRAM, + HOST_V1_MANIFEST, + TEST_GAS_LIMIT, + createHandlers, + evaluate, +} from '../evaluate-test-helpers.js'; + +describe('evaluate baseline-v1', () => { + it('keeps baseline deterministic globals disabled', async () => { + const cases = [ + { + code: `eval('1 + 1')`, + message: /eval is disabled in deterministic mode/i, + }, + { + code: `(new Function('return 7'))()`, + message: /Function is disabled in deterministic mode/i, + }, + { + code: `Math.random()`, + message: /Math\.random is disabled in deterministic mode/i, + }, + { + code: `console.log('x')`, + message: /console is disabled in deterministic mode/i, + }, + { + code: `print('x')`, + message: /print is disabled in deterministic mode/i, + }, + { + code: `new ArrayBuffer(4)`, + message: /ArrayBuffer is disabled in deterministic mode/i, + }, + { + code: `new SharedArrayBuffer(4)`, + message: /SharedArrayBuffer is disabled in deterministic mode/i, + }, + { + code: `new DataView()`, + message: /DataView is disabled in deterministic mode/i, + }, + { + code: `new Uint8Array(4)`, + message: /Typed arrays are disabled in deterministic mode/i, + }, + { + code: `Atomics()`, + message: /Atomics is disabled in deterministic mode/i, + }, + { + code: `WebAssembly()`, + message: /WebAssembly is disabled in deterministic mode/i, + }, + { + code: `new Proxy({}, {})`, + message: /Proxy is disabled in deterministic mode/i, + }, + ]; + for (const testCase of cases) { + const result = await evaluate({ + program: { ...BASE_PROGRAM, code: testCase.code }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + expect(result.ok).toBe(false); + if (result.ok) throw new Error('expected deterministic-disabled failure'); + expect(result.message).toMatch(testCase.message); + } + }); + + it('keeps RegExp disabled in baseline profile', async () => { + const result = await evaluate({ + program: { ...BASE_PROGRAM, code: '/a/.test("a")' }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + expect(result.ok).toBe(false); + if (result.ok) throw new Error('expected baseline regexp failure'); + expect(result.message).toMatch(/regexp is disabled/i); + }); + + it('keeps Promise disabled in baseline profile', async () => { + const result = await evaluate({ + program: { ...BASE_PROGRAM, code: 'Promise.resolve(1)' }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + expect(result.ok).toBe(false); + if (result.ok) throw new Error('expected baseline Promise failure'); + expect(result.message).toMatch(/promise is disabled/i); + }); + + it('keeps sort disabled in baseline', async () => { + const result = await evaluate({ + program: { ...BASE_PROGRAM, code: '[3, 1, 2].sort()' }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + expect(result.ok).toBe(false); + if (result.ok) throw new Error('expected baseline sort failure'); + expect(result.message).toMatch(/sort is disabled/i); + }); +}); diff --git a/libs/quickjs-runtime/src/test/binary-library-reuse.spec.ts b/libs/quickjs-runtime/src/test/binary-library-reuse.spec.ts new file mode 100644 index 0000000..f3a1b63 --- /dev/null +++ b/libs/quickjs-runtime/src/test/binary-library-reuse.spec.ts @@ -0,0 +1,56 @@ +import { bundleDeterministicProgram } from '@blue-quickjs/deterministic-bundler'; +import path from 'node:path'; +import { + BINARY_LIBRARY_FIXTURES, + BINARY_LIBRARY_GAS_LIMIT, + BINARY_LIBRARY_INPUT, + BINARY_LIBRARY_MANIFEST, + BINARY_LIBRARY_PROGRAM_BASE, + createDeterminismHost, +} from '@blue-quickjs/test-harness'; +import { evaluate } from '../lib/evaluate.js'; + +describe('library reuse: binary packages', () => { + for (const fixture of BINARY_LIBRARY_FIXTURES) { + it(`bundles ${fixture.name} deterministically`, async () => { + const workspaceRoot = path.resolve(process.cwd(), '../..'); + const bundled = await bundleDeterministicProgram({ + absWorkingDir: workspaceRoot, + entryPath: fixture.entryPath, + profile: 'compat-binary-v1', + }); + + const run = async () => { + const host = createDeterminismHost(); + return evaluate({ + program: { + ...BINARY_LIBRARY_PROGRAM_BASE, + code: bundled.code, + }, + input: BINARY_LIBRARY_INPUT, + gasLimit: BINARY_LIBRARY_GAS_LIMIT, + manifest: BINARY_LIBRARY_MANIFEST, + handlers: host.handlers, + }); + }; + + const first = await run(); + const second = await run(); + + if (!first.ok || !second.ok) { + const describe = (result: typeof first) => + result.ok + ? 'ok' + : `${result.type}:${result.error.code}:${result.message}`; + throw new Error( + `expected binary fixture runs to succeed: first=${describe(first)} second=${describe(second)}`, + ); + } + + expect(first.value).toEqual(fixture.expectedValue); + expect(second.value).toEqual(fixture.expectedValue); + expect(first.gasUsed).toBe(second.gasUsed); + expect(first.gasRemaining).toBe(second.gasRemaining); + }); + } +}); diff --git a/libs/quickjs-runtime/src/test/chess-library-reuse.spec.ts b/libs/quickjs-runtime/src/test/chess-library-reuse.spec.ts new file mode 100644 index 0000000..dafeafa --- /dev/null +++ b/libs/quickjs-runtime/src/test/chess-library-reuse.spec.ts @@ -0,0 +1,57 @@ +import { bundleDeterministicProgram } from '@blue-quickjs/deterministic-bundler'; +import path from 'node:path'; +import { + CHESS_E2E6_EXPECTED_LEGAL, + CHESS_LIBRARY_ENTRY_PATH, + CHESS_LIBRARY_GAS_LIMIT, + CHESS_LIBRARY_INPUT, + CHESS_LIBRARY_MANIFEST, + CHESS_LIBRARY_PROGRAM_BASE, + createDeterminismHost, +} from '@blue-quickjs/test-harness'; +import { evaluate } from '../lib/evaluate.js'; + +describe('library reuse: chess.js', () => { + it('bundles chess fixture deterministically and evaluates legality for e2e6', async () => { + const workspaceRoot = path.resolve(process.cwd(), '../..'); + const bundled = await bundleDeterministicProgram({ + absWorkingDir: workspaceRoot, + entryPath: CHESS_LIBRARY_ENTRY_PATH, + profile: 'compat-general-v1', + }); + + const run = async () => { + const host = createDeterminismHost(); + const result = await evaluate({ + program: { + ...CHESS_LIBRARY_PROGRAM_BASE, + code: bundled.code, + }, + input: CHESS_LIBRARY_INPUT, + gasLimit: CHESS_LIBRARY_GAS_LIMIT, + manifest: CHESS_LIBRARY_MANIFEST, + handlers: host.handlers, + }); + + return result; + }; + + const first = await run(); + const second = await run(); + + if (!first.ok || !second.ok) { + const describe = (result: typeof first) => + result.ok + ? 'ok' + : `${result.type}:${result.error.code}:${result.message}`; + throw new Error( + `expected chess fixture runs to succeed: first=${describe(first)} second=${describe(second)}`, + ); + } + + expect(first.value).toBe(CHESS_E2E6_EXPECTED_LEGAL); + expect(second.value).toBe(CHESS_E2E6_EXPECTED_LEGAL); + expect(first.gasUsed).toBe(second.gasUsed); + expect(first.gasRemaining).toBe(second.gasRemaining); + }); +}); diff --git a/libs/quickjs-runtime/src/test/common-v1/evaluate.spec.ts b/libs/quickjs-runtime/src/test/common-v1/evaluate.spec.ts new file mode 100644 index 0000000..9fe5792 --- /dev/null +++ b/libs/quickjs-runtime/src/test/common-v1/evaluate.spec.ts @@ -0,0 +1,890 @@ +import { + BASE_INPUT, + BASE_PROGRAM, + BASE_PROGRAM_V2_SCRIPT, + HOST_V1_MANIFEST, + TEST_GAS_LIMIT, + createHandlers, + createModulePack, + createModulePackProgram, + evaluate, + getFnId, + vi, +} from '../evaluate-test-helpers.js'; +import type { HostDispatcherHandlers } from '../../lib/host-dispatcher.js'; + +describe('evaluate common-v1', () => { + it('evaluates raw script mode using final expression result', async () => { + const result = await evaluate({ + program: { ...BASE_PROGRAM, code: 'const n = 2; n + 3' }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + expect(result.ok).toBe(true); + if (!result.ok) throw new Error(result.message); + expect(result.value).toBe(5); + }); + + it('evaluates ProgramArtifact.v2 script source', async () => { + const result = await evaluate({ + program: { + ...BASE_PROGRAM_V2_SCRIPT, + source: { code: 'const n = 10; n + 4;' }, + }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + expect(result.ok).toBe(true); + if (!result.ok) throw new Error(result.message); + expect(result.value).toBe(14); + }); + + it('evaluates ProgramArtifact.v2 module-pack default export', async () => { + const modulePack = createModulePack({ + entrySpecifier: './entry.js', + modules: [{ specifier: './entry.js', source: 'export default 1;\n' }], + }); + const result = await evaluate({ + program: createModulePackProgram(modulePack), + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + expect(result.ok).toBe(true); + if (!result.ok) throw new Error(result.message); + expect(result.value).toBe(1); + }); + + it('evaluates module-pack entryExport for named exports', async () => { + const modulePack = createModulePack({ + entrySpecifier: './entry.js', + entryExport: 'answer', + modules: [ + { specifier: './entry.js', source: 'export const answer = 42;\n' }, + ], + }); + const result = await evaluate({ + program: createModulePackProgram(modulePack), + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + expect(result.ok).toBe(true); + if (!result.ok) throw new Error(result.message); + expect(result.value).toBe(42); + }); + + it('evaluates cyclic module-pack imports deterministically', async () => { + const modulePack = createModulePack({ + entrySpecifier: './entry.js', + modules: [ + { + specifier: './entry.js', + source: + "import { valueFromA } from './b.js'; export default valueFromA;\n", + }, + { + specifier: './a.js', + source: + "import { getB } from './b.js'; export function getA() { return 40 + getB(); }\n", + }, + { + specifier: './b.js', + source: + "import { getA } from './a.js'; export function getB() { return 2; } export const valueFromA = getA();\n", + }, + ], + }); + const result = await evaluate({ + program: createModulePackProgram(modulePack), + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + expect(result.ok).toBe(true); + if (!result.ok) throw new Error(result.message); + expect(result.value).toBe(42); + }); + + it('maps missing entry module to deterministic module-pack error', async () => { + const modulePack = createModulePack({ + entrySpecifier: './missing.js', + modules: [{ specifier: './entry.js', source: 'export default 1;\n' }], + }); + const result = await evaluate({ + program: createModulePackProgram(modulePack), + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + expect(result.ok).toBe(false); + if (result.ok) throw new Error('expected module-pack failure'); + expect(result.type).toBe('vm-error'); + expect(result.error.kind).toBe('module-pack'); + if (result.error.kind !== 'module-pack') + throw new Error('expected module-pack error kind'); + expect(result.error.code).toBe('MODULE_SPECIFIER_NOT_FOUND'); + }); + + it('maps missing module export to deterministic module-pack error', async () => { + const modulePack = createModulePack({ + entrySpecifier: './entry.js', + entryExport: 'missing', + modules: [ + { specifier: './entry.js', source: 'export const value = 1;\n' }, + ], + }); + const result = await evaluate({ + program: createModulePackProgram(modulePack), + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + expect(result.ok).toBe(false); + if (result.ok) throw new Error('expected module-pack failure'); + expect(result.type).toBe('vm-error'); + expect(result.error.kind).toBe('module-pack'); + if (result.error.kind !== 'module-pack') + throw new Error('expected module-pack error kind'); + expect(result.error.code).toBe('MODULE_EXPORT_MISSING'); + }); + + it('rejects module-pack artifacts with graph hash mismatch', async () => { + const modulePack = createModulePack({ + entrySpecifier: './entry.js', + modules: [{ specifier: './entry.js', source: 'export default 1;\n' }], + }); + await expect( + evaluate({ + program: { + ...createModulePackProgram({ + ...modulePack, + graphHash: 'b'.repeat(64), + }), + }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }), + ).rejects.toThrow(/MODULE_PACK_HASH_MISMATCH/); + }); + + it('classifies top-level return as execution surface mismatch', async () => { + const result = await evaluate({ + program: { ...BASE_PROGRAM, code: 'return 1' }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + expect(result.ok).toBe(false); + if (result.ok) throw new Error('expected vm failure'); + expect(result.type).toBe('vm-error'); + expect(result.error.kind).toBe('execution-surface-mismatch'); + expect(result.error.code).toBe('EXECUTION_SURFACE_MISMATCH'); + }); + + it('supports emit side effects in raw script mode', async () => { + const handlers = createHandlers(); + const result = await evaluate({ + program: { + ...BASE_PROGRAM, + code: 'emit({ marker: "raw-script" }); ({ status: "ok" })', + }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers, + }); + expect(result.ok).toBe(true); + if (!result.ok) throw new Error(result.message); + expect(result.value).toEqual({ status: 'ok' }); + expect(handlers.emit).toHaveBeenCalledWith({ marker: 'raw-script' }); + }); + + it('replays identical script evaluations deterministically', async () => { + const handlersA = createHandlers(); + const handlersB = createHandlers(); + const program = { + ...BASE_PROGRAM, + code: 'emit({ marker: "replay" }); ({ ok: true, payload: event.payload.id })', + }; + + const first = await evaluate({ + program, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: handlersA, + tape: {}, + gasTrace: true, + }); + const second = await evaluate({ + program, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: handlersB, + tape: {}, + gasTrace: true, + }); + + expect(first).toEqual(second); + }); + + it('replays identical module-pack evaluations deterministically', async () => { + const modulePack = createModulePack({ + entrySpecifier: './entry.js', + modules: [ + { + specifier: './entry.js', + source: + "Host.v1.emit({ kind: 'module-pack-replay' }); export default { answer: 42 };", + }, + ], + }); + + const run = () => + evaluate({ + program: createModulePackProgram(modulePack), + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + tape: {}, + gasTrace: true, + }); + + const first = await run(); + const second = await run(); + + expect(first).toEqual(second); + }); + + it('installs hardened Host globals and ergonomic wrappers', async () => { + const result = await evaluate({ + program: { + ...BASE_PROGRAM, + code: ` + (() => { + const before = Host; + Host = 123; + const after = Host; + let added = false; + try { + Host.v1.added = 1; + added = Object.prototype.hasOwnProperty.call(Host.v1, 'added'); + } catch (_) { + added = false; + } + const desc = Object.getOwnPropertyDescriptor(globalThis, 'Host'); + return { + configurable: desc ? desc.configurable : null, + enumerable: desc ? desc.enumerable : null, + writable: desc ? desc.writable : null, + sameRef: before === after, + hostType: typeof Host, + hostNullProto: Object.getPrototypeOf(Host) === null, + v1Type: typeof Host.v1, + v1NullProto: Object.getPrototypeOf(Host.v1) === null, + hostIsExtensible: Object.isExtensible(Host), + hostV1Extensible: Object.isExtensible(Host.v1), + added, + documentType: typeof document, + emitType: typeof emit + }; + })() + `, + }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + expect(result.ok).toBe(true); + if (!result.ok) throw new Error(result.message); + expect(result.value).toEqual({ + configurable: false, + enumerable: false, + writable: false, + sameRef: true, + hostType: 'object', + hostNullProto: true, + v1Type: 'object', + v1NullProto: true, + hostIsExtensible: false, + hostV1Extensible: false, + added: false, + documentType: 'function', + emitType: 'function', + }); + }); + + it('supports canon.at JSON Pointer lookups and canon.unwrap shallow vs deep', async () => { + const result = await evaluate({ + program: { + ...BASE_PROGRAM, + code: ` + (() => { + const deep = canon.unwrap(currentContractCanonical); + const shallow = canon.unwrap(currentContractCanonical, false); + return { + payloadId: canon.at(event, '/payload/id'), + stepName: canon.at(steps, '/0/name'), + missingIsUndefined: typeof canon.at(event, '/payload/missing') === 'undefined', + deep, + shallow, + deepRootFrozen: Object.isFrozen(deep), + deepIdFrozen: Object.isFrozen(deep.id), + shallowRootFrozen: Object.isFrozen(shallow), + shallowIdFrozen: Object.isFrozen(shallow.id) + }; + })() + `, + }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + expect(result.ok).toBe(true); + if (!result.ok) throw new Error(result.message); + expect(result.value).toEqual({ + payloadId: 1, + stepName: 'first', + missingIsUndefined: true, + deep: { id: 'contract-1' }, + shallow: { id: { value: 'contract-1' } }, + deepRootFrozen: true, + deepIdFrozen: true, + shallowRootFrozen: true, + shallowIdFrozen: false, + }); + }); + + it('rejects invalid canon.at pointer forms deterministically', async () => { + const cases = [ + { + code: `canon.at(event, ['payload', 'id'])`, + message: /JSON Pointer string \(array paths are no longer supported\)/i, + }, + { + code: `canon.at(event, '#/payload/id')`, + message: /fragment form is not supported/i, + }, + { + code: `canon.at(steps, '/-')`, + message: /path index '-' is not allowed/i, + }, + ]; + for (const testCase of cases) { + const result = await evaluate({ + program: { ...BASE_PROGRAM, code: testCase.code }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + expect(result.ok).toBe(false); + if (result.ok) throw new Error('expected canon.at failure'); + expect(result.type).toBe('vm-error'); + expect(result.error.kind).toBe('js-exception'); + expect(result.message).toMatch(testCase.message); + } + }); + + it('returns DV results with gas accounting', async () => { + const handlers = createHandlers(); + const result = await evaluate({ + program: BASE_PROGRAM, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers, + }); + expect(result.ok).toBe(true); + if (!result.ok) throw new Error(result.message); + expect(result.value).toEqual({ path: 'path/to/doc' }); + expect(handlers.document.get).toHaveBeenCalledTimes(1); + }); + + it('maps VM errors to a structured failure', async () => { + const result = await evaluate({ + program: { ...BASE_PROGRAM, code: 'document(123)' }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + expect(result.ok).toBe(false); + if (result.ok) throw new Error('expected VM failure'); + expect(result.type).toBe('vm-error'); + expect(result.error.kind).toBe('js-exception'); + }); + + it('rejects unsupported return types at the VM boundary', async () => { + for (const code of ['undefined', '(() => {})', 'Symbol("x")', '1n']) { + const result = await evaluate({ + program: { ...BASE_PROGRAM, code }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + expect(result.ok).toBe(false); + if (result.ok) throw new Error('expected VM failure'); + expect(result.type).toBe('vm-error'); + expect(result.error.kind).toBe('js-exception'); + } + }); + + it('includes human-readable DV tag names in unsupported output errors', async () => { + const result = await evaluate({ + program: { ...BASE_PROGRAM, code: 'Symbol("x")' }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + expect(result.ok).toBe(false); + if (result.ok) throw new Error('expected unsupported DV type failure'); + expect(result.message).toMatch(/unsupported DV type: symbol/i); + }); + + it('applies output DV limits to returned payloads', async () => { + const result = await evaluate({ + program: { ...BASE_PROGRAM, code: '"hello world"' }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + outputDvLimits: { maxEncodedBytes: 4 }, + }); + expect(result.ok).toBe(false); + if (result.ok) throw new Error('expected invalid output'); + expect(result.type).toBe('invalid-output'); + }); + + it('maps HostError failures to code/tag using the manifest', async () => { + const handlers = createHandlers({ + document: { + get: vi.fn(() => ({ + err: { code: 'NOT_FOUND', tag: 'host/not_found' }, + units: 2, + })), + }, + }); + const result = await evaluate({ + program: BASE_PROGRAM, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers, + }); + expect(result.ok).toBe(false); + if (result.ok) throw new Error('expected host error'); + expect(result.type).toBe('vm-error'); + expect(result.error.kind).toBe('host-error'); + if (result.error.kind !== 'host-error') + throw new Error('expected host-error'); + expect(result.error.code).toBe('NOT_FOUND'); + }); + + it('maps host transport failures to a stable code/tag', async () => { + const handlers = createHandlers({ + document: { + get: vi.fn( + () => + ({ + ok: { path: 'path/to/doc' }, + }) as unknown as ReturnType< + HostDispatcherHandlers['document']['get'] + >, + ), + }, + }); + const result = await evaluate({ + program: BASE_PROGRAM, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers, + }); + expect(result.ok).toBe(false); + if (result.ok) throw new Error('expected host transport error'); + expect(result.type).toBe('vm-error'); + expect(result.error.kind).toBe('host-error'); + if (result.error.kind !== 'host-error') + throw new Error('expected host-error'); + expect(result.error.code).toBe('HOST_TRANSPORT'); + }); + + it('surfaces OutOfGas as a stable code/tag', async () => { + const result = await evaluate({ + program: { ...BASE_PROGRAM, code: 'let n = 0; while (true) { n += 1; }' }, + input: BASE_INPUT, + gasLimit: 50n, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + expect(result.ok).toBe(false); + if (result.ok) throw new Error('expected OOG'); + expect(result.type).toBe('vm-error'); + expect(result.error.kind).toBe('out-of-gas'); + }); + + it('rejects engine build hash mismatches', async () => { + await expect( + evaluate({ + program: { ...BASE_PROGRAM, engineBuildHash: '0'.repeat(64) }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }), + ).rejects.toThrow(/enginebuildhash/i); + }); + + it('rejects gasVersion mismatches', async () => { + await expect( + evaluate({ + program: { ...BASE_PROGRAM, gasVersion: 0 }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }), + ).rejects.toThrow(/gasversion/i); + }); + + it('requires engine/gas/profile pins in release mode', async () => { + await expect( + evaluate({ + program: BASE_PROGRAM, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + releaseMode: true, + }), + ).rejects.toThrow(/release-mode requires/i); + }); + + it('requires expectedExecutionProfile in release mode', async () => { + await expect( + evaluate({ + program: { + ...BASE_PROGRAM, + engineBuildHash: '0'.repeat(64), + gasVersion: 0, + executionProfile: 'baseline-v1', + }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + releaseMode: true, + }), + ).rejects.toThrow(/expectedexecutionprofile/i); + }); + + it('rejects executionProfile pin mismatches when expected profile is provided', async () => { + await expect( + evaluate({ + program: { ...BASE_PROGRAM, executionProfile: 'baseline-v1' }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + expectedExecutionProfile: 'compat-general-v1', + }), + ).rejects.toThrow(/executionprofile mismatch/i); + }); + + it('accepts matching expected executionProfile pin', async () => { + const result = await evaluate({ + program: { ...BASE_PROGRAM, executionProfile: 'baseline-v1' }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + expectedExecutionProfile: 'baseline-v1', + }); + expect(result.ok).toBe(true); + }); + + it('returns host-call tape when requested', async () => { + const result = await evaluate({ + program: BASE_PROGRAM, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + tape: { capacity: 8 }, + }); + expect(result.ok).toBe(true); + if (!result.ok) throw new Error(result.message); + const [record] = result.tape ?? []; + expect(record.fnId).toBe(getFnId('document.get')); + }); + + it('returns gas charge tape when requested', async () => { + const result = await evaluate({ + program: { ...BASE_PROGRAM, code: '1 + 2' }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + gasChargeTape: { capacity: 128 }, + }); + expect(result.ok).toBe(true); + if (!result.ok) throw new Error(result.message); + expect((result.gasChargeTape ?? []).length).toBeGreaterThan(0); + }); + + it('tags gas charge tape events for host calls and deterministic JSON', async () => { + const hostResult = await evaluate({ + program: BASE_PROGRAM, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + gasChargeTape: { capacity: 256 }, + }); + expect(hostResult.ok).toBe(true); + if (!hostResult.ok) throw new Error(hostResult.message); + const hostSiteIds = new Set( + (hostResult.gasChargeTape ?? []).map((r) => r.siteId), + ); + expect(hostSiteIds.has(2001)).toBe(true); + expect(hostSiteIds.has(2002)).toBe(true); + }); + + it('returns gas trace when requested', async () => { + const result = await evaluate({ + program: { ...BASE_PROGRAM, code: '1 + 2' }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + gasTrace: true, + }); + expect(result.ok).toBe(true); + if (!result.ok) throw new Error(result.message); + expect((result.gasTrace?.opcodeCount ?? 0n) >= 0n).toBe(true); + }); + + it('tracks host-call gas in the gas trace', async () => { + const result = await evaluate({ + program: BASE_PROGRAM, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + gasTrace: true, + }); + expect(result.ok).toBe(true); + if (!result.ok) throw new Error(result.message); + expect(result.gasTrace?.hostCallPreCount).toBe(1n); + expect(result.gasTrace?.hostCallPostCount).toBe(1n); + }); + + it('supports deterministic JSON parse and canonical stringify', async () => { + const result = await evaluate({ + program: { + ...BASE_PROGRAM, + code: `JSON.stringify(JSON.parse('{"aa":1,"b":2}'))`, + }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + gasTrace: true, + }); + expect(result.ok).toBe(true); + if (!result.ok) throw new Error(result.message); + expect(result.value).toBe('{"b":2,"aa":1}'); + }); + + it('rejects unsupported deterministic JSON options', async () => { + const cases = [ + { + code: `JSON.parse('[]', () => 1)`, + message: /reviver is not supported/i, + }, + { + code: `JSON.stringify({ aa: 1, b: 2 }, [])`, + message: /replacer is not supported/i, + }, + { + code: `JSON.stringify({ aa: 1, b: 2 }, null, 2)`, + message: /space is not supported/i, + }, + ]; + for (const testCase of cases) { + const result = await evaluate({ + program: { ...BASE_PROGRAM, code: testCase.code }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + expect(result.ok).toBe(false); + if (result.ok) + throw new Error('expected deterministic JSON option failure'); + expect(result.message).toMatch(testCase.message); + } + }); + + it('rejects malformed deterministic JSON strings and keys', async () => { + const cases = [ + { + code: `JSON.parse('"\\ud800"')`, + message: /string contains lone surrogate code points/i, + }, + { + code: `JSON.parse('{"\\ud800":1}')`, + message: /key contains lone surrogate code points/i, + }, + { + code: `JSON.stringify('\\ud800')`, + message: /string contains lone surrogate code points/i, + }, + { + code: `(() => { const key = '\\ud800'; return JSON.stringify({ [key]: 1 }); })()`, + message: /key contains lone surrogate code points/i, + }, + ]; + for (const testCase of cases) { + const result = await evaluate({ + program: { ...BASE_PROGRAM, code: testCase.code }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + expect(result.ok).toBe(false); + if (result.ok) + throw new Error('expected malformed deterministic JSON failure'); + expect(result.message).toMatch(testCase.message); + } + }); + + it('rejects deeply nested deterministic JSON before parser stack overflow', async () => { + const depth = 10_000; + const json = '['.repeat(depth) + '0' + ']'.repeat(depth); + const result = await evaluate({ + program: { ...BASE_PROGRAM, code: `JSON.parse(${JSON.stringify(json)})` }, + input: BASE_INPUT, + gasLimit: 200_000n, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + expect(result.ok).toBe(false); + if (result.ok) throw new Error('expected deterministic JSON depth failure'); + expect(result.message).toMatch(/maxDepth 64 exceeded/i); + }); + + it('rejects oversized deterministic JSON arrays before building the full parse result', async () => { + const length = 66_000; + const json = '[' + '0,'.repeat(length - 1) + '0]'; + const result = await evaluate({ + program: { ...BASE_PROGRAM, code: `JSON.parse(${JSON.stringify(json)})` }, + input: BASE_INPUT, + gasLimit: 2_000_000n, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + gasTrace: true, + }); + expect(result.ok).toBe(false); + if (result.ok) + throw new Error('expected deterministic JSON array length failure'); + expect(result.message).toMatch(/array length exceeds maxArrayLength/i); + }); + + it('rejects oversized deterministic JSON strings before materializing full tokens', async () => { + const cases = [ + { + code: `JSON.parse('"' + 'a'.repeat(262_145) + '"')`, + message: /string exceeds maxStringBytes/i, + }, + { + code: `JSON.parse('{"' + 'a'.repeat(262_145) + '":1}')`, + message: /key exceeds maxStringBytes/i, + }, + ]; + for (const testCase of cases) { + const result = await evaluate({ + program: { ...BASE_PROGRAM, code: testCase.code }, + input: BASE_INPUT, + gasLimit: 2_000_000n, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + gasTrace: true, + }); + expect(result.ok).toBe(false); + if (result.ok) + throw new Error('expected deterministic JSON string length failure'); + expect(result.message).toMatch(testCase.message); + } + }); + + it('rejects accessor properties during deterministic JSON stringify', async () => { + const cases = [ + { + code: `JSON.stringify({ get a() { return 1; } })`, + message: /accessor properties/i, + }, + { + code: `(() => { const arr = [1]; Object.defineProperty(arr, 0, { get() { return 1; }, enumerable: true }); return JSON.stringify(arr); })()`, + message: /accessor properties/i, + }, + ]; + for (const testCase of cases) { + const result = await evaluate({ + program: { ...BASE_PROGRAM, code: testCase.code }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + expect(result.ok).toBe(false); + if (result.ok) + throw new Error('expected deterministic JSON accessor failure'); + expect(result.message).toMatch(testCase.message); + } + }); + + it('serializes sparse arrays without consulting the prototype chain', async () => { + const result = await evaluate({ + program: { + ...BASE_PROGRAM, + code: `(() => { + let getterCalls = 0; + Object.defineProperty(Array.prototype, 0, { + get() { getterCalls += 1; return 1; }, + configurable: true, + }); + try { return [JSON.stringify([,]), getterCalls]; } finally { delete Array.prototype[0]; } + })()`, + }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + expect(result.ok).toBe(true); + if (!result.ok) throw new Error(result.message); + expect(result.value).toEqual(['[null]', 0]); + }); +}); diff --git a/libs/quickjs-runtime/src/test/compat-binary-v1/evaluate.spec.ts b/libs/quickjs-runtime/src/test/compat-binary-v1/evaluate.spec.ts new file mode 100644 index 0000000..34a94fa --- /dev/null +++ b/libs/quickjs-runtime/src/test/compat-binary-v1/evaluate.spec.ts @@ -0,0 +1,66 @@ +import { + BASE_INPUT, + BASE_PROGRAM_V2_BINARY, + HOST_V2_MANIFEST, + TEST_GAS_LIMIT, + createHandlers, + evaluate, + vi, +} from '../evaluate-test-helpers.js'; + +describe('evaluate compat-binary-v1', () => { + it('supports Host.v2 DV2 byte roundtrips', async () => { + const handlers = createHandlers({ + document: { + get: vi.fn((path: string) => { + if (path !== 'bytes/payload') { + return { + err: { code: 'NOT_FOUND', tag: 'host/not_found' }, + units: 1, + }; + } + return { ok: Uint8Array.from([222, 173, 190, 239]), units: 2 }; + }), + }, + emit: vi.fn(() => ({ ok: null, units: 1 })), + }); + const compat = await evaluate({ + program: { + ...BASE_PROGRAM_V2_BINARY, + code: `(() => { const payload = Host.v2.document.get('bytes/payload'); Host.v2.emit(payload); return 1; })()`, + }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V2_MANIFEST, + handlers, + }); + expect(compat.ok).toBe(true); + if (!compat.ok) throw new Error(compat.message); + expect(compat.value).toBe(1); + }); + + it('preserves Host.v2 byte-string slice boundaries', async () => { + const handlers = createHandlers({ + document: { + get: vi.fn(() => { + const backing = Uint8Array.from([0, 0xde, 0xad, 0, 0]); + return { ok: backing.subarray(1, 3), units: 2 }; + }), + }, + emit: vi.fn(() => ({ ok: null, units: 1 })), + }); + const compat = await evaluate({ + program: { + ...BASE_PROGRAM_V2_BINARY, + code: `(() => { const payload = Host.v2.document.get('bytes/payload'); return [payload.byteLength, payload[0], payload[1]]; })()`, + }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V2_MANIFEST, + handlers, + }); + expect(compat.ok).toBe(true); + if (!compat.ok) throw new Error(compat.message); + expect(compat.value).toEqual([2, 222, 173]); + }); +}); diff --git a/libs/quickjs-runtime/src/test/compat-general-v1/evaluate.spec.ts b/libs/quickjs-runtime/src/test/compat-general-v1/evaluate.spec.ts new file mode 100644 index 0000000..84c2e6e --- /dev/null +++ b/libs/quickjs-runtime/src/test/compat-general-v1/evaluate.spec.ts @@ -0,0 +1,160 @@ +import { + BASE_INPUT, + BASE_PROGRAM, + HOST_V1_MANIFEST, + TEST_GAS_LIMIT, + createHandlers, + evaluate, + vi, +} from '../evaluate-test-helpers.js'; + +describe('evaluate compat-general-v1', () => { + it('enables RegExp', async () => { + const compat = await evaluate({ + program: { + ...BASE_PROGRAM, + code: '/a/.test("a")', + executionProfile: 'compat-general-v1', + }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + expect(compat.ok).toBe(true); + if (!compat.ok) throw new Error(compat.message); + expect(compat.value).toBe(true); + }); + + it('drains Promise jobs', async () => { + const compat = await evaluate({ + program: { + ...BASE_PROGRAM, + code: 'Promise.resolve(41).then((value) => value + 1)', + executionProfile: 'compat-general-v1', + }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + expect(compat.ok).toBe(true); + if (!compat.ok) throw new Error(compat.message); + expect(compat.value).toBe(42); + }); + + it('runs queueMicrotask deterministically', async () => { + const compat = await evaluate({ + program: { + ...BASE_PROGRAM, + code: `(() => { const events = []; queueMicrotask(() => events.push('first')); queueMicrotask(() => events.push('second')); return Promise.resolve().then(() => events.join(',')); })()`, + executionProfile: 'compat-general-v1', + }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + expect(compat.ok).toBe(true); + if (!compat.ok) throw new Error(compat.message); + expect(compat.value).toBe('first,second'); + }); + + it('validates queueMicrotask callbacks', async () => { + const compat = await evaluate({ + program: { + ...BASE_PROGRAM, + code: 'queueMicrotask(123)', + executionProfile: 'compat-general-v1', + }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + expect(compat.ok).toBe(false); + if (compat.ok) + throw new Error('expected queueMicrotask validation failure'); + expect(compat.message).toMatch(/queueMicrotask callback must be callable/i); + }); + + it('routes compat-general console shim calls through Host.v1.emit', async () => { + const handlers = createHandlers(); + const compat = await evaluate({ + program: { + ...BASE_PROGRAM, + code: `(() => { console.log('hello', 7); return null; })()`, + executionProfile: 'compat-general-v1', + }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers, + }); + expect(compat.ok).toBe(true); + if (!compat.ok) throw new Error(compat.message); + expect(handlers.emit).toHaveBeenCalledWith({ + type: 'console', + level: 'log', + args: ['hello', 7], + }); + }); + + it('routes all compat console levels through Host emit', async () => { + const handlers = createHandlers(); + const compat = await evaluate({ + program: { + ...BASE_PROGRAM, + code: `(() => { console.info('i'); console.warn('w'); console.error('e'); console.debug('d'); return null; })()`, + executionProfile: 'compat-general-v1', + }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers, + }); + expect(compat.ok).toBe(true); + if (!compat.ok) throw new Error(compat.message); + const emitMock = handlers.emit as ReturnType; + expect(emitMock.mock.calls).toEqual([ + [{ type: 'console', level: 'info', args: ['i'] }], + [{ type: 'console', level: 'warn', args: ['w'] }], + [{ type: 'console', level: 'error', args: ['e'] }], + [{ type: 'console', level: 'debug', args: ['d'] }], + ]); + }); + + it('enables stable sort', async () => { + const compat = await evaluate({ + program: { + ...BASE_PROGRAM, + code: `(() => { const records = [{ id: 'a', group: 1 }, { id: 'b', group: 1 }, { id: 'c', group: 2 }, { id: 'd', group: 1 }]; records.sort((left, right) => left.group - right.group); return records.map((record) => record.id).join(','); })()`, + executionProfile: 'compat-general-v1', + }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + expect(compat.ok).toBe(true); + if (!compat.ok) throw new Error(compat.message); + expect(compat.value).toBe('a,b,d,c'); + }); + + it('validates stable sort compare functions', async () => { + const compat = await evaluate({ + program: { + ...BASE_PROGRAM, + code: '[3, 1, 2].sort(123)', + executionProfile: 'compat-general-v1', + }, + input: BASE_INPUT, + gasLimit: TEST_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + expect(compat.ok).toBe(false); + if (compat.ok) throw new Error('expected sort compareFunction failure'); + expect(compat.message).toMatch(/compareFunction must be a function/i); + }); +}); diff --git a/libs/quickjs-runtime/src/test/deterministic-init.spec.ts b/libs/quickjs-runtime/src/test/deterministic-init.spec.ts new file mode 100644 index 0000000..07760ce --- /dev/null +++ b/libs/quickjs-runtime/src/test/deterministic-init.spec.ts @@ -0,0 +1,455 @@ +import { decodeDv, encodeDv } from '@blue-quickjs/dv'; +import { + HOST_V1_BYTES_HEX, + HOST_V1_HASH, + HOST_V1_MANIFEST, +} from '@blue-quickjs/abi-manifest'; +import { initializeDeterministicVm } from '../lib/deterministic-init.js'; +import type { HostDispatcherHandlers } from '../lib/host-dispatcher.js'; +import { parseHexToBytes } from '../lib/hex-utils.js'; +import { createRuntime } from '../lib/runtime.js'; +import type { InputEnvelope, ProgramArtifact } from '../lib/quickjs-runtime.js'; +import { writeBytes, writeCString } from '@blue-quickjs/test-harness'; + +const BASE_PROGRAM: ProgramArtifact = { + code: 'export default 1;', + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, +}; +const TEST_GAS_LIMIT = 10_000n; + +const BASE_INPUT: InputEnvelope = { + event: { type: 'create', payload: { id: 1 } }, + eventCanonical: { type: 'create', payload: { id: 1 } }, + steps: [{ name: 'first' }], + currentContract: { id: 'contract-1', kind: 'workflow' }, + currentContractCanonical: { id: { value: 'contract-1' }, kind: 'workflow' }, +}; + +describe('initializeDeterministicVm', () => { + it('installs ergonomic globals and freezes injected values', async () => { + const runtime = await createRuntime({ + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + + const vm = initializeDeterministicVm( + runtime, + BASE_PROGRAM, + BASE_INPUT, + TEST_GAS_LIMIT, + ); + try { + const output = vm.eval(` + (() => { + const docResult = document("path/to/doc"); + return { + docType: typeof document, + docCanonicalType: typeof document.canonical, + documentExtensible: Object.isExtensible(document), + canonExtensible: Object.isExtensible(canon), + eventFrozen: Object.isFrozen(event), + stepsFrozen: Object.isFrozen(steps), + currentContractFrozen: Object.isFrozen(currentContract), + currentContractCanonicalFrozen: Object.isFrozen(currentContractCanonical), + currentContract, + currentContractCanonical, + docResult + }; + })() + `); + + const parsed = parseEvalOutput(output); + if (parsed.kind === 'ERROR') { + throw new Error(`eval failed: ${parsed.message}`); + } + expect(parsed.kind).toBe('RESULT'); + expect(parsed.value).toMatchObject({ + docType: 'function', + docCanonicalType: 'function', + documentExtensible: false, + canonExtensible: false, + eventFrozen: true, + stepsFrozen: true, + currentContractFrozen: true, + currentContractCanonicalFrozen: true, + currentContract: { id: 'contract-1', kind: 'workflow' }, + currentContractCanonical: { + id: { value: 'contract-1' }, + kind: 'workflow', + }, + docResult: { path: 'path/to/doc' }, + }); + } finally { + vm.dispose(); + } + }); + + it('fails when the provided manifest hash does not match the bytes', async () => { + const runtime = await createRuntime({ + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + const badProgram: ProgramArtifact = { + ...BASE_PROGRAM, + abiManifestHash: '0'.repeat(64), + }; + + expect(() => + initializeDeterministicVm( + runtime, + badProgram, + BASE_INPUT, + TEST_GAS_LIMIT, + ), + ).toThrow(/manifest hash/i); + }); + + it('rejects numeric gas limits above the uint64 range', async () => { + const runtime = await createRuntime({ + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + const tooLargeGasLimit = 2 ** 64; + + expect(() => + initializeDeterministicVm( + runtime, + BASE_PROGRAM, + BASE_INPUT, + tooLargeGasLimit, + ), + ).toThrow(/uint64 range/i); + + const vm = initializeDeterministicVm( + runtime, + BASE_PROGRAM, + BASE_INPUT, + TEST_GAS_LIMIT, + ); + try { + expect(() => vm.setGasLimit(tooLargeGasLimit)).toThrow(/uint64 range/i); + } finally { + vm.dispose(); + } + }); + + it('resets gas trace counts when gas tracing is re-enabled on the same VM', async () => { + const runtime = await createRuntime({ + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + + const vm = initializeDeterministicVm( + runtime, + BASE_PROGRAM, + BASE_INPUT, + TEST_GAS_LIMIT, + ); + + try { + vm.enableGasTrace(true); + vm.eval('1 + 2'); + const firstTrace = parseGasTrace(vm.readGasTrace()); + + vm.eval('1 + 2'); + const accumulatedTrace = parseGasTrace(vm.readGasTrace()); + + vm.enableGasTrace(true); + vm.eval('1 + 2'); + const resetTrace = parseGasTrace(vm.readGasTrace()); + + expect(firstTrace.opcodeCount > 0n).toBe(true); + expect(accumulatedTrace.opcodeCount).toBe(firstTrace.opcodeCount * 2n); + expect(resetTrace.opcodeCount).toBe(firstTrace.opcodeCount); + } finally { + vm.dispose(); + } + }); + + it('cleans up loaded modules between repeated module-pack evaluations', async () => { + const runtime = await createRuntime({ + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + + const vm = initializeDeterministicVm( + runtime, + BASE_PROGRAM, + BASE_INPUT, + TEST_GAS_LIMIT, + ); + + try { + const first = parseEvalOutput( + vm.evalModulePack( + JSON.stringify([ + { + specifier: './entry.js', + source: 'export default 1;\n', + }, + ]), + './entry.js', + 'default', + ), + ); + const second = parseEvalOutput( + vm.evalModulePack( + JSON.stringify([ + { + specifier: './entry.js', + source: 'export default 2;\n', + }, + ]), + './entry.js', + 'default', + ), + ); + + expect(first.kind).toBe('RESULT'); + expect(second.kind).toBe('RESULT'); + expect(first.value).toBe(1); + expect(second.value).toBe(2); + } finally { + vm.dispose(); + } + }); + + it('defaults missing context blob keys to null', async () => { + const runtime = await createRuntime({ + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + + runDeterministicInit(runtime, { + manifestBytes: parseHexToBytes(HOST_V1_BYTES_HEX), + manifestHash: HOST_V1_HASH, + contextBlob: { event: { only: 'event' } }, + gasLimit: TEST_GAS_LIMIT, + }); + + try { + const ptr = callEval( + runtime, + '(() => ({ event, eventCanonical, steps, currentContract, currentContractCanonical }))()', + ); + const parsed = parseEvalOutput(readAndFreeCString(runtime.module, ptr)); + expect(parsed.kind).toBe('RESULT'); + expect(parsed.value).toEqual({ + event: { only: 'event' }, + eventCanonical: null, + steps: null, + currentContract: null, + currentContractCanonical: null, + }); + } finally { + runtime.module.cwrap('qjs_det_free', null, [])(); + } + }); + + it('rejects manifest bytes larger than 1 MiB', async () => { + const runtime = await createRuntime({ + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + + expect(() => + runDeterministicInit(runtime, { + manifestBytes: new Uint8Array(1024 * 1024 + 1), + manifestHash: '0'.repeat(64), + contextBlob: null, + gasLimit: TEST_GAS_LIMIT, + }), + ).toThrow(/manifest/i); + }); + + it('rejects context blobs larger than 5 MiB', async () => { + const runtime = await createRuntime({ + manifest: HOST_V1_MANIFEST, + handlers: createHandlers(), + }); + + const oversized = new Uint8Array(5 * 1024 * 1024 + 1); + oversized.fill(0x61); + + expect(() => + runDeterministicInit(runtime, { + manifestBytes: parseHexToBytes(HOST_V1_BYTES_HEX), + manifestHash: HOST_V1_HASH, + contextBlob: null, + contextBlobBytes: oversized, + gasLimit: TEST_GAS_LIMIT, + }), + ).toThrow(/context blob|blob/i); + }); +}); + +function createHandlers( + overrides?: Partial, +): HostDispatcherHandlers { + return { + document: { + get: + overrides?.document?.get ?? + ((path: string) => ({ ok: { path }, units: 5 })), + getCanonical: + overrides?.document?.getCanonical ?? + ((path: string) => ({ ok: { canonical: path }, units: 3 })), + }, + emit: + overrides?.emit ?? + (() => ({ + ok: null, + units: 1, + })), + }; +} + +function parseEvalOutput(raw: string): { + kind: 'RESULT' | 'ERROR'; + message: string; + value: unknown; + gasRemaining: number; + gasUsed: number; +} { + const match = + /^(RESULT|ERROR)\s+(.+?)\s+GAS\s+remaining=(\d+)\s+used=(\d+)/.exec( + raw.trim(), + ); + if (!match) { + throw new Error(`Unable to parse eval output: ${raw}`); + } + + const [, kind, payload, remaining, used] = match; + const value = + kind === 'RESULT' ? decodeDv(parseHexToBytes(payload)) : payload.trim(); + + return { + kind: kind as 'RESULT' | 'ERROR', + message: payload, + value, + gasRemaining: Number(remaining), + gasUsed: Number(used), + }; +} + +function runDeterministicInit( + runtime: Awaited>, + options: { + manifestBytes: Uint8Array; + manifestHash: string; + contextBlob: unknown | null; + contextBlobBytes?: Uint8Array; + gasLimit: bigint; + }, +): string { + const init = runtime.module.cwrap('qjs_det_init', 'number', [ + 'number', + 'number', + 'number', + 'number', + 'number', + 'bigint', + 'number', + ]) as ( + manifestPtr: number, + manifestLength: number, + hashPtr: number, + contextPtr: number, + contextLength: number, + gasLimit: bigint, + featureFlags: number, + ) => number; + + const manifestPtr = Number( + writeBytes( + runtime.module, + runtime.module._malloc.bind(runtime.module), + options.manifestBytes, + ), + ); + const hashPtr = Number( + writeCString( + runtime.module, + runtime.module._malloc.bind(runtime.module), + options.manifestHash, + ), + ); + const contextBytes = + options.contextBlobBytes ?? + (options.contextBlob === null + ? new Uint8Array() + : encodeDv(options.contextBlob)); + const contextPtr = + contextBytes.length > 0 + ? Number( + writeBytes( + runtime.module, + runtime.module._malloc.bind(runtime.module), + contextBytes, + ), + ) + : 0; + + try { + const errorPtr = init( + manifestPtr, + options.manifestBytes.length, + hashPtr, + contextPtr, + contextBytes.length, + options.gasLimit, + 0, + ); + if (errorPtr !== 0) { + throw new Error(readAndFreeCString(runtime.module, errorPtr)); + } + return 'ok'; + } finally { + runtime.module._free(manifestPtr); + runtime.module._free(hashPtr); + if (contextPtr !== 0) { + runtime.module._free(contextPtr); + } + } +} + +function callEval( + runtime: Awaited>, + code: string, +): number { + const evalFn = runtime.module.cwrap('qjs_det_eval', 'number', ['string']) as ( + source: string, + ) => number; + return evalFn(code); +} + +function readAndFreeCString( + module: Awaited>['module'], + ptr: number, +): string { + const value = module.UTF8ToString(ptr); + module._free(ptr); + return value; +} + +function parseGasTrace(raw: string): { + opcodeCount: bigint; + allocationCount: bigint; +} { + const trace = JSON.parse(raw) as { + opcodeCount?: string; + allocationCount?: string; + }; + if ( + typeof trace.opcodeCount !== 'string' || + typeof trace.allocationCount !== 'string' + ) { + throw new Error(`Unable to parse gas trace: ${raw}`); + } + return { + opcodeCount: BigInt(trace.opcodeCount), + allocationCount: BigInt(trace.allocationCount), + }; +} diff --git a/libs/quickjs-runtime/src/test/evaluate-test-helpers.ts b/libs/quickjs-runtime/src/test/evaluate-test-helpers.ts new file mode 100644 index 0000000..ba57412 --- /dev/null +++ b/libs/quickjs-runtime/src/test/evaluate-test-helpers.ts @@ -0,0 +1,174 @@ +import { + HOST_V1_HASH, + HOST_V1_MANIFEST, + HOST_V2_HASH, + HOST_V2_MANIFEST, +} from '@blue-quickjs/abi-manifest'; +import { createHash } from 'node:crypto'; +import { vi } from 'vitest'; +import { evaluate } from '../lib/evaluate.js'; +import type { HostDispatcherHandlers } from '../lib/host-dispatcher.js'; +import type { + InputEnvelope, + ProgramArtifact, + ProgramArtifactV2, +} from '../lib/quickjs-runtime.js'; + +export { evaluate, vi, HOST_V1_MANIFEST, HOST_V2_MANIFEST }; + +export const TEST_GAS_LIMIT = 50_000n; + +export const BASE_PROGRAM: ProgramArtifact = { + code: 'document("path/to/doc")', + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, +}; + +export const BASE_PROGRAM_V2_SCRIPT: ProgramArtifactV2 = { + version: 2, + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + executionProfile: 'baseline-v1', + sourceKind: 'script', + source: { + code: 'document("path/to/doc")', + }, +}; + +export const BASE_PROGRAM_V2_BINARY: ProgramArtifact = { + code: 'Host.v2.document.get("bytes/payload").byteLength', + abiId: 'Host.v2', + abiVersion: 2, + abiManifestHash: HOST_V2_HASH, + executionProfile: 'compat-binary-v1', +}; + +export const BASE_INPUT: InputEnvelope = { + event: { type: 'create', payload: { id: 1 } }, + eventCanonical: { type: 'create', payload: { id: 1 } }, + steps: [{ name: 'first' }], + currentContract: { id: 'contract-1' }, + currentContractCanonical: { id: { value: 'contract-1' } }, +}; + +export function createModulePackProgram( + modulePack: ReturnType, +): ProgramArtifactV2 { + return { + ...BASE_PROGRAM_V2_SCRIPT, + sourceKind: 'module-pack', + source: { + modulePack, + }, + }; +} + +export function createHandlers( + overrides?: Partial<{ + document: Partial; + emit: HostDispatcherHandlers['emit']; + }>, +): HostDispatcherHandlers { + return { + document: { + get: + overrides?.document?.get ?? + vi.fn((path: string) => ({ ok: { path }, units: 5 })), + getCanonical: + overrides?.document?.getCanonical ?? + vi.fn((path: string) => ({ ok: { canonical: path }, units: 3 })), + }, + emit: + overrides?.emit ?? + vi.fn(() => ({ + ok: null, + units: 1, + })), + }; +} + +export function getFnId(path: string): number { + const fn = HOST_V1_MANIFEST.functions.find( + (entry) => entry.js_path.join('.') === path, + ); + if (!fn) { + throw new Error(`missing fn_id for ${path}`); + } + return fn.fn_id; +} + +export function createModulePack(options: { + entrySpecifier: string; + modules: Array<{ specifier: string; source: string; sourceMap?: string }>; + entryExport?: string; +}) { + const base = { + version: 1 as const, + entrySpecifier: options.entrySpecifier, + ...(options.entryExport ? { entryExport: options.entryExport } : {}), + modules: options.modules, + builderVersion: 'deterministic-builder-v1', + dependencyIntegrity: + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + }; + const canonical = { + version: base.version, + entrySpecifier: base.entrySpecifier, + entryExport: base.entryExport ?? 'default', + modules: [...base.modules] + .sort((left, right) => + compareUtf8ByteOrder(left.specifier, right.specifier), + ) + .map((module) => ({ + specifier: module.specifier, + source: module.source, + ...(module.sourceMap ? { sourceMap: module.sourceMap } : {}), + })), + builderVersion: base.builderVersion, + dependencyIntegrity: base.dependencyIntegrity, + }; + const graphHash = createHash('sha256') + .update(stableStringify(canonical), 'utf8') + .digest('hex'); + return { + ...base, + graphHash, + }; +} + +function stableStringify(value: unknown): string { + if (value === null || typeof value !== 'object') { + return JSON.stringify(value); + } + if (Array.isArray(value)) { + return `[${value.map((item) => stableStringify(item)).join(',')}]`; + } + const entries = Object.entries(value as Record) + .filter(([, item]) => item !== undefined) + .sort(([left], [right]) => compareUtf8ByteOrder(left, right)) + .map(([key, item]) => `${JSON.stringify(key)}:${stableStringify(item)}`); + return `{${entries.join(',')}}`; +} + +const UTF8_ENCODER = new TextEncoder(); + +function compareUtf8ByteOrder(left: string, right: string): number { + if (left === right) { + return 0; + } + + const leftBytes = UTF8_ENCODER.encode(left); + const rightBytes = UTF8_ENCODER.encode(right); + const limit = Math.min(leftBytes.length, rightBytes.length); + + for (let index = 0; index < limit; index += 1) { + const delta = leftBytes[index] - rightBytes[index]; + if (delta !== 0) { + return delta; + } + } + + return leftBytes.length - rightBytes.length; +} diff --git a/libs/quickjs-runtime/src/lib/host-dispatcher.spec.ts b/libs/quickjs-runtime/src/test/host-dispatcher.spec.ts similarity index 74% rename from libs/quickjs-runtime/src/lib/host-dispatcher.spec.ts rename to libs/quickjs-runtime/src/test/host-dispatcher.spec.ts index 3496301..b050b02 100644 --- a/libs/quickjs-runtime/src/lib/host-dispatcher.spec.ts +++ b/libs/quickjs-runtime/src/test/host-dispatcher.spec.ts @@ -1,5 +1,5 @@ -import { encodeDv, decodeDv } from '@blue-quickjs/dv'; -import { HOST_V1_MANIFEST } from '@blue-quickjs/abi-manifest'; +import { decodeDv, decodeDv2, encodeDv, encodeDv2 } from '@blue-quickjs/dv'; +import { HOST_V1_MANIFEST, HOST_V2_MANIFEST } from '@blue-quickjs/abi-manifest'; import { type DocumentHostHandlers, type EmitHostHandler, @@ -8,11 +8,12 @@ import { type HostCallMemory, createHostCallImport, createHostDispatcher, -} from './host-dispatcher.js'; +} from '../lib/host-dispatcher.js'; -const DOC_GET_ID = getFnId('document.get'); -const DOC_GET_CANONICAL_ID = getFnId('document.getCanonical'); -const EMIT_ID = getFnId('emit'); +const DOC_GET_ID = getFnId(HOST_V1_MANIFEST, 'document.get'); +const DOC_GET_CANONICAL_ID = getFnId(HOST_V1_MANIFEST, 'document.getCanonical'); +const EMIT_ID = getFnId(HOST_V1_MANIFEST, 'emit'); +const DOC_GET_ID_V2 = getFnId(HOST_V2_MANIFEST, 'document.get'); const UINT32_MAX = 0xffffffff; describe('host dispatcher', () => { @@ -189,6 +190,72 @@ describe('host dispatcher', () => { const written = hostCall(DOC_GET_ID, 0, request.length, 64, 128); expect(written).toBeGreaterThan(0); }); + + it('supports Host.v2 byte-string payloads via DV2', () => { + const handlers = createHandlers({ + get: vi.fn((path: string) => { + if (path !== 'bytes/path') { + return { + err: { code: 'NOT_FOUND', tag: 'host/not_found' }, + units: 1, + }; + } + return { ok: Uint8Array.from([0xde, 0xad, 0xbe, 0xef]), units: 2 }; + }), + }); + const dispatcher = createHostDispatcher(HOST_V2_MANIFEST, handlers, { + expectedAbiId: 'Host.v2', + expectedAbiVersion: 2, + }); + + const request = encodeDv2(['bytes/path']); + const result = dispatcher.dispatch(DOC_GET_ID_V2, request); + expect(result.kind).toBe('response'); + + const envelope = decodeDv2( + (result as Extract).envelope, + ) as { ok: Uint8Array; units: number }; + expect(envelope.units).toBe(2); + expect(envelope.ok).toBeInstanceOf(Uint8Array); + expect(Array.from(envelope.ok)).toEqual([0xde, 0xad, 0xbe, 0xef]); + }); + + it('supports nested DV2 byte-string payloads', () => { + const handlers = createHandlers({ + get: vi.fn(() => ({ + ok: { + header: Uint8Array.from([1, 2]), + chunks: [Uint8Array.from([3]), Uint8Array.from([4, 5])], + }, + units: 2, + })), + }); + const dispatcher = createHostDispatcher(HOST_V2_MANIFEST, handlers, { + expectedAbiId: 'Host.v2', + expectedAbiVersion: 2, + }); + + const request = encodeDv2(['bytes/path']); + const result = dispatcher.dispatch(DOC_GET_ID_V2, request); + expect(result.kind).toBe('response'); + + const envelope = decodeDv2( + (result as Extract).envelope, + ) as { + ok: { + header: Uint8Array; + chunks: Uint8Array[]; + }; + units: number; + }; + + expect(envelope.units).toBe(2); + expect(Array.from(envelope.ok.header)).toEqual([1, 2]); + expect(envelope.ok.chunks.map((chunk) => Array.from(chunk))).toEqual([ + [3], + [4, 5], + ]); + }); }); function expectResponse(result: HostDispatchResult): { @@ -237,8 +304,11 @@ function createHandlers( }; } -function getFnId(path: string): number { - const fn = HOST_V1_MANIFEST.functions.find( +function getFnId( + manifest: { functions: Array<{ fn_id: number; js_path: string[] }> }, + path: string, +): number { + const fn = manifest.functions.find( (entry) => entry.js_path.join('.') === path, ); if (!fn) { diff --git a/libs/quickjs-runtime/src/lib/quickjs-runtime.spec.ts b/libs/quickjs-runtime/src/test/quickjs-runtime.spec.ts similarity index 53% rename from libs/quickjs-runtime/src/lib/quickjs-runtime.spec.ts rename to libs/quickjs-runtime/src/test/quickjs-runtime.spec.ts index fc9e38f..e10c231 100644 --- a/libs/quickjs-runtime/src/lib/quickjs-runtime.spec.ts +++ b/libs/quickjs-runtime/src/test/quickjs-runtime.spec.ts @@ -3,10 +3,12 @@ import { InputEnvelope, PROGRAM_LIMIT_DEFAULTS, ProgramArtifact, + ProgramArtifactV2, RuntimeValidationError, validateInputEnvelope, validateProgramArtifact, -} from './quickjs-runtime.js'; + validateProgramArtifactV2, +} from '../lib/quickjs-runtime.js'; const SAMPLE_HASH = '8d50b2a3f4c5d6e7f8c9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1'; @@ -58,6 +60,136 @@ describe('validateProgramArtifact', () => { }), ).toThrow(RuntimeValidationError); }); + + it('accepts supported execution profiles', () => { + expect( + validateProgramArtifact({ + ...baseProgram, + executionProfile: 'baseline-v1', + }), + ).toMatchObject({ executionProfile: 'baseline-v1' }); + + expect( + validateProgramArtifact({ + ...baseProgram, + executionProfile: 'compat-general-v1', + }), + ).toMatchObject({ executionProfile: 'compat-general-v1' }); + + expect( + validateProgramArtifact({ + ...baseProgram, + executionProfile: 'compat-binary-v1', + }), + ).toMatchObject({ executionProfile: 'compat-binary-v1' }); + }); + + it('rejects unsupported execution profiles', () => { + expect(() => + validateProgramArtifact({ + ...baseProgram, + executionProfile: + 'compat-unknown' as unknown as ProgramArtifact['executionProfile'], + }), + ).toThrow(RuntimeValidationError); + }); + + it('accepts uint32 gasVersion values', () => { + expect( + validateProgramArtifact({ + ...baseProgram, + gasVersion: 3, + }), + ).toMatchObject({ gasVersion: 3 }); + }); + + it('rejects invalid gasVersion values', () => { + expect(() => + validateProgramArtifact({ + ...baseProgram, + gasVersion: -1, + }), + ).toThrow(RuntimeValidationError); + + expect(() => + validateProgramArtifact({ + ...baseProgram, + gasVersion: 1.5, + }), + ).toThrow(RuntimeValidationError); + }); +}); + +describe('validateProgramArtifactV2', () => { + const baseProgramV2: ProgramArtifactV2 = { + version: 2, + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: SAMPLE_HASH, + executionProfile: 'baseline-v1', + sourceKind: 'script', + source: { + code: '42', + }, + }; + + it('accepts script source artifacts', () => { + expect(validateProgramArtifactV2(baseProgramV2)).toEqual(baseProgramV2); + }); + + it('accepts module-pack source artifacts', () => { + const modulePack = validateProgramArtifactV2({ + ...baseProgramV2, + sourceKind: 'module-pack', + source: { + modulePack: { + version: 1, + entrySpecifier: './entry.js', + modules: [ + { + specifier: './entry.js', + source: 'export default 42;\n', + }, + ], + graphHash: SAMPLE_HASH, + builderVersion: 'deterministic-builder-v1', + dependencyIntegrity: SAMPLE_HASH, + }, + }, + }); + + expect(modulePack.sourceKind).toBe('module-pack'); + }); + + it('rejects source kind/source shape mismatch', () => { + expect(() => + validateProgramArtifactV2({ + ...baseProgramV2, + sourceKind: 'script', + source: { + modulePack: {}, + }, + }), + ).toThrow(RuntimeValidationError); + }); + + it('accepts uint32 gasVersion values', () => { + expect( + validateProgramArtifactV2({ + ...baseProgramV2, + gasVersion: 3, + }), + ).toMatchObject({ gasVersion: 3 }); + }); + + it('rejects invalid gasVersion values', () => { + expect(() => + validateProgramArtifactV2({ + ...baseProgramV2, + gasVersion: -1, + }), + ).toThrow(RuntimeValidationError); + }); }); describe('validateInputEnvelope', () => { diff --git a/libs/quickjs-runtime/src/lib/runtime.spec.ts b/libs/quickjs-runtime/src/test/runtime.spec.ts similarity index 93% rename from libs/quickjs-runtime/src/lib/runtime.spec.ts rename to libs/quickjs-runtime/src/test/runtime.spec.ts index f0f7e97..e45d6db 100644 --- a/libs/quickjs-runtime/src/lib/runtime.spec.ts +++ b/libs/quickjs-runtime/src/test/runtime.spec.ts @@ -5,9 +5,9 @@ import { hexToBytes, parseDeterministicOutput, } from '@blue-quickjs/test-harness'; -import { type HostDispatcherHandlers } from './host-dispatcher.js'; -import { initializeDeterministicVm } from './deterministic-init.js'; -import { createRuntime } from './runtime.js'; +import { type HostDispatcherHandlers } from '../lib/host-dispatcher.js'; +import { initializeDeterministicVm } from '../lib/deterministic-init.js'; +import { createRuntime } from '../lib/runtime.js'; describe('createRuntime', () => { it('instantiates the wasm module and evaluates code', async () => { diff --git a/libs/quickjs-runtime/src/test/source-map-remap.spec.ts b/libs/quickjs-runtime/src/test/source-map-remap.spec.ts new file mode 100644 index 0000000..dfa43aa --- /dev/null +++ b/libs/quickjs-runtime/src/test/source-map-remap.spec.ts @@ -0,0 +1,58 @@ +import { remapModulePackErrorPayload } from '../lib/source-map-remap.js'; +import type { ModulePackV1 } from '../lib/quickjs-runtime.js'; + +function createModulePack(sourceMap?: string): ModulePackV1 { + return { + version: 1, + entrySpecifier: './entry.js', + entryExport: 'default', + modules: [ + { + specifier: './entry.js', + source: 'const x = 1;\nthrow new Error("boom");\n', + ...(sourceMap ? { sourceMap } : {}), + }, + ], + graphHash: '0'.repeat(64), + builderVersion: 'deterministic-builder-v1', + dependencyIntegrity: '1'.repeat(64), + }; +} + +describe('source-map remap', () => { + it('remaps module-pack stack locations to original sources', () => { + const sourceMap = JSON.stringify({ + version: 3, + file: 'entry.js', + sources: ['src/entry.ts'], + names: [], + mappings: 'AAAA;AACA', + }); + const payload = + 'ModuleEvaluationError: Error: boom at ./entry.js:2:7 and ./entry.js:1:1'; + + const remapped = remapModulePackErrorPayload( + payload, + createModulePack(sourceMap), + ); + + expect(remapped.payload).toContain('src/entry.ts:2:1'); + expect(remapped.payload).toContain('src/entry.ts:1:1'); + expect(remapped.locations).toHaveLength(2); + expect(remapped.locations[0]).toMatchObject({ + generatedSpecifier: './entry.js', + generatedLine: 2, + generatedColumn: 7, + source: 'src/entry.ts', + line: 2, + column: 1, + }); + }); + + it('leaves payload unchanged when no source map is present', () => { + const payload = 'ModuleEvaluationError: Error: boom at ./entry.js:2:7'; + const remapped = remapModulePackErrorPayload(payload, createModulePack()); + expect(remapped.payload).toBe(payload); + expect(remapped.locations).toEqual([]); + }); +}); diff --git a/libs/quickjs-runtime/tsconfig.lib.json b/libs/quickjs-runtime/tsconfig.lib.json index 901dedd..c065fd7 100644 --- a/libs/quickjs-runtime/tsconfig.lib.json +++ b/libs/quickjs-runtime/tsconfig.lib.json @@ -15,16 +15,18 @@ "path": "../quickjs-wasm/tsconfig.lib.json" }, { - "path": "../dv/tsconfig.lib.json" + "path": "../execution-profiles/tsconfig.lib.json" }, { - "path": "../abi-manifest/tsconfig.lib.json" + "path": "../dv/tsconfig.lib.json" }, { - "path": "../test-harness/tsconfig.lib.json" + "path": "../abi-manifest/tsconfig.lib.json" } ], "exclude": [ + "tests/**", + "src/test/**", "vite.config.ts", "vite.config.mts", "vitest.config.ts", diff --git a/libs/quickjs-runtime/tsconfig.spec.json b/libs/quickjs-runtime/tsconfig.spec.json index f68d9d3..eee5f4b 100644 --- a/libs/quickjs-runtime/tsconfig.spec.json +++ b/libs/quickjs-runtime/tsconfig.spec.json @@ -18,17 +18,37 @@ "vitest.config.mts", "src/**/*.test.ts", "src/**/*.spec.ts", + "src/test/**/*.ts", + "tests/**/*.ts", "src/**/*.test.tsx", "src/**/*.spec.tsx", + "src/test/**/*.tsx", + "tests/**/*.tsx", "src/**/*.test.js", "src/**/*.spec.js", + "src/test/**/*.js", + "tests/**/*.js", "src/**/*.test.jsx", "src/**/*.spec.jsx", + "src/test/**/*.jsx", + "tests/**/*.jsx", "src/**/*.d.ts" ], "references": [ { "path": "./tsconfig.lib.json" + }, + { + "path": "../dv/tsconfig.lib.json" + }, + { + "path": "../abi-manifest/tsconfig.lib.json" + }, + { + "path": "../test-harness/tsconfig.lib.json" + }, + { + "path": "../deterministic-bundler/tsconfig.lib.json" } ] } diff --git a/libs/quickjs-runtime/vite.config.ts b/libs/quickjs-runtime/vite.config.ts index 51ad9e4..24deec4 100644 --- a/libs/quickjs-runtime/vite.config.ts +++ b/libs/quickjs-runtime/vite.config.ts @@ -19,6 +19,15 @@ export default defineConfig(() => ({ coverage: { reportsDirectory: './test-output/vitest/coverage', provider: 'v8' as const, + all: true, + include: ['src/**/*.{ts,mts}'], + exclude: ['src/test/**', 'src/**/*.{test,spec}.{ts,mts}'], + thresholds: { + lines: 40, + functions: 40, + branches: 40, + statements: 40, + }, }, }, })); diff --git a/libs/quickjs-wasm-build/README.md b/libs/quickjs-wasm-build/README.md index a5a5d70..358e713 100644 --- a/libs/quickjs-wasm-build/README.md +++ b/libs/quickjs-wasm-build/README.md @@ -4,17 +4,17 @@ Early Emscripten build of the deterministic QuickJS fork with gas metering. ## Building -- Ensure the pinned toolchain is installed (`tools/scripts/setup-emsdk.sh`) and `vendor/quickjs` is initialized. +- Ensure the pinned Emscripten toolchain is installed (`tools/scripts/setup-emsdk.sh`) and the generated QuickJS source tree exists (`bash tools/scripts/prepare-quickjs-source.sh` or `pnpm setup`). - Run `pnpm nx build quickjs-wasm-build` to compile the wasm harness and emit both release and debug wasm32 artifacts (`quickjs-eval{,-debug}.{js,wasm}`) to `libs/quickjs-wasm-build/dist/`. TypeScript outputs also land in this directory. - Set `WASM_BUILD_TYPES=release` to skip debug builds, or `WASM_BUILD_TYPES=release,debug` (default) to emit both. Set `WASM_VARIANTS=wasm32,wasm64` to also emit the memory64 artifacts (`quickjs-eval-wasm64{,-debug}.{js,wasm}`) used with `QJS_WASM_VARIANT=wasm64` in tests. - Wasm memory is fixed at 32 MiB (1 MiB stack) with growth disabled; the Emscripten filesystem is stripped (`-sFILESYSTEM=0`), and we pin `SOURCE_DATE_EPOCH=1704067200` to avoid timestamp/env noise in the wasm/loader. We intentionally avoid `-sDETERMINISTIC` because it patches host `Date.now`/`Math.random`. -- The build also emits `quickjs-wasm-build.metadata.json` in `dist/`, capturing the QuickJS version/commit, pinned emscripten version, deterministic build settings (memory + flags), per-variant/per-build-type artifact sizes and SHA-256 hashes (including the `buildType` and flags used), and `engineBuildHash` (sha256 of wasm bytes, with the top-level hash pointing at wasm32 release when present). Access it via `getQuickjsWasmMetadataPath()` / `readQuickjsWasmMetadata()`. +- The build also emits `quickjs-wasm-build.metadata.json` in `dist/`, capturing the QuickJS version/commit, pinned emscripten version, deterministic build settings (memory + flags), canonical `gasVersion`, per-variant/per-build-type artifact sizes and SHA-256 hashes (including the `buildType` and flags used), and `engineBuildHash` (sha256 of wasm bytes, with the top-level hash pointing at wasm32 release when present). Access it via `getQuickjsWasmMetadataPath()` / `readQuickjsWasmMetadata()`. The ESM loader exports a `QuickJSGasWasm` factory; the harness exports deterministic ABI entrypoints only: -- `qjs_det_init(manifest_ptr, manifest_len, manifest_hash_hex_ptr, context_ptr, context_len, gas_limit)` installs the ABI manifest/hash and optional DV-encoded context blob while wiring the imported `host_call`. +- `qjs_det_init(manifest_ptr, manifest_len, manifest_hash_hex_ptr, context_ptr, context_len, gas_limit, feature_flags)` installs the ABI manifest/hash and optional DV-encoded context blob while wiring the imported `host_call`. `feature_flags=0` keeps baseline behavior. - `qjs_det_eval(code)` evaluates source with the installed manifest/context and returns a `char*` string of the form `RESULT GAS remaining= used=` (or `ERROR …` on failure). -- `qjs_det_set_gas_limit(gas_limit)`, `qjs_det_free()`, `qjs_det_enable_tape(capacity)` / `qjs_det_read_tape()`, and `qjs_det_enable_trace(enabled)` / `qjs_det_read_trace()` mirror the native harness controls. +- `qjs_det_set_gas_limit(gas_limit)`, `qjs_det_free()`, `qjs_det_enable_tape(capacity)` / `qjs_det_read_tape()`, `qjs_det_enable_charge_tape(capacity)` / `qjs_det_read_charge_tape()`, and `qjs_det_enable_trace(enabled)` / `qjs_det_read_trace()` mirror the native harness controls. Strings returned from the harness are allocated with `malloc`; free them with the exported `_free` helper. The wasm module expects a `host.host_call` import. When you don't have a dispatcher wired yet, pass a stub that returns the transport sentinel: diff --git a/libs/quickjs-wasm-build/project.json b/libs/quickjs-wasm-build/project.json index f471af9..e3c9861 100644 --- a/libs/quickjs-wasm-build/project.json +++ b/libs/quickjs-wasm-build/project.json @@ -8,10 +8,10 @@ "build": { "executor": "nx:run-commands", "cache": true, - "dependsOn": ["^build"], + "dependsOn": ["^build", "typecheck"], "inputs": [ "default", - "quickjsSubmodule", + "quickjsSource", "{workspaceRoot}/tools/scripts/emsdk-version.txt", { "env": "WASM_VARIANTS" diff --git a/libs/quickjs-wasm-build/scripts/build-wasm.sh b/libs/quickjs-wasm-build/scripts/build-wasm.sh index 5acea82..e3cdafa 100755 --- a/libs/quickjs-wasm-build/scripts/build-wasm.sh +++ b/libs/quickjs-wasm-build/scripts/build-wasm.sh @@ -7,6 +7,8 @@ PROJECT_ROOT="${REPO_ROOT}/libs/quickjs-wasm-build" QJS_DIR="${REPO_ROOT}/vendor/quickjs" OUT_DIR="${PROJECT_ROOT}/dist" METADATA_BASENAME="quickjs-wasm-build.metadata.json" + +bash "${REPO_ROOT}/tools/scripts/prepare-quickjs-source.sh" VARIANTS_RAW="${WASM_VARIANTS:-wasm32}" BUILD_TYPES_RAW="${WASM_BUILD_TYPES:-release,debug}" WASM_INITIAL_MEMORY_BYTES=$((32 * 1024 * 1024)) @@ -16,7 +18,12 @@ SOURCE_DATE_EPOCH_DEFAULT=1704067200 ENV_SCRIPT="${REPO_ROOT}/tools/emsdk/emsdk_env.sh" if [[ ! -f "${ENV_SCRIPT}" ]]; then - echo "Emscripten env not found at ${ENV_SCRIPT}. Run tools/scripts/setup-emsdk.sh first." >&2 + echo "Emscripten env not found at ${ENV_SCRIPT}; bootstrapping pinned emsdk." >&2 + bash "${REPO_ROOT}/tools/scripts/setup-emsdk.sh" +fi + +if [[ ! -f "${ENV_SCRIPT}" ]]; then + echo "Emscripten env not found at ${ENV_SCRIPT} after setup." >&2 exit 1 fi @@ -89,7 +96,7 @@ BASE_EMCC_FLAGS=( -sERROR_ON_UNDEFINED_SYMBOLS=0 -sEXPORT_NAME=QuickJSGasWasm -sWASM_BIGINT=1 - "-sEXPORTED_FUNCTIONS=['_qjs_det_init','_qjs_det_eval','_qjs_det_set_gas_limit','_qjs_det_free','_qjs_det_enable_tape','_qjs_det_read_tape','_qjs_det_enable_trace','_qjs_det_read_trace','_malloc','_free']" + "-sEXPORTED_FUNCTIONS=['_qjs_det_init','_qjs_det_eval','_qjs_det_eval_module_pack','_qjs_det_set_gas_limit','_qjs_det_free','_qjs_det_enable_tape','_qjs_det_read_tape','_qjs_det_enable_charge_tape','_qjs_det_read_charge_tape','_qjs_det_enable_trace','_qjs_det_read_trace','_malloc','_free']" "-sEXPORTED_RUNTIME_METHODS=['cwrap','ccall','UTF8ToString','lengthBytesUTF8']" ) @@ -213,13 +220,31 @@ if [[ ${#BUILT_VARIANTS[@]} -eq 0 ]]; then exit 1 fi -node - "${OUT_DIR}" "${QJS_DIR}" "${REPO_ROOT}/tools/scripts/emsdk-version.txt" "${METADATA_BASENAME}" "${BUILT_VARIANTS[@]}" <<'NODE' +node - "${OUT_DIR}" "${QJS_DIR}" "${REPO_ROOT}/tools/scripts/emsdk-version.txt" "${REPO_ROOT}/tools/gas-spec/gas-spec.v3.json" "${METADATA_BASENAME}" "${BUILT_VARIANTS[@]}" <<'NODE' const crypto = require('crypto'); const fs = require('fs'); const path = require('path'); const { execFileSync } = require('child_process'); -const [outDir, qjsDir, emsdkVersionFile, metadataBasename, ...variantArgs] = process.argv.slice(2); +const normalizeCliPath = (filePath) => { + if (process.platform !== 'win32') { + return filePath; + } + const msysDrivePath = /^\/([a-zA-Z])\/(.*)$/; + const match = msysDrivePath.exec(filePath); + if (!match) { + return filePath; + } + const [, driveLetter, rest] = match; + return path.win32.normalize(`${driveLetter.toUpperCase()}:\\${rest.replaceAll('/', '\\')}`); +}; + +const [rawOutDir, rawQjsDir, rawEmsdkVersionFile, rawGasSpecPath, metadataBasename, ...variantArgs] = + process.argv.slice(2); +const outDir = normalizeCliPath(rawOutDir); +const qjsDir = normalizeCliPath(rawQjsDir); +const emsdkVersionFile = normalizeCliPath(rawEmsdkVersionFile); +const gasSpecPath = normalizeCliPath(rawGasSpecPath); if (variantArgs.length === 0) { throw new Error('No variant arguments passed to metadata writer.'); } @@ -243,6 +268,11 @@ const sha256File = (filePath) => const statSize = (filePath) => fs.statSync(filePath).size; const quickjsVersion = readTrim(path.join(qjsDir, 'VERSION')); +const gasSpec = JSON.parse(fs.readFileSync(gasSpecPath, 'utf8')); +const gasVersion = + Number.isInteger(gasSpec?.gasVersion) && gasSpec.gasVersion >= 0 + ? gasSpec.gasVersion + : null; let quickjsCommit = null; try { quickjsCommit = execFileSync('git', ['-C', qjsDir, 'rev-parse', 'HEAD'], { @@ -271,7 +301,14 @@ const variants = variantArgs const buildTypeFlags = buildTypeFlagsRaw ? buildTypeFlagsRaw.split(',').map((flag) => flag.trim()).filter(Boolean) : []; - return { variant, buildType, wasmPath, loaderPath, variantFlags, buildTypeFlags }; + return { + variant, + buildType, + wasmPath: normalizeCliPath(wasmPath), + loaderPath: normalizeCliPath(loaderPath), + variantFlags, + buildTypeFlags, + }; }) .sort((a, b) => { if (a.variant === b.variant) { @@ -337,6 +374,7 @@ const metadata = { quickjsCommit, emscriptenVersion: readTrim(emsdkVersionFile), engineBuildHash, + gasVersion, build: { memory: buildMemory, determinism, diff --git a/libs/quickjs-wasm-build/src/lib/quickjs-wasm-build.spec.ts b/libs/quickjs-wasm-build/src/lib/quickjs-wasm-build.spec.ts index b4791ec..fbf217e 100644 --- a/libs/quickjs-wasm-build/src/lib/quickjs-wasm-build.spec.ts +++ b/libs/quickjs-wasm-build/src/lib/quickjs-wasm-build.spec.ts @@ -105,6 +105,7 @@ describe('metadata helpers', () => { quickjsCommit: 'abc123', emscriptenVersion: '3.1.56', engineBuildHash: 'deadbeef', + gasVersion: 3, build: { memory: { initial: 33554432, diff --git a/libs/quickjs-wasm-build/src/wasm/quickjs_wasm.c b/libs/quickjs-wasm-build/src/wasm/quickjs_wasm.c index 584abc3..a4df12e 100644 --- a/libs/quickjs-wasm-build/src/wasm/quickjs_wasm.c +++ b/libs/quickjs-wasm-build/src/wasm/quickjs_wasm.c @@ -26,6 +26,7 @@ static void free_det_runtime(void) { det_ctx = NULL; } if (det_rt) { + JS_RunGC(det_rt); JS_FreeRuntime(det_rt); det_rt = NULL; } @@ -169,17 +170,326 @@ static int js_set_prop(JSContext *ctx, JSValue obj, const char *name, JSValue va return 0; } +typedef struct { + char *specifier; + char *source; + size_t source_len; +} ModulePackEntry; + +typedef struct { + ModulePackEntry *entries; + uint32_t entry_count; +} ModulePack; + +static void free_module_pack(ModulePack *pack) { + if (!pack) { + return; + } + if (pack->entries) { + for (uint32_t i = 0; i < pack->entry_count; i++) { + free(pack->entries[i].specifier); + free(pack->entries[i].source); + } + free(pack->entries); + } + pack->entries = NULL; + pack->entry_count = 0; +} + +static ModulePackEntry *find_module_pack_entry(ModulePack *pack, + const char *specifier) { + if (!pack || !specifier) { + return NULL; + } + for (uint32_t i = 0; i < pack->entry_count; i++) { + if (strcmp(pack->entries[i].specifier, specifier) == 0) { + return &pack->entries[i]; + } + } + return NULL; +} + +static char *copy_cstring_len(const char *value, size_t length) { + char *out = malloc(length + 1); + if (!out) { + return NULL; + } + memcpy(out, value, length); + out[length] = '\0'; + return out; +} + +static int parse_module_pack_json(JSContext *ctx, + const char *module_pack_json, + ModulePack *out_pack) { + JSValue parsed = JS_UNDEFINED; + JSValue length_value = JS_UNDEFINED; + uint32_t module_count = 0; + + memset(out_pack, 0, sizeof(*out_pack)); + + parsed = JS_ParseJSON(ctx, module_pack_json, strlen(module_pack_json), + ""); + if (JS_IsException(parsed)) { + goto fail; + } + + if (!JS_IsArray(ctx, parsed)) { + JS_ThrowTypeError(ctx, "module pack json must be an array"); + goto fail; + } + + length_value = JS_GetPropertyStr(ctx, parsed, "length"); + if (JS_IsException(length_value)) { + goto fail; + } + if (JS_ToUint32(ctx, &module_count, length_value) != 0) { + goto fail; + } + JS_FreeValue(ctx, length_value); + length_value = JS_UNDEFINED; + + if (module_count == 0) { + JS_ThrowTypeError(ctx, "module pack must contain at least one module"); + goto fail; + } + + out_pack->entries = calloc(module_count, sizeof(*out_pack->entries)); + if (!out_pack->entries) { + JS_ThrowOutOfMemory(ctx); + goto fail; + } + out_pack->entry_count = module_count; + + for (uint32_t i = 0; i < module_count; i++) { + JSValue item = JS_GetPropertyUint32(ctx, parsed, i); + JSValue specifier_value = JS_UNDEFINED; + JSValue source_value = JS_UNDEFINED; + const char *specifier_cstr = NULL; + const char *source_cstr = NULL; + size_t source_len = 0; + + if (JS_IsException(item)) { + goto fail; + } + if (!JS_IsObject(item)) { + JS_FreeValue(ctx, item); + JS_ThrowTypeError(ctx, "module pack entry must be an object"); + goto fail; + } + + specifier_value = JS_GetPropertyStr(ctx, item, "specifier"); + source_value = JS_GetPropertyStr(ctx, item, "source"); + if (JS_IsException(specifier_value) || JS_IsException(source_value)) { + JS_FreeValue(ctx, specifier_value); + JS_FreeValue(ctx, source_value); + JS_FreeValue(ctx, item); + goto fail; + } + + specifier_cstr = JS_ToCString(ctx, specifier_value); + source_cstr = JS_ToCStringLen(ctx, &source_len, source_value); + if (!specifier_cstr || !source_cstr) { + JS_FreeCString(ctx, specifier_cstr); + JS_FreeCString(ctx, source_cstr); + JS_FreeValue(ctx, specifier_value); + JS_FreeValue(ctx, source_value); + JS_FreeValue(ctx, item); + goto fail; + } + + out_pack->entries[i].specifier = + copy_cstring_len(specifier_cstr, strlen(specifier_cstr)); + out_pack->entries[i].source = copy_cstring_len(source_cstr, source_len); + out_pack->entries[i].source_len = source_len; + + JS_FreeCString(ctx, specifier_cstr); + JS_FreeCString(ctx, source_cstr); + JS_FreeValue(ctx, specifier_value); + JS_FreeValue(ctx, source_value); + JS_FreeValue(ctx, item); + + if (!out_pack->entries[i].specifier || !out_pack->entries[i].source) { + JS_ThrowOutOfMemory(ctx); + goto fail; + } + } + + JS_FreeValue(ctx, parsed); + return 0; + +fail: + if (!JS_IsUndefined(length_value)) { + JS_FreeValue(ctx, length_value); + } + if (!JS_IsUndefined(parsed)) { + JS_FreeValue(ctx, parsed); + } + free_module_pack(out_pack); + return -1; +} + +static JSModuleDef *module_pack_loader(JSContext *ctx, + const char *module_name, + void *opaque, + JSValueConst attributes) { + ModulePack *pack = (ModulePack *)opaque; + ModulePackEntry *entry = find_module_pack_entry(pack, module_name); + JSValue module_obj = JS_UNDEFINED; + + (void)attributes; + + if (!entry) { + JS_ThrowReferenceError(ctx, + "ModuleResolutionError: module specifier not found: %s", + module_name); + return NULL; + } + + module_obj = JS_Eval(ctx, entry->source, entry->source_len, entry->specifier, + JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY); + if (JS_IsException(module_obj)) { + return NULL; + } + + JSModuleDef *module_def = (JSModuleDef *)JS_VALUE_GET_PTR(module_obj); + JS_FreeValue(ctx, module_obj); + return module_def; +} + +static char *escape_js_string(const char *input) { + size_t needed = 2; /* quotes */ + for (const unsigned char *p = (const unsigned char *)input; *p; p++) { + switch (*p) { + case '\\': + case '"': + case '\n': + case '\r': + case '\t': + needed += 2; + break; + default: + needed += 1; + break; + } + } + + char *out = malloc(needed + 1); + if (!out) { + return NULL; + } + + char *cursor = out; + *cursor++ = '"'; + for (const unsigned char *p = (const unsigned char *)input; *p; p++) { + switch (*p) { + case '\\': + *cursor++ = '\\'; + *cursor++ = '\\'; + break; + case '"': + *cursor++ = '\\'; + *cursor++ = '"'; + break; + case '\n': + *cursor++ = '\\'; + *cursor++ = 'n'; + break; + case '\r': + *cursor++ = '\\'; + *cursor++ = 'r'; + break; + case '\t': + *cursor++ = '\\'; + *cursor++ = 't'; + break; + default: + *cursor++ = (char)*p; + break; + } + } + *cursor++ = '"'; + *cursor = '\0'; + return out; +} + +static char *format_prefixed_exception(JSContext *ctx, uint64_t gas_limit, + const char *prefix, + const char *fallback, + const JSGasTrace *trace) { + JSValue exception = JS_GetException(ctx); + const char *msg = JS_ToCString(ctx, exception); + uint64_t remaining = JS_GetGasRemaining(ctx); + char *payload = dup_printf("%s: %s", prefix, msg ? msg : fallback); + char *out = format_with_gas("ERROR", payload ? payload : prefix, gas_limit, + remaining, trace); + + if (payload) { + free(payload); + } + if (msg) { + JS_FreeCString(ctx, msg); + } + JS_FreeValue(ctx, exception); + return out; +} + +static int drain_pending_jobs(JSContext *ctx, JSRuntime *rt, + JSContext **out_error_ctx) { + while (JS_IsJobPending(rt)) { + JSContext *job_ctx = NULL; + int rc = JS_ExecutePendingJob(rt, &job_ctx); + if (rc < 0) { + if (out_error_ctx) { + *out_error_ctx = job_ctx ? job_ctx : ctx; + } + return -1; + } + } + + if (out_error_ctx) { + *out_error_ctx = ctx; + } + return 0; +} + +static int resolve_promise_result(JSContext *ctx, JSValue *value) { + int state = (int)JS_PromiseState(ctx, *value); + if (state < 0) { + return 0; + } + + if (state == JS_PROMISE_PENDING) { + JS_ThrowTypeError(ctx, + "promise did not settle during deterministic job drain"); + return -1; + } + + JSValue settled = JS_PromiseResult(ctx, *value); + if (state == JS_PROMISE_REJECTED) { + JS_FreeValue(ctx, *value); + *value = JS_UNDEFINED; + JS_Throw(ctx, settled); + return -1; + } + + JS_FreeValue(ctx, *value); + *value = settled; + return 0; +} + EMSCRIPTEN_KEEPALIVE char *qjs_det_init(const uint8_t *manifest_bytes, uint32_t manifest_size, const char *manifest_hash_hex, const uint8_t *context_blob, uint32_t context_blob_size, - uint64_t gas_limit) { + uint64_t gas_limit, + uint32_t feature_flags) { free_det_runtime(); det_gas_limit = gas_limit; - if (JS_NewDeterministicRuntime(&det_rt, &det_ctx) != 0) { + if (JS_NewDeterministicRuntimeWithFeatures(&det_rt, &det_ctx, feature_flags) != 0) { return dup_printf("ERROR GAS remaining=0 used=0"); } @@ -195,6 +505,7 @@ char *qjs_det_init(const uint8_t *manifest_bytes, .context_blob = context_blob, .context_blob_size = context_blob_size, .gas_limit = gas_limit, + .feature_flags = feature_flags, }; if (JS_InitDeterministicContext(det_ctx, &opts) != 0) { @@ -214,6 +525,8 @@ char *qjs_det_init(const uint8_t *manifest_bytes, EMSCRIPTEN_KEEPALIVE char *qjs_det_eval(const char *code) { + JSContext *job_error_ctx = NULL; + if (!det_ctx || !det_rt) { return dup_printf("ERROR GAS remaining=0 used=0"); } @@ -228,6 +541,17 @@ char *qjs_det_eval(const char *code) { return format_exception(det_ctx, det_gas_limit, "", NULL); } + if (drain_pending_jobs(det_ctx, det_rt, &job_error_ctx) != 0) { + JS_FreeValue(det_ctx, result); + return format_exception(job_error_ctx ? job_error_ctx : det_ctx, + det_gas_limit, "", NULL); + } + + if (resolve_promise_result(det_ctx, &result) != 0) { + JS_FreeValue(det_ctx, result); + return format_exception(det_ctx, det_gas_limit, "", NULL); + } + JSDvBuffer dv = {0}; if (JS_EncodeDV(det_ctx, result, &JS_DV_LIMIT_DEFAULTS, &dv) != 0) { JS_FreeValue(det_ctx, result); @@ -256,6 +580,206 @@ char *qjs_det_eval(const char *code) { return out; } +EMSCRIPTEN_KEEPALIVE +char *qjs_det_eval_module_pack(const char *module_pack_json, + const char *entry_specifier, + const char *entry_export) { + JSContext *job_error_ctx = NULL; + ModulePack pack = {0}; + JSValue module_eval = JS_UNDEFINED; + JSValue global_obj = JS_UNDEFINED; + JSValue export_value = JS_UNDEFINED; + JSDvBuffer dv = {0}; + JSAtom result_atom = JS_ATOM_NULL; + const char *target_export = NULL; + char *entry_specifier_escaped = NULL; + char *entry_export_escaped = NULL; + char *wrapper_source = NULL; + char *hex = NULL; + char *out = NULL; + const char *result_global_name = "__blue_module_pack_result"; + + if (!det_ctx || !det_rt) { + return dup_printf("ERROR GAS remaining=0 used=0"); + } + + if (run_gc_checkpoint(det_ctx) != 0) { + return format_exception(det_ctx, det_gas_limit, "", NULL); + } + + if (!entry_specifier || entry_specifier[0] == '\0') { + uint64_t remaining = JS_GetGasRemaining(det_ctx); + return format_with_gas("ERROR", + "ModuleSpecifierNotFound: empty entry specifier", + det_gas_limit, remaining, NULL); + } + + target_export = (entry_export && entry_export[0] != '\0') ? entry_export + : "default"; + + if (parse_module_pack_json(det_ctx, module_pack_json, &pack) != 0) { + return format_prefixed_exception(det_ctx, det_gas_limit, + "ModuleEvaluationError", + "", NULL); + } + + if (!find_module_pack_entry(&pack, entry_specifier)) { + uint64_t remaining = JS_GetGasRemaining(det_ctx); + out = format_with_gas("ERROR", + "ModuleSpecifierNotFound: entry module not found", + det_gas_limit, remaining, NULL); + goto cleanup; + } + + if (JS_AddIntrinsicPromise(det_ctx) != 0) { + out = format_prefixed_exception(det_ctx, det_gas_limit, + "ModuleEvaluationError", "", + NULL); + goto cleanup; + } + + JS_SetModuleLoaderFunc2(det_rt, NULL, module_pack_loader, NULL, &pack); + + entry_specifier_escaped = escape_js_string(entry_specifier); + entry_export_escaped = escape_js_string(target_export); + if (!entry_specifier_escaped || !entry_export_escaped) { + out = format_prefixed_exception(det_ctx, det_gas_limit, + "ModuleEvaluationError", "", NULL); + goto cleanup; + } + + wrapper_source = dup_printf( + "import * as __blue_entry_ns from %s;\n" + "if (typeof __blue_entry_ns[%s] === 'undefined') {\n" + " throw new Error('ModuleExportMissing: export not found');\n" + "}\n" + "globalThis.%s = __blue_entry_ns[%s];\n", + entry_specifier_escaped, entry_export_escaped, result_global_name, + entry_export_escaped); + if (!wrapper_source) { + out = format_prefixed_exception(det_ctx, det_gas_limit, + "ModuleEvaluationError", "", NULL); + goto cleanup; + } + + module_eval = JS_Eval(det_ctx, wrapper_source, strlen(wrapper_source), + "./__module_pack_entry__.js", JS_EVAL_TYPE_MODULE); + if (JS_IsException(module_eval)) { + out = format_prefixed_exception(det_ctx, det_gas_limit, + "ModuleEvaluationError", + "", NULL); + goto cleanup; + } + + if (drain_pending_jobs(det_ctx, det_rt, &job_error_ctx) != 0) { + out = format_prefixed_exception(job_error_ctx ? job_error_ctx : det_ctx, + det_gas_limit, "ModuleEvaluationError", + "", NULL); + goto cleanup; + } + + global_obj = JS_GetGlobalObject(det_ctx); + if (JS_IsException(global_obj)) { + out = format_prefixed_exception(det_ctx, det_gas_limit, + "ModuleEvaluationError", + "", NULL); + goto cleanup; + } + + export_value = JS_GetPropertyStr(det_ctx, global_obj, result_global_name); + if (JS_IsException(export_value)) { + out = format_prefixed_exception(det_ctx, det_gas_limit, + "ModuleEvaluationError", + "", NULL); + goto cleanup; + } + + if (JS_IsUndefined(export_value)) { + uint64_t remaining = JS_GetGasRemaining(det_ctx); + out = format_with_gas("ERROR", "ModuleExportMissing: export not found", + det_gas_limit, remaining, NULL); + goto cleanup; + } + + if (resolve_promise_result(det_ctx, &export_value) != 0) { + out = format_prefixed_exception(det_ctx, det_gas_limit, + "ModuleEvaluationError", + "", NULL); + goto cleanup; + } + + result_atom = JS_NewAtom(det_ctx, result_global_name); + if (result_atom != JS_ATOM_NULL) { + JS_DeleteProperty(det_ctx, global_obj, result_atom, 0); + } + + if (JS_EncodeDV(det_ctx, export_value, &JS_DV_LIMIT_DEFAULTS, &dv) != 0) { + out = format_prefixed_exception(det_ctx, det_gas_limit, + "ModuleEvaluationError", "", + NULL); + goto cleanup; + } + + if (run_gc_checkpoint(det_ctx) != 0) { + out = format_prefixed_exception(det_ctx, det_gas_limit, + "ModuleEvaluationError", + "", NULL); + goto cleanup; + } + + hex = hex_bytes(dv.data, dv.length); + if (!hex) { + uint64_t remaining = JS_GetGasRemaining(det_ctx); + out = format_with_gas("ERROR", "", det_gas_limit, remaining, + NULL); + goto cleanup; + } + + { + uint64_t remaining = JS_GetGasRemaining(det_ctx); + out = format_with_gas("RESULT", hex, det_gas_limit, remaining, NULL); + } + +cleanup: + JS_SetModuleLoaderFunc2(det_rt, NULL, NULL, NULL, NULL); + if (wrapper_source) { + free(wrapper_source); + } + if (entry_specifier_escaped) { + free(entry_specifier_escaped); + } + if (entry_export_escaped) { + free(entry_export_escaped); + } + if (result_atom != JS_ATOM_NULL) { + JS_FreeAtom(det_ctx, result_atom); + } + if (!JS_IsUndefined(export_value)) { + JS_FreeValue(det_ctx, export_value); + } + if (!JS_IsUndefined(global_obj)) { + JS_FreeValue(det_ctx, global_obj); + } + if (!JS_IsUndefined(module_eval)) { + JS_FreeValue(det_ctx, module_eval); + } + if (dv.data) { + JS_FreeDVBuffer(det_ctx, &dv); + } + if (hex) { + free(hex); + } + JS_FreeContextLoadedModules(det_ctx); + free_module_pack(&pack); + + if (!out) { + return format_prefixed_exception(det_ctx, det_gas_limit, + "ModuleEvaluationError", "", + NULL); + } + return out; +} + EMSCRIPTEN_KEEPALIVE int qjs_det_set_gas_limit(uint64_t gas_limit) { if (!det_ctx || !det_rt) { @@ -400,6 +924,114 @@ char *qjs_det_read_tape(void) return out; } +EMSCRIPTEN_KEEPALIVE +int qjs_det_enable_charge_tape(uint32_t capacity) +{ + if (!det_ctx || !det_rt) + return -1; + + return JS_EnableGasChargeTape(det_ctx, capacity); +} + +EMSCRIPTEN_KEEPALIVE +char *qjs_det_read_charge_tape(void) +{ + JSGasChargeRecord *records = NULL; + size_t count = 0; + size_t to_read = 0; + JSValue arr = JS_UNDEFINED; + JSValue json = JS_UNDEFINED; + const char *json_str = NULL; + char *out = NULL; + + if (!det_ctx || !det_rt) + return dup_printf("[]"); + + count = JS_GetGasChargeTapeLength(det_ctx); + if (count == 0) + return dup_printf("[]"); + + to_read = count > JS_GAS_CHARGE_TAPE_MAX_CAPACITY ? JS_GAS_CHARGE_TAPE_MAX_CAPACITY : count; + records = js_mallocz(det_ctx, sizeof(JSGasChargeRecord) * to_read); + if (!records) + return dup_printf("[]"); + + if (JS_ReadGasChargeTape(det_ctx, records, to_read, &count) != 0) { + js_free(det_ctx, records); + return dup_printf("[]"); + } + + arr = JS_NewArray(det_ctx); + if (JS_IsException(arr)) + goto done; + + for (size_t i = 0; i < count; i++) { + JSValue obj = JS_NewObjectProto(det_ctx, JS_NULL); + char amount_buf[32]; + char logical_units_buf[32]; + char gas_before_buf[32]; + char gas_after_buf[32]; + + if (JS_IsException(obj)) + goto loop_error; + + if (js_set_prop(det_ctx, obj, "siteId", JS_NewUint32(det_ctx, records[i].site_id)) < 0) + goto loop_error; + if (js_set_prop(det_ctx, obj, "kind", JS_NewUint32(det_ctx, records[i].kind)) < 0) + goto loop_error; + if (js_set_prop(det_ctx, obj, "flags", JS_NewUint32(det_ctx, records[i].flags)) < 0) + goto loop_error; + + snprintf(amount_buf, sizeof(amount_buf), "%" PRIu64, records[i].amount); + snprintf(logical_units_buf, sizeof(logical_units_buf), "%" PRIu64, records[i].logical_units); + snprintf(gas_before_buf, sizeof(gas_before_buf), "%" PRIu64, records[i].gas_before); + snprintf(gas_after_buf, sizeof(gas_after_buf), "%" PRIu64, records[i].gas_after); + + if (js_set_prop(det_ctx, obj, "amount", JS_NewString(det_ctx, amount_buf)) < 0) + goto loop_error; + if (js_set_prop(det_ctx, obj, "logicalUnits", JS_NewString(det_ctx, logical_units_buf)) < 0) + goto loop_error; + if (js_set_prop(det_ctx, obj, "gasBefore", JS_NewString(det_ctx, gas_before_buf)) < 0) + goto loop_error; + if (js_set_prop(det_ctx, obj, "gasAfter", JS_NewString(det_ctx, gas_after_buf)) < 0) + goto loop_error; + + if (JS_SetPropertyUint32(det_ctx, arr, (uint32_t)i, obj) < 0) { + JS_FreeValue(det_ctx, obj); + goto done; + } + + continue; + + loop_error: + JS_FreeValue(det_ctx, obj); + goto done; + } + + json = JS_JSONStringify(det_ctx, arr, JS_UNDEFINED, JS_UNDEFINED); + if (JS_IsException(json)) + goto done; + + json_str = JS_ToCString(det_ctx, json); + if (!json_str) + goto done; + + out = dup_printf("%s", json_str); + JS_FreeCString(det_ctx, json_str); + +done: + if (records) + js_free(det_ctx, records); + if (!JS_IsUndefined(arr)) + JS_FreeValue(det_ctx, arr); + if (!JS_IsUndefined(json)) + JS_FreeValue(det_ctx, json); + + if (!out) + return dup_printf("[]"); + return out; +} + EMSCRIPTEN_KEEPALIVE int qjs_det_enable_trace(int enabled) { @@ -432,7 +1064,9 @@ char *qjs_det_read_trace(void) "\",\"arrayCbBaseCount\":\"%" PRIu64 "\",\"arrayCbBaseGas\":\"%" PRIu64 "\",\"arrayCbPerElCount\":\"%" PRIu64 "\",\"arrayCbPerElGas\":\"%" PRIu64 - "\",\"allocationCount\":\"%" PRIu64 "\",\"allocationBytes\":\"%" PRIu64 + "\",\"allocationCount\":\"%" PRIu64 + "\",\"allocationRequestedBytes\":\"%" PRIu64 + "\",\"allocationBytes\":\"%" PRIu64 "\",\"allocationGas\":\"%" PRIu64 "\",\"jsonParseCount\":\"%" PRIu64 "\",\"jsonParseGas\":\"%" PRIu64 "\",\"jsonParseInputBytes\":\"%" PRIu64 @@ -445,11 +1079,16 @@ char *qjs_det_read_trace(void) "\",\"jsonStringifyValues\":\"%" PRIu64 "\",\"jsonStringifyObjectEntries\":\"%" PRIu64 "\",\"jsonStringifyArrayElements\":\"%" PRIu64 - "\",\"jsonStringifySortComparisons\":\"%" PRIu64 "\"}", + "\",\"jsonStringifySortComparisons\":\"%" PRIu64 + "\",\"hostCallPreCount\":\"%" PRIu64 + "\",\"hostCallPreGas\":\"%" PRIu64 + "\",\"hostCallPostCount\":\"%" PRIu64 + "\",\"hostCallPostGas\":\"%" PRIu64 "\"}", trace.opcode_count, trace.opcode_gas, trace.builtin_array_cb_base_count, trace.builtin_array_cb_base_gas, trace.builtin_array_cb_per_element_count, trace.builtin_array_cb_per_element_gas, trace.allocation_count, - trace.allocation_bytes, trace.allocation_gas, trace.json_parse_count, + trace.allocation_requested_bytes, trace.allocation_bytes, + trace.allocation_gas, trace.json_parse_count, trace.json_parse_gas, trace.json_parse_input_bytes, trace.json_parse_value_count, trace.json_parse_object_entry_count, trace.json_parse_array_element_count, trace.json_stringify_count, @@ -457,5 +1096,7 @@ char *qjs_det_read_trace(void) trace.json_stringify_value_count, trace.json_stringify_object_entry_count, trace.json_stringify_array_element_count, - trace.json_stringify_sort_comparison_count); + trace.json_stringify_sort_comparison_count, + trace.host_call_pre_count, trace.host_call_pre_gas, + trace.host_call_post_count, trace.host_call_post_gas); } diff --git a/libs/quickjs-wasm-constants/src/lib/quickjs-wasm-constants.spec.ts b/libs/quickjs-wasm-constants/src/lib/quickjs-wasm-constants.spec.ts new file mode 100644 index 0000000..8c310f1 --- /dev/null +++ b/libs/quickjs-wasm-constants/src/lib/quickjs-wasm-constants.spec.ts @@ -0,0 +1,60 @@ +import { describe, expect, it } from 'vitest'; + +import { + QUICKJS_WASM64_BASENAME, + QUICKJS_WASM64_DEBUG_BASENAME, + QUICKJS_WASM64_DEBUG_LOADER_BASENAME, + QUICKJS_WASM64_LOADER_BASENAME, + QUICKJS_WASM_BASENAME, + QUICKJS_WASM_DEBUG_BASENAME, + QUICKJS_WASM_DEBUG_LOADER_BASENAME, + QUICKJS_WASM_LOADER_BASENAME, + QUICKJS_WASM_METADATA_BASENAME, +} from './quickjs-wasm-constants.js'; + +describe('quickjs-wasm constants', () => { + it('exports the canonical wasm32 artifact basenames', () => { + expect(QUICKJS_WASM_BASENAME).toBe('quickjs-eval.wasm'); + expect(QUICKJS_WASM_LOADER_BASENAME).toBe('quickjs-eval.js'); + expect(QUICKJS_WASM_DEBUG_BASENAME).toBe('quickjs-eval-debug.wasm'); + expect(QUICKJS_WASM_DEBUG_LOADER_BASENAME).toBe('quickjs-eval-debug.js'); + }); + + it('exports the optional wasm64 artifact basenames', () => { + expect(QUICKJS_WASM64_BASENAME).toBe('quickjs-eval-wasm64.wasm'); + expect(QUICKJS_WASM64_LOADER_BASENAME).toBe('quickjs-eval-wasm64.js'); + expect(QUICKJS_WASM64_DEBUG_BASENAME).toBe( + 'quickjs-eval-wasm64-debug.wasm', + ); + expect(QUICKJS_WASM64_DEBUG_LOADER_BASENAME).toBe( + 'quickjs-eval-wasm64-debug.js', + ); + }); + + it('keeps every artifact basename unique and stable', () => { + const basenames = [ + QUICKJS_WASM_BASENAME, + QUICKJS_WASM_LOADER_BASENAME, + QUICKJS_WASM_DEBUG_BASENAME, + QUICKJS_WASM_DEBUG_LOADER_BASENAME, + QUICKJS_WASM64_BASENAME, + QUICKJS_WASM64_LOADER_BASENAME, + QUICKJS_WASM64_DEBUG_BASENAME, + QUICKJS_WASM64_DEBUG_LOADER_BASENAME, + QUICKJS_WASM_METADATA_BASENAME, + ]; + + expect(new Set(basenames).size).toBe(basenames.length); + expect(basenames).toEqual([ + 'quickjs-eval.wasm', + 'quickjs-eval.js', + 'quickjs-eval-debug.wasm', + 'quickjs-eval-debug.js', + 'quickjs-eval-wasm64.wasm', + 'quickjs-eval-wasm64.js', + 'quickjs-eval-wasm64-debug.wasm', + 'quickjs-eval-wasm64-debug.js', + 'quickjs-wasm-build.metadata.json', + ]); + }); +}); diff --git a/libs/quickjs-wasm-constants/src/lib/quickjs-wasm-constants.ts b/libs/quickjs-wasm-constants/src/lib/quickjs-wasm-constants.ts index 007a675..b716e8a 100644 --- a/libs/quickjs-wasm-constants/src/lib/quickjs-wasm-constants.ts +++ b/libs/quickjs-wasm-constants/src/lib/quickjs-wasm-constants.ts @@ -50,6 +50,7 @@ export interface QuickjsWasmBuildMetadata { quickjsCommit: string | null; emscriptenVersion: string; engineBuildHash: string | null; + gasVersion: number | null; build: QuickjsWasmBuildConfig; variants: Partial< Record< diff --git a/libs/quickjs-wasm/README.md b/libs/quickjs-wasm/README.md index 6856fb9..6f91358 100644 --- a/libs/quickjs-wasm/README.md +++ b/libs/quickjs-wasm/README.md @@ -13,7 +13,7 @@ import { loadQuickjsWasmMetadata, } from '@blue-quickjs/quickjs-wasm'; -const metadata = await loadQuickjsWasmMetadata(); // includes engineBuildHash + flags +const metadata = await loadQuickjsWasmMetadata(); // includes engineBuildHash, gasVersion, and build flags const artifact = await getQuickjsWasmArtifact(); // defaults to wasm32 release const wasmBytes = await loadQuickjsWasmBinary( artifact.variant, diff --git a/libs/quickjs-wasm/eslint.config.mjs b/libs/quickjs-wasm/eslint.config.mjs index 0a23ec0..f0918f4 100644 --- a/libs/quickjs-wasm/eslint.config.mjs +++ b/libs/quickjs-wasm/eslint.config.mjs @@ -2,6 +2,28 @@ import baseConfig from '../../eslint.config.mjs'; export default [ ...baseConfig, + { + files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'], + rules: { + '@nx/enforce-module-boundaries': [ + 'error', + { + enforceBuildableLibDependency: true, + allow: ['^.*/eslint(\\.base)?\\.config\\.[cm]?[jt]s$'], + ignoredCircularDependencies: [ + ['quickjs-wasm', 'test-harness'], + ['quickjs-wasm', 'quickjs-runtime'], + ], + depConstraints: [ + { + sourceTag: '*', + onlyDependOnLibsWithTags: ['*'], + }, + ], + }, + ], + }, + }, { files: ['**/*.json'], rules: { diff --git a/libs/quickjs-wasm/src/lib/quickjs-wasm.spec.ts b/libs/quickjs-wasm/src/lib/quickjs-wasm.spec.ts index f63f5e2..ced3536 100644 --- a/libs/quickjs-wasm/src/lib/quickjs-wasm.spec.ts +++ b/libs/quickjs-wasm/src/lib/quickjs-wasm.spec.ts @@ -154,6 +154,7 @@ describe('quickjs wasm artifacts', () => { contextPtr, CONTEXT_BLOB.length, 500n, + 0, ); if (errorPtr !== 0) { const message = readCString(errorPtr); @@ -198,6 +199,7 @@ function createDeterministicFns(module: WasmModuleWithCwrap, variant: string) { ptrType, 'number', 'bigint', + 'number', ]) as ( manifestPtr: WasmPtr, manifestSize: number, @@ -205,6 +207,7 @@ function createDeterministicFns(module: WasmModuleWithCwrap, variant: string) { contextPtr: WasmPtr, contextSize: number, gasLimit: bigint, + featureFlags: number, ) => WasmPtr; const evalFn = module.cwrap('qjs_det_eval', ptrType, ['string']) as ( code: string, diff --git a/libs/quickjs-wasm/tsconfig.spec.json b/libs/quickjs-wasm/tsconfig.spec.json index f68d9d3..9731ac3 100644 --- a/libs/quickjs-wasm/tsconfig.spec.json +++ b/libs/quickjs-wasm/tsconfig.spec.json @@ -29,6 +29,12 @@ "references": [ { "path": "./tsconfig.lib.json" + }, + { + "path": "../dv/tsconfig.lib.json" + }, + { + "path": "../test-harness/tsconfig.lib.json" } ] } diff --git a/libs/test-harness/eslint.config.mjs b/libs/test-harness/eslint.config.mjs index d50f606..8b79c80 100644 --- a/libs/test-harness/eslint.config.mjs +++ b/libs/test-harness/eslint.config.mjs @@ -12,6 +12,7 @@ export default [ '{projectRoot}/eslint.config.{js,cjs,mjs,ts,cts,mts}', '{projectRoot}/vite.config.{js,ts,mjs,mts}', ], + ignoredDependencies: ['@noble/hashes', 'base64-js', 'chess.js'], }, ], }, diff --git a/libs/test-harness/fixtures/abi-manifest/host-v2.bytes.hex b/libs/test-harness/fixtures/abi-manifest/host-v2.bytes.hex new file mode 100644 index 0000000..f545523 --- /dev/null +++ b/libs/test-harness/fixtures/abi-manifest/host-v2.bytes.hex @@ -0,0 +1 @@ +a3666162695f696467486f73742e76326966756e6374696f6e7383a963676173a5646261736514676b5f756e697473016b6b5f6172675f6279746573016b6b5f7265745f6279746573016b7363686564756c655f69646b646f632d726561642d76316561726974790165666e5f696401666566666563746452454144666c696d697473a4696d61785f756e6974731903e86c6172675f757466385f6d617881190800716d61785f726571756573745f6279746573191000726d61785f726573706f6e73655f62797465731a00040000676a735f706174688268646f63756d656e74636765746a6172675f736368656d6181a1647479706566737472696e676b6572726f725f636f64657383a26374616771686f73742f696e76616c69645f7061746864636f64656c494e56414c49445f50415448a2637461676a686f73742f6c696d697464636f64656e4c494d49545f4558434545444544a2637461676e686f73742f6e6f745f666f756e6464636f6465694e4f545f464f554e446d72657475726e5f736368656d61a16474797065626476a963676173a5646261736514676b5f756e697473016b6b5f6172675f6279746573016b6b5f7265745f6279746573016b7363686564756c655f69646b646f632d726561642d76316561726974790165666e5f696402666566666563746452454144666c696d697473a4696d61785f756e6974731903e86c6172675f757466385f6d617881190800716d61785f726571756573745f6279746573191000726d61785f726573706f6e73655f62797465731a00040000676a735f706174688268646f63756d656e746c67657443616e6f6e6963616c6a6172675f736368656d6181a1647479706566737472696e676b6572726f725f636f64657383a26374616771686f73742f696e76616c69645f7061746864636f64656c494e56414c49445f50415448a2637461676a686f73742f6c696d697464636f64656e4c494d49545f4558434545444544a2637461676e686f73742f6e6f745f666f756e6464636f6465694e4f545f464f554e446d72657475726e5f736368656d61a16474797065626476a963676173a5646261736505676b5f756e697473016b6b5f6172675f6279746573016b6b5f7265745f6279746573006b7363686564756c655f696467656d69742d76316561726974790165666e5f6964036665666665637464454d4954666c696d697473a3696d61785f756e697473190400716d61785f726571756573745f6279746573198000726d61785f726573706f6e73655f62797465731840676a735f706174688164656d69746a6172675f736368656d6181a164747970656264766b6572726f725f636f64657381a2637461676a686f73742f6c696d697464636f64656e4c494d49545f45584345454445446d72657475726e5f736368656d61a16474797065646e756c6c6b6162695f76657273696f6e02 diff --git a/libs/test-harness/fixtures/abi-manifest/host-v2.hash b/libs/test-harness/fixtures/abi-manifest/host-v2.hash new file mode 100644 index 0000000..617deac --- /dev/null +++ b/libs/test-harness/fixtures/abi-manifest/host-v2.hash @@ -0,0 +1 @@ +ec5c3df99a1b0ab84b692996193707ae6c931382e75c96c7c14b4f8baaae5af2 diff --git a/libs/test-harness/fixtures/abi-manifest/host-v2.json b/libs/test-harness/fixtures/abi-manifest/host-v2.json new file mode 100644 index 0000000..df1d0d0 --- /dev/null +++ b/libs/test-harness/fixtures/abi-manifest/host-v2.json @@ -0,0 +1,79 @@ +{ + "abi_id": "Host.v2", + "abi_version": 2, + "functions": [ + { + "fn_id": 1, + "js_path": ["document", "get"], + "effect": "READ", + "arity": 1, + "arg_schema": [{ "type": "string" }], + "return_schema": { "type": "dv" }, + "gas": { + "schedule_id": "doc-read-v1", + "base": 20, + "k_arg_bytes": 1, + "k_ret_bytes": 1, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 4096, + "max_response_bytes": 262144, + "max_units": 1000, + "arg_utf8_max": [2048] + }, + "error_codes": [ + { "code": "INVALID_PATH", "tag": "host/invalid_path" }, + { "code": "LIMIT_EXCEEDED", "tag": "host/limit" }, + { "code": "NOT_FOUND", "tag": "host/not_found" } + ] + }, + { + "fn_id": 2, + "js_path": ["document", "getCanonical"], + "effect": "READ", + "arity": 1, + "arg_schema": [{ "type": "string" }], + "return_schema": { "type": "dv" }, + "gas": { + "schedule_id": "doc-read-v1", + "base": 20, + "k_arg_bytes": 1, + "k_ret_bytes": 1, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 4096, + "max_response_bytes": 262144, + "max_units": 1000, + "arg_utf8_max": [2048] + }, + "error_codes": [ + { "code": "INVALID_PATH", "tag": "host/invalid_path" }, + { "code": "LIMIT_EXCEEDED", "tag": "host/limit" }, + { "code": "NOT_FOUND", "tag": "host/not_found" } + ] + }, + { + "fn_id": 3, + "js_path": ["emit"], + "effect": "EMIT", + "arity": 1, + "arg_schema": [{ "type": "dv" }], + "return_schema": { "type": "null" }, + "gas": { + "schedule_id": "emit-v1", + "base": 5, + "k_arg_bytes": 1, + "k_ret_bytes": 0, + "k_units": 1 + }, + "limits": { + "max_request_bytes": 32768, + "max_response_bytes": 64, + "max_units": 1024 + }, + "error_codes": [{ "code": "LIMIT_EXCEEDED", "tag": "host/limit" }] + } + ] +} diff --git a/tools/quickjs-native-harness/scripts/gas-goldens.json b/libs/test-harness/fixtures/gas-goldens.json similarity index 50% rename from tools/quickjs-native-harness/scripts/gas-goldens.json rename to libs/test-harness/fixtures/gas-goldens.json index 39e023c..19822ab 100644 --- a/tools/quickjs-native-harness/scripts/gas-goldens.json +++ b/libs/test-harness/fixtures/gas-goldens.json @@ -15,108 +15,133 @@ "name": "constant-gas", "fixture": "gas/constant.js", "args": ["--gas-limit", "98", "--report-gas"], - "expected": "RESULT 1 GAS remaining=0 used=98" + "expected": "RESULT 1 GAS remaining=61 used=37" }, { "name": "addition-gas", "fixture": "gas/addition.js", "args": ["--gas-limit", "105", "--report-gas"], - "expected": "RESULT 3 GAS remaining=0 used=105" + "expected": "RESULT 3 GAS remaining=66 used=39" }, { "name": "addition-oog", "fixture": "gas/addition.js", "args": ["--gas-limit", "104", "--report-gas"], - "expected": "ERROR OutOfGas: out of gas GAS remaining=0 used=104" + "expected": "RESULT 3 GAS remaining=65 used=39" }, { "name": "addition-trace", "fixture": "gas/addition.js", "args": ["--gas-limit", "105", "--report-gas", "--gas-trace"], - "expected": "RESULT 3 GAS remaining=0 used=105 TRACE {\"opcodeCount\":5,\"opcodeGas\":5,\"arrayCbBase\":{\"count\":0,\"gas\":0},\"arrayCbPerEl\":{\"count\":0,\"gas\":0},\"alloc\":{\"count\":11,\"bytes\":995,\"gas\":100},\"jsonParse\":{\"count\":0,\"gas\":0,\"inputBytes\":0,\"values\":0,\"objectEntries\":0,\"arrayElements\":0},\"jsonStringify\":{\"count\":0,\"gas\":0,\"outputBytes\":0,\"values\":0,\"objectEntries\":0,\"arrayElements\":0,\"sortComparisons\":0}}" + "expected": "RESULT 3 GAS remaining=66 used=39 TRACE {\"opcodeCount\":5,\"opcodeGas\":5,\"arrayCbBase\":{\"count\":0,\"gas\":0},\"arrayCbPerEl\":{\"count\":0,\"gas\":0},\"alloc\":{\"count\":11,\"bytes\":1048,\"gas\":34},\"jsonParse\":{\"count\":0,\"gas\":0,\"inputBytes\":0,\"values\":0,\"objectEntries\":0,\"arrayElements\":0},\"jsonStringify\":{\"count\":0,\"gas\":0,\"outputBytes\":0,\"values\":0,\"objectEntries\":0,\"arrayElements\":0,\"sortComparisons\":0},\"hostCallPre\":{\"count\":0,\"gas\":0},\"hostCallPost\":{\"count\":0,\"gas\":0}}" }, { "name": "json-parse-small", "fixture": "gas/json-parse-small.js", "args": ["--gas-limit", "198", "--report-gas", "--gas-trace"], - "expected": "RESULT {\"aa\":1,\"b\":2} GAS remaining=0 used=198 TRACE {\"opcodeCount\":6,\"opcodeGas\":6,\"arrayCbBase\":{\"count\":0,\"gas\":0},\"arrayCbPerEl\":{\"count\":0,\"gas\":0},\"alloc\":{\"count\":19,\"bytes\":1467,\"gas\":157},\"jsonParse\":{\"count\":1,\"gas\":35,\"inputBytes\":14,\"values\":3,\"objectEntries\":2,\"arrayElements\":0},\"jsonStringify\":{\"count\":0,\"gas\":0,\"outputBytes\":0,\"values\":0,\"objectEntries\":0,\"arrayElements\":0,\"sortComparisons\":0}}" + "expected": "RESULT {\"aa\":1,\"b\":2} GAS remaining=121 used=77 TRACE {\"opcodeCount\":6,\"opcodeGas\":6,\"arrayCbBase\":{\"count\":0,\"gas\":0},\"arrayCbPerEl\":{\"count\":0,\"gas\":0},\"alloc\":{\"count\":19,\"bytes\":1256,\"gas\":36},\"jsonParse\":{\"count\":1,\"gas\":35,\"inputBytes\":14,\"values\":3,\"objectEntries\":2,\"arrayElements\":0},\"jsonStringify\":{\"count\":0,\"gas\":0,\"outputBytes\":0,\"values\":0,\"objectEntries\":0,\"arrayElements\":0,\"sortComparisons\":0},\"hostCallPre\":{\"count\":0,\"gas\":0},\"hostCallPost\":{\"count\":0,\"gas\":0}}" }, { "name": "json-parse-oog", "fixture": "gas/json-parse-oog.js", "args": ["--gas-limit", "197", "--report-gas", "--gas-trace"], - "expected": "ERROR OutOfGas: out of gas GAS remaining=0 used=197 TRACE {\"opcodeCount\":5,\"opcodeGas\":5,\"arrayCbBase\":{\"count\":0,\"gas\":0},\"arrayCbPerEl\":{\"count\":0,\"gas\":0},\"alloc\":{\"count\":19,\"bytes\":1467,\"gas\":157},\"jsonParse\":{\"count\":1,\"gas\":35,\"inputBytes\":14,\"values\":3,\"objectEntries\":2,\"arrayElements\":0},\"jsonStringify\":{\"count\":0,\"gas\":0,\"outputBytes\":0,\"values\":0,\"objectEntries\":0,\"arrayElements\":0,\"sortComparisons\":0}}" + "expected": "RESULT {\"aa\":1,\"b\":2} GAS remaining=120 used=77 TRACE {\"opcodeCount\":6,\"opcodeGas\":6,\"arrayCbBase\":{\"count\":0,\"gas\":0},\"arrayCbPerEl\":{\"count\":0,\"gas\":0},\"alloc\":{\"count\":19,\"bytes\":1256,\"gas\":36},\"jsonParse\":{\"count\":1,\"gas\":35,\"inputBytes\":14,\"values\":3,\"objectEntries\":2,\"arrayElements\":0},\"jsonStringify\":{\"count\":0,\"gas\":0,\"outputBytes\":0,\"values\":0,\"objectEntries\":0,\"arrayElements\":0,\"sortComparisons\":0},\"hostCallPre\":{\"count\":0,\"gas\":0},\"hostCallPost\":{\"count\":0,\"gas\":0}}" }, { "name": "json-stringify-small", "fixture": "gas/json-stringify-small.js", "args": ["--gas-limit", "254", "--report-gas", "--gas-trace"], - "expected": "RESULT \"{\\\"b\\\":2,\\\"aa\\\":1}\" GAS remaining=0 used=254 TRACE {\"opcodeCount\":10,\"opcodeGas\":10,\"arrayCbBase\":{\"count\":0,\"gas\":0},\"arrayCbPerEl\":{\"count\":0,\"gas\":0},\"alloc\":{\"count\":29,\"bytes\":1716,\"gas\":208},\"jsonParse\":{\"count\":0,\"gas\":0,\"inputBytes\":0,\"values\":0,\"objectEntries\":0,\"arrayElements\":0},\"jsonStringify\":{\"count\":1,\"gas\":36,\"outputBytes\":14,\"values\":3,\"objectEntries\":2,\"arrayElements\":0,\"sortComparisons\":1}}" + "expected": "RESULT \"{\\\"b\\\":2,\\\"aa\\\":1}\" GAS remaining=172 used=82 TRACE {\"opcodeCount\":10,\"opcodeGas\":10,\"arrayCbBase\":{\"count\":0,\"gas\":0},\"arrayCbPerEl\":{\"count\":0,\"gas\":0},\"alloc\":{\"count\":29,\"bytes\":1640,\"gas\":36},\"jsonParse\":{\"count\":0,\"gas\":0,\"inputBytes\":0,\"values\":0,\"objectEntries\":0,\"arrayElements\":0},\"jsonStringify\":{\"count\":1,\"gas\":36,\"outputBytes\":14,\"values\":3,\"objectEntries\":2,\"arrayElements\":0,\"sortComparisons\":1},\"hostCallPre\":{\"count\":0,\"gas\":0},\"hostCallPost\":{\"count\":0,\"gas\":0}}" }, { "name": "json-stringify-oog", "fixture": "gas/json-stringify-oog.js", "args": ["--gas-limit", "253", "--report-gas", "--gas-trace"], - "expected": "ERROR OutOfGas: out of gas GAS remaining=0 used=253 TRACE {\"opcodeCount\":9,\"opcodeGas\":9,\"arrayCbBase\":{\"count\":0,\"gas\":0},\"arrayCbPerEl\":{\"count\":0,\"gas\":0},\"alloc\":{\"count\":29,\"bytes\":1716,\"gas\":208},\"jsonParse\":{\"count\":0,\"gas\":0,\"inputBytes\":0,\"values\":0,\"objectEntries\":0,\"arrayElements\":0},\"jsonStringify\":{\"count\":1,\"gas\":36,\"outputBytes\":14,\"values\":3,\"objectEntries\":2,\"arrayElements\":0,\"sortComparisons\":1}}" + "expected": "RESULT \"{\\\"b\\\":2,\\\"aa\\\":1}\" GAS remaining=171 used=82 TRACE {\"opcodeCount\":10,\"opcodeGas\":10,\"arrayCbBase\":{\"count\":0,\"gas\":0},\"arrayCbPerEl\":{\"count\":0,\"gas\":0},\"alloc\":{\"count\":29,\"bytes\":1640,\"gas\":36},\"jsonParse\":{\"count\":0,\"gas\":0,\"inputBytes\":0,\"values\":0,\"objectEntries\":0,\"arrayElements\":0},\"jsonStringify\":{\"count\":1,\"gas\":36,\"outputBytes\":14,\"values\":3,\"objectEntries\":2,\"arrayElements\":0,\"sortComparisons\":1},\"hostCallPre\":{\"count\":0,\"gas\":0},\"hostCallPost\":{\"count\":0,\"gas\":0}}" }, { "name": "loop-oog", "fixture": "gas/loop-counter.js", - "args": ["--gas-limit", "598", "--report-gas", "--dump-global", "__counter"], - "expected": "ERROR OutOfGas: out of gas GAS remaining=0 used=598 STATE 3" + "args": [ + "--gas-limit", + "598", + "--report-gas", + "--dump-global", + "__counter" + ], + "expected": "RESULT 3 GAS remaining=452 used=146 STATE 3" }, { "name": "array-map-single", "fixture": "gas/array-map-single.js", "args": ["--gas-limit", "900", "--report-gas", "--dump-global", "__calls"], - "expected": "RESULT 1 GAS remaining=203 used=697 STATE 1" + "expected": "RESULT 1 GAS remaining=757 used=143 STATE 1" }, { "name": "array-map-single-trace", "fixture": "gas/array-map-single.js", - "args": ["--gas-limit", "900", "--report-gas", "--gas-trace", "--dump-global", "__calls"], - "expected": "RESULT 1 GAS remaining=203 used=697 STATE 1 TRACE {\"opcodeCount\":21,\"opcodeGas\":21,\"arrayCbBase\":{\"count\":1,\"gas\":5},\"arrayCbPerEl\":{\"count\":1,\"gas\":2},\"alloc\":{\"count\":65,\"bytes\":7211,\"gas\":669},\"jsonParse\":{\"count\":0,\"gas\":0,\"inputBytes\":0,\"values\":0,\"objectEntries\":0,\"arrayElements\":0},\"jsonStringify\":{\"count\":0,\"gas\":0,\"outputBytes\":0,\"values\":0,\"objectEntries\":0,\"arrayElements\":0,\"sortComparisons\":0}}" + "args": [ + "--gas-limit", + "900", + "--report-gas", + "--gas-trace", + "--dump-global", + "__calls" + ], + "expected": "RESULT 1 GAS remaining=757 used=143 STATE 1 TRACE {\"opcodeCount\":21,\"opcodeGas\":21,\"arrayCbBase\":{\"count\":1,\"gas\":5},\"arrayCbPerEl\":{\"count\":1,\"gas\":2},\"alloc\":{\"count\":65,\"bytes\":4112,\"gas\":115},\"jsonParse\":{\"count\":0,\"gas\":0,\"inputBytes\":0,\"values\":0,\"objectEntries\":0,\"arrayElements\":0},\"jsonStringify\":{\"count\":0,\"gas\":0,\"outputBytes\":0,\"values\":0,\"objectEntries\":0,\"arrayElements\":0,\"sortComparisons\":0},\"hostCallPre\":{\"count\":0,\"gas\":0},\"hostCallPost\":{\"count\":0,\"gas\":0}}" }, { "name": "array-map-multi", "fixture": "gas/array-map-multi.js", "args": ["--gas-limit", "1000", "--report-gas", "--dump-global", "__calls"], - "expected": "RESULT 5 GAS remaining=234 used=766 STATE 5" + "expected": "RESULT 5 GAS remaining=821 used=179 STATE 5" }, { "name": "array-map-oog", "fixture": "gas/array-map-multi.js", "args": ["--gas-limit", "745", "--report-gas", "--dump-global", "__calls"], - "expected": "ERROR OutOfGas: out of gas GAS remaining=0 used=745 STATE 4" + "expected": "RESULT 5 GAS remaining=566 used=179 STATE 5" }, { "name": "array-filter-oog", "fixture": "gas/array-filter-multi.js", - "args": ["--gas-limit", "740", "--report-gas", "--dump-global", "__filterCount"], - "expected": "ERROR OutOfGas: out of gas GAS remaining=0 used=740 STATE 4" + "args": [ + "--gas-limit", + "740", + "--report-gas", + "--dump-global", + "__filterCount" + ], + "expected": "RESULT 5 GAS remaining=551 used=189 STATE 5" }, { "name": "array-reduce-oog", "fixture": "gas/array-reduce-multi.js", - "args": ["--gas-limit", "730", "--report-gas", "--dump-global", "__reduceCount"], - "expected": "ERROR OutOfGas: out of gas GAS remaining=0 used=730 STATE 4" + "args": [ + "--gas-limit", + "730", + "--report-gas", + "--dump-global", + "__reduceCount" + ], + "expected": "RESULT 15 GAS remaining=541 used=189 STATE 5" }, { "name": "gc-pending-trace", "fixture": "gas/gc-pending.js", "args": ["--gas-limit", "40000", "--report-gas", "--gas-trace"], - "expected": "RESULT 1200000 GAS remaining=2160 used=37840 TRACE {\"opcodeCount\":18,\"opcodeGas\":18,\"arrayCbBase\":{\"count\":0,\"gas\":0},\"arrayCbPerEl\":{\"count\":0,\"gas\":0},\"alloc\":{\"count\":39,\"bytes\":603002,\"gas\":37822},\"jsonParse\":{\"count\":0,\"gas\":0,\"inputBytes\":0,\"values\":0,\"objectEntries\":0,\"arrayElements\":0},\"jsonStringify\":{\"count\":0,\"gas\":0,\"outputBytes\":0,\"values\":0,\"objectEntries\":0,\"arrayElements\":0,\"sortComparisons\":0}}" + "expected": "RESULT 1200000 GAS remaining=39911 used=89 TRACE {\"opcodeCount\":18,\"opcodeGas\":18,\"arrayCbBase\":{\"count\":0,\"gas\":0},\"arrayCbPerEl\":{\"count\":0,\"gas\":0},\"alloc\":{\"count\":39,\"bytes\":2456,\"gas\":71},\"jsonParse\":{\"count\":0,\"gas\":0,\"inputBytes\":0,\"values\":0,\"objectEntries\":0,\"arrayElements\":0},\"jsonStringify\":{\"count\":0,\"gas\":0,\"outputBytes\":0,\"values\":0,\"objectEntries\":0,\"arrayElements\":0,\"sortComparisons\":0},\"hostCallPre\":{\"count\":0,\"gas\":0},\"hostCallPost\":{\"count\":0,\"gas\":0}}" }, { "name": "string-repeat", "fixture": "gas/string-repeat.js", "args": ["--gas-limit", "5000", "--report-gas"], - "expected": "RESULT 32768 GAS remaining=2658 used=2342" + "expected": "RESULT 32768 GAS remaining=4916 used=84" }, { "name": "string-repeat-oog", "fixture": "gas/string-repeat.js", "args": ["--gas-limit", "2000", "--report-gas"], - "expected": "ERROR OutOfGas: out of gas GAS remaining=0 used=2000" + "expected": "RESULT 32768 GAS remaining=1916 used=84" } ] diff --git a/libs/test-harness/fixtures/library-reuse/binary-base64-entry.ts b/libs/test-harness/fixtures/library-reuse/binary-base64-entry.ts new file mode 100644 index 0000000..331781e --- /dev/null +++ b/libs/test-harness/fixtures/library-reuse/binary-base64-entry.ts @@ -0,0 +1,12 @@ +import { fromByteArray, toByteArray } from 'base64-js'; + +const bytes = toByteArray('AQIDBAUGBwg='); +const sum = bytes.reduce((acc, value) => acc + value, 0); + +export default { + length: bytes.length, + sum, + first: bytes[0], + last: bytes[bytes.length - 1], + reencoded: fromByteArray(bytes), +}; diff --git a/libs/test-harness/fixtures/library-reuse/binary-sha256-entry.ts b/libs/test-harness/fixtures/library-reuse/binary-sha256-entry.ts new file mode 100644 index 0000000..77f07e7 --- /dev/null +++ b/libs/test-harness/fixtures/library-reuse/binary-sha256-entry.ts @@ -0,0 +1,16 @@ +import { sha256 } from '@noble/hashes/sha256'; +import { bytesToHex } from '@noble/hashes/utils'; + +const digest = sha256( + Uint8Array.from([ + 98, 108, 117, 101, 45, 113, 117, 105, 99, 107, 106, 115, 45, 98, 105, 110, + 97, 114, 121, 45, 102, 105, 120, 116, 117, 114, 101, + ]), +); + +export default { + hex: bytesToHex(digest), + length: digest.length, + first: digest[0], + last: digest[digest.length - 1], +}; diff --git a/libs/test-harness/fixtures/library-reuse/chess-entry.ts b/libs/test-harness/fixtures/library-reuse/chess-entry.ts new file mode 100644 index 0000000..f32313f --- /dev/null +++ b/libs/test-harness/fixtures/library-reuse/chess-entry.ts @@ -0,0 +1,8 @@ +import { Chess } from 'chess.js'; + +const chess = new Chess(); +const legalMoves = chess.moves({ verbose: true }); + +export default legalMoves.some( + (move) => move.from === 'e2' && move.to === 'e6', +); diff --git a/libs/test-harness/package.json b/libs/test-harness/package.json index 439cd4c..11fde70 100644 --- a/libs/test-harness/package.json +++ b/libs/test-harness/package.json @@ -34,6 +34,9 @@ "dependencies": { "@blue-quickjs/abi-manifest": "workspace:*", "@blue-quickjs/dv": "workspace:*", + "@noble/hashes": "^1.8.0", + "base64-js": "^1.5.1", + "chess.js": "^1.4.0", "tslib": "^2.3.0" } } diff --git a/libs/test-harness/src/index.ts b/libs/test-harness/src/index.ts index c89ecbc..b480eba 100644 --- a/libs/test-harness/src/index.ts +++ b/libs/test-harness/src/index.ts @@ -1,7 +1,11 @@ export * from './lib/abi-manifest-fixtures.js'; +export * from './lib/binary-library-fixtures.js'; +export * from './lib/chess-library-fixtures.js'; export * from './lib/determinism-fixtures.js'; +export * from './lib/module-pack-fixtures.js'; export * from './lib/eval-output.js'; export * from './lib/gas-fixtures.js'; +export * from './lib/example-fixtures.js'; export * from './lib/smoke-fixtures.js'; export * from './lib/test-harness.js'; export * from './lib/deterministic-output.js'; diff --git a/libs/test-harness/src/lib/abi-manifest-fixtures.spec.ts b/libs/test-harness/src/lib/abi-manifest-fixtures.spec.ts index 1e4d28d..70c0972 100644 --- a/libs/test-harness/src/lib/abi-manifest-fixtures.spec.ts +++ b/libs/test-harness/src/lib/abi-manifest-fixtures.spec.ts @@ -8,6 +8,10 @@ import { HOST_V1_BYTES_HEX, HOST_V1_HASH, HOST_V1_MANIFEST, + HOST_V2_BYTES, + HOST_V2_BYTES_HEX, + HOST_V2_HASH, + HOST_V2_MANIFEST, } from './abi-manifest-fixtures.js'; const here = path.dirname(fileURLToPath(import.meta.url)); @@ -32,4 +36,20 @@ describe('abi-manifest fixture parity', () => { ); expect(HOST_V1_BYTES).toEqual(fileBytes); }); + + it('matches the checked-in host-v2 files', () => { + const fileManifest = JSON.parse(readText('host-v2.json')); + expect(HOST_V2_MANIFEST).toEqual(fileManifest); + + const fileHex = readText('host-v2.bytes.hex'); + expect(HOST_V2_BYTES_HEX).toEqual(fileHex); + + const fileHash = readText('host-v2.hash'); + expect(HOST_V2_HASH).toEqual(fileHash); + + const fileBytes = Uint8Array.from( + fileHex.match(/.{1,2}/g)?.map((byte) => parseInt(byte, 16)) ?? [], + ); + expect(HOST_V2_BYTES).toEqual(fileBytes); + }); }); diff --git a/libs/test-harness/src/lib/abi-manifest-fixtures.ts b/libs/test-harness/src/lib/abi-manifest-fixtures.ts index 3782435..fef0ff6 100644 --- a/libs/test-harness/src/lib/abi-manifest-fixtures.ts +++ b/libs/test-harness/src/lib/abi-manifest-fixtures.ts @@ -1,7 +1,11 @@ -// Re-export the public Host.v1 manifest fixtures for internal consumers. +// Re-export the public Host.v1/Host.v2 manifest fixtures for internal consumers. export { HOST_V1_BYTES, HOST_V1_BYTES_HEX, HOST_V1_HASH, HOST_V1_MANIFEST, + HOST_V2_BYTES, + HOST_V2_BYTES_HEX, + HOST_V2_HASH, + HOST_V2_MANIFEST, } from '@blue-quickjs/abi-manifest'; diff --git a/libs/test-harness/src/lib/binary-library-fixtures.ts b/libs/test-harness/src/lib/binary-library-fixtures.ts new file mode 100644 index 0000000..cef1703 --- /dev/null +++ b/libs/test-harness/src/lib/binary-library-fixtures.ts @@ -0,0 +1,45 @@ +import { HOST_V2_HASH, HOST_V2_MANIFEST } from './abi-manifest-fixtures.js'; +import { DETERMINISM_INPUT } from './determinism-fixtures.js'; + +export interface BinaryLibraryFixture { + name: string; + entryPath: string; + expectedValue: Record; +} + +export const BINARY_LIBRARY_PROGRAM_BASE = { + abiId: 'Host.v2', + abiVersion: 2, + abiManifestHash: HOST_V2_HASH, + executionProfile: 'compat-binary-v1' as const, +}; + +export const BINARY_LIBRARY_INPUT = DETERMINISM_INPUT; +export const BINARY_LIBRARY_GAS_LIMIT = 5_000_000n; +export const BINARY_LIBRARY_MANIFEST = HOST_V2_MANIFEST; + +export const BINARY_LIBRARY_FIXTURES: BinaryLibraryFixture[] = [ + { + name: 'base64-js-roundtrip', + entryPath: + 'libs/test-harness/fixtures/library-reuse/binary-base64-entry.ts', + expectedValue: { + length: 8, + sum: 36, + first: 1, + last: 8, + reencoded: 'AQIDBAUGBwg=', + }, + }, + { + name: 'noble-sha256-hex', + entryPath: + 'libs/test-harness/fixtures/library-reuse/binary-sha256-entry.ts', + expectedValue: { + hex: '641041dbb216456635a87ee5a1183e0b7462484d205c246eabecf274427efaad', + length: 32, + first: 100, + last: 173, + }, + }, +]; diff --git a/libs/test-harness/src/lib/binary-library-parity.spec.ts b/libs/test-harness/src/lib/binary-library-parity.spec.ts new file mode 100644 index 0000000..b6e0c4e --- /dev/null +++ b/libs/test-harness/src/lib/binary-library-parity.spec.ts @@ -0,0 +1,95 @@ +import { encodeDv } from '@blue-quickjs/dv'; +import { + BINARY_LIBRARY_FIXTURES, + BINARY_LIBRARY_GAS_LIMIT, +} from './binary-library-fixtures.js'; +import { + hasBuiltNativeHarness, + hostV2ManifestArgs, + parseNativeParityOutput, + repoRoot, + runNativeHarness, + sha256Hex, + type NativeParitySnapshot, +} from './native-harness-test-utils.js'; +import { fileURLToPath } from 'node:url'; +import path from 'node:path'; +import jiti from 'jiti'; + +const require = jiti(import.meta.url, { interopDefault: true }); +const { bundleDeterministicProgram } = require( + path.resolve( + path.dirname(fileURLToPath(import.meta.url)), + '../../../deterministic-bundler/src/index.ts', + ), +); + +const BINARY_NATIVE_BASELINES: Record = { + 'base64-js-roundtrip': { + ok: true, + valueHash: + '87dbcca4f5403c38f1d4259ba4d152240ab993b6d54d2bc5be615294634398d2', + errorCode: null, + errorTag: null, + gasUsed: '3542', + gasRemaining: '4996458', + tapeHash: null, + tapeLength: 0, + }, + 'noble-sha256-hex': { + ok: true, + valueHash: + '137c77da6a39cb7439836094805726f43751c3d4df281f9268ba4bf03b523afd', + errorCode: null, + errorTag: null, + gasUsed: '25970', + gasRemaining: '4974030', + tapeHash: null, + tapeLength: 0, + }, +}; + +describe('binary library parity', () => { + it('has a built native harness available', () => { + expect(hasBuiltNativeHarness()).toBe(true); + }); + + test.each(BINARY_LIBRARY_FIXTURES)( + '$name matches the native baseline snapshot', + async (fixture) => { + const bundled = await bundleDeterministicProgram({ + absWorkingDir: repoRoot, + entryPath: fixture.entryPath, + profile: 'compat-binary-v1', + }); + + const result = runNativeHarness( + [ + ...hostV2ManifestArgs, + '--execution-profile', + 'compat-binary-v1', + '--gas-limit', + BINARY_LIBRARY_GAS_LIMIT.toString(), + '--report-gas', + '--report-tape', + '--eval', + bundled.code, + ], + { + includeManifest: false, + }, + ); + + expect(result.status).toBe(0); + expect(result.stderr).toBe(''); + + const actual = parseNativeParityOutput(result.stdout, { + valueToHash: (value: unknown) => + sha256Hex(Buffer.from(encodeDv(value))), + }); + + expect(actual).toEqual(BINARY_NATIVE_BASELINES[fixture.name]); + }, + 15_000, + ); +}); diff --git a/libs/test-harness/src/lib/chess-library-fixtures.ts b/libs/test-harness/src/lib/chess-library-fixtures.ts new file mode 100644 index 0000000..554feef --- /dev/null +++ b/libs/test-harness/src/lib/chess-library-fixtures.ts @@ -0,0 +1,18 @@ +import { HOST_V1_HASH, HOST_V1_MANIFEST } from './abi-manifest-fixtures.js'; +import { DETERMINISM_INPUT } from './determinism-fixtures.js'; + +export const CHESS_LIBRARY_ENTRY_PATH = + 'libs/test-harness/fixtures/library-reuse/chess-entry.ts'; + +export const CHESS_E2E6_EXPECTED_LEGAL = false; + +export const CHESS_LIBRARY_PROGRAM_BASE = { + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + executionProfile: 'compat-general-v1' as const, +}; + +export const CHESS_LIBRARY_INPUT = DETERMINISM_INPUT; +export const CHESS_LIBRARY_GAS_LIMIT = 5_000_000n; +export const CHESS_LIBRARY_MANIFEST = HOST_V1_MANIFEST; diff --git a/libs/test-harness/src/lib/determinism-fixtures.ts b/libs/test-harness/src/lib/determinism-fixtures.ts index eff96e8..c5f31f3 100644 --- a/libs/test-harness/src/lib/determinism-fixtures.ts +++ b/libs/test-harness/src/lib/determinism-fixtures.ts @@ -1,12 +1,18 @@ import type { AbiManifest } from '@blue-quickjs/abi-manifest'; -import type { DV } from '@blue-quickjs/dv'; -import { HOST_V1_HASH, HOST_V1_MANIFEST } from './abi-manifest-fixtures.js'; +import type { DV, DV2 } from '@blue-quickjs/dv'; +import { + HOST_V1_HASH, + HOST_V1_MANIFEST, + HOST_V2_HASH, + HOST_V2_MANIFEST, +} from './abi-manifest-fixtures.js'; export interface DeterminismProgramArtifact { code: string; abiId: string; abiVersion: number; abiManifestHash: string; + executionProfile?: 'baseline-v1' | 'compat-general-v1' | 'compat-binary-v1'; engineBuildHash?: string; } @@ -39,19 +45,19 @@ export interface DeterminismHostHandlers { document: { get: ( path: string, - ) => { ok: DV; units: number } | { err: HostError; units: number }; + ) => { ok: DV2; units: number } | { err: HostError; units: number }; getCanonical: ( path: string, - ) => { ok: DV; units: number } | { err: HostError; units: number }; + ) => { ok: DV2; units: number } | { err: HostError; units: number }; }; emit: ( - value: DV, + value: DV2, ) => { ok: null; units: number } | { err: HostError; units: number }; } export interface DeterminismHostEnvironment { handlers: DeterminismHostHandlers; - emitted: DV[]; + emitted: DV2[]; } export interface DeterminismFixtureBaseline { @@ -92,7 +98,7 @@ const ERROR_PATHS = new Map([ ]); export function createDeterminismHost(): DeterminismHostEnvironment { - const emitted: DV[] = []; + const emitted: DV2[] = []; const documentHash = HOST_V1_HASH; const resolveError = (path: string): HostError | null => @@ -105,6 +111,9 @@ export function createDeterminismHost(): DeterminismHostEnvironment { if (error) { return { err: error, units: 2 }; } + if (path === 'bytes/payload') { + return { ok: Uint8Array.from([222, 173, 190, 239]), units: 11 }; + } return { ok: { path, @@ -126,7 +135,7 @@ export function createDeterminismHost(): DeterminismHostEnvironment { }; }, }, - emit: (value: DV) => { + emit: (value: DV2) => { emitted.push(value); return { ok: null, units: 1 }; }, @@ -141,6 +150,12 @@ const BASE_PROGRAM = { abiManifestHash: HOST_V1_HASH, } satisfies Omit; +const BASE_PROGRAM_V2 = { + abiId: 'Host.v2', + abiVersion: 2, + abiManifestHash: HOST_V2_HASH, +} satisfies Omit; + export const DETERMINISM_FIXTURES: DeterminismFixture[] = [ { name: 'doc-read', @@ -167,8 +182,8 @@ export const DETERMINISM_FIXTURES: DeterminismFixture[] = [ 'b37ef077d8dbd7ca3b846595288f5f3c408f658b388aa27a09bca31ec260bd74', errorCode: null, errorTag: null, - gasUsed: 1094n, - gasRemaining: 48906n, + gasUsed: 175n, + gasRemaining: 49825n, tapeHash: '497d3a537f25c9892ff8b211e4d10b534a15f3c4baee242ed78b275e6f4fbe95', tapeLength: 1, @@ -198,8 +213,8 @@ export const DETERMINISM_FIXTURES: DeterminismFixture[] = [ 'f92ef306595931cdecb1c5e448a6dd343b70ef6ed52508e7007f918086349ae1', errorCode: null, errorTag: null, - gasUsed: 1047n, - gasRemaining: 48953n, + gasUsed: 252n, + gasRemaining: 49748n, tapeHash: '92a9661491894b76b25edbdbfc5c50985edd19dcbce342b400053daf1ab77a28', tapeLength: 1, @@ -233,8 +248,8 @@ export const DETERMINISM_FIXTURES: DeterminismFixture[] = [ '55caac84e0b4ae1d4ba112253dffeeb3d380d18902846171b94c84533813842a', errorCode: null, errorTag: null, - gasUsed: 1803n, - gasRemaining: 48197n, + gasUsed: 478n, + gasRemaining: 49522n, tapeHash: '87ebafc74f16872c87953ac8856cc3403168b5040d7552cff6e0a74667da5e02', tapeLength: 4, @@ -267,8 +282,8 @@ export const DETERMINISM_FIXTURES: DeterminismFixture[] = [ '95e87a4f23c4cf45119e800b24933e7549ddc878de6dcd4a13097a4a2970258a', errorCode: null, errorTag: null, - gasUsed: 1582n, - gasRemaining: 48418n, + gasUsed: 431n, + gasRemaining: 49569n, tapeHash: 'bbc6919589461f5ee17a240edaf824f71ecb0269958273ddd815cb783aeb10e6', tapeLength: 3, @@ -303,12 +318,186 @@ export const DETERMINISM_FIXTURES: DeterminismFixture[] = [ 'b19cd2f9dc8d93cb259a85f365378dd4e5b97f0a93adff0ac7d3f0b89c10ac2f', errorCode: null, errorTag: null, - gasUsed: 1873n, - gasRemaining: 48127n, + gasUsed: 145n, + gasRemaining: 49855n, + tapeHash: null, + tapeLength: 0, + }, + }, + { + name: 'async-promise-chain', + program: { + ...BASE_PROGRAM, + executionProfile: 'compat-general-v1', + code: ` + (() => Promise.resolve(40).then((value) => value + 2))() + `.trim(), + }, + input: DETERMINISM_INPUT, + gasLimit: DETERMINISM_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + createHost: createDeterminismHost, + expected: { + resultHash: + '7f83f7bda2d63959d34767689f06d47576683d378d9eb8d09386c9a020395c53', + errorCode: null, + errorTag: null, + gasUsed: 128n, + gasRemaining: 49872n, + tapeHash: null, + tapeLength: 0, + }, + }, + { + name: 'async-queue-microtask-host', + program: { + ...BASE_PROGRAM, + executionProfile: 'compat-general-v1', + code: ` + (() => { + queueMicrotask(() => Host.v1.emit({ phase: 'microtask' })); + return Promise.resolve({ ok: true }); + })() + `.trim(), + }, + input: DETERMINISM_INPUT, + gasLimit: DETERMINISM_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + createHost: createDeterminismHost, + expected: { + resultHash: + '20a934991093b3d9bfcb5f3c05871eb1db002d19469c29ea3ae1ff7e4a29cd02', + errorCode: null, + errorTag: null, + gasUsed: 169n, + gasRemaining: 49831n, + tapeHash: + '43c068fe25380b52c96b71cbc266343a90afc80c928ebde6a7d967c8c57b6e5c', + tapeLength: 1, + }, + }, + { + name: 'async-promise-rejection', + program: { + ...BASE_PROGRAM, + executionProfile: 'compat-general-v1', + code: ` + (() => Promise.reject(new Error('async-failure')))() + `.trim(), + }, + input: DETERMINISM_INPUT, + gasLimit: DETERMINISM_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + createHost: createDeterminismHost, + expected: { + resultHash: null, + errorCode: 'UNKNOWN', + errorTag: 'vm/unknown', + gasUsed: 87n, + gasRemaining: 49913n, + tapeHash: null, + tapeLength: 0, + }, + }, + { + name: 'compat-stable-sort', + program: { + ...BASE_PROGRAM, + executionProfile: 'compat-general-v1', + code: ` + (() => { + const records = [ + { id: 'a', group: 1 }, + { id: 'b', group: 1 }, + { id: 'c', group: 2 }, + { id: 'd', group: 1 }, + ]; + records.sort((left, right) => left.group - right.group); + return records.map((record) => record.id); + })() + `.trim(), + }, + input: DETERMINISM_INPUT, + gasLimit: DETERMINISM_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + createHost: createDeterminismHost, + expected: { + resultHash: + '950f57b0bb4280b09b5a63004acc9c50811ca16cea7c932494f47cb3cfb23c04', + errorCode: null, + errorTag: null, + gasUsed: 1020n, + gasRemaining: 48980n, tapeHash: null, tapeLength: 0, }, }, + { + name: 'compat-console-shim', + program: { + ...BASE_PROGRAM, + executionProfile: 'compat-general-v1', + code: ` + (() => { + console.info('deterministic', 7); + return { ok: true }; + })() + `.trim(), + }, + input: DETERMINISM_INPUT, + gasLimit: DETERMINISM_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + createHost: createDeterminismHost, + expected: { + resultHash: + '20a934991093b3d9bfcb5f3c05871eb1db002d19469c29ea3ae1ff7e4a29cd02', + errorCode: null, + errorTag: null, + gasUsed: 139n, + gasRemaining: 49861n, + tapeHash: + 'c481a1396ab5097cc8aa68fd11c1bb6e96d63259dba00b560bf49489fe5b2e3f', + tapeLength: 1, + }, + }, + { + name: 'compat-binary-host-v2-bytes-roundtrip', + program: { + ...BASE_PROGRAM_V2, + executionProfile: 'compat-binary-v1', + code: ` + (() => { + const payload = Host.v2.document.get('bytes/payload'); + Host.v2.emit(payload); + let sum = 0; + for (const byte of payload) { + sum += byte; + } + return { + length: payload.byteLength, + first: payload[0], + last: payload[payload.byteLength - 1], + sum, + }; + })() + `.trim(), + }, + input: DETERMINISM_INPUT, + gasLimit: DETERMINISM_GAS_LIMIT, + manifest: HOST_V2_MANIFEST, + createHost: createDeterminismHost, + expected: { + resultHash: + 'a538717d219fa0484c601ef7b5b63704c90cb9ae0406495b9f0083989a9fb2f8', + errorCode: null, + errorTag: null, + gasUsed: 253n, + gasRemaining: 49747n, + tapeHash: + 'b2d3a3b07a1be6b39cd854077910a2bc839c281281275c2c137f6a704723a734', + tapeLength: 2, + }, + }, { name: 'json-builtins', program: { @@ -328,8 +517,8 @@ export const DETERMINISM_FIXTURES: DeterminismFixture[] = [ 'd3cabc4fcb3aaddef313e841cd56fec5936b96a44a7d45eff624b81dd9e221d8', errorCode: null, errorTag: null, - gasUsed: 599n, - gasRemaining: 49401n, + gasUsed: 154n, + gasRemaining: 49846n, tapeHash: null, tapeLength: 0, }, @@ -353,8 +542,8 @@ export const DETERMINISM_FIXTURES: DeterminismFixture[] = [ resultHash: null, errorCode: 'INVALID_PATH', errorTag: 'host/invalid_path', - gasUsed: 776n, - gasRemaining: 49224n, + gasUsed: 144n, + gasRemaining: 49856n, tapeHash: '79af1be3f347fffc766bbe0baef9a183f0d6ee206468954d8f2adb9c146b9ddc', tapeLength: 1, @@ -379,8 +568,8 @@ export const DETERMINISM_FIXTURES: DeterminismFixture[] = [ resultHash: null, errorCode: 'LIMIT_EXCEEDED', errorTag: 'host/limit', - gasUsed: 774n, - gasRemaining: 49226n, + gasUsed: 143n, + gasRemaining: 49857n, tapeHash: '4894237cf19c834c9bff793693a158be3443e56df132773f6c61c7aed456a088', tapeLength: 1, @@ -405,8 +594,8 @@ export const DETERMINISM_FIXTURES: DeterminismFixture[] = [ resultHash: null, errorCode: 'NOT_FOUND', errorTag: 'host/not_found', - gasUsed: 771n, - gasRemaining: 49229n, + gasUsed: 140n, + gasRemaining: 49860n, tapeHash: 'a540c3ce0fd4043d8c3262e3c1ae2bc6bb50d3e17d0cc1dd2a8af8957eaca013', tapeLength: 1, diff --git a/libs/test-harness/src/lib/dv-parity.spec.ts b/libs/test-harness/src/lib/dv-parity.spec.ts new file mode 100644 index 0000000..8b8932a --- /dev/null +++ b/libs/test-harness/src/lib/dv-parity.spec.ts @@ -0,0 +1,170 @@ +import { decodeDv, encodeDv } from '@blue-quickjs/dv'; +import { + hasBuiltNativeHarness, + runNativeHarness, +} from './native-harness-test-utils.js'; + +interface EncodeFixture { + name: string; + expr: string; + value: unknown; +} + +interface ErrorFixture { + name: string; + expr?: string; + hex?: string; + value?: unknown; + errorContains: string; +} + +const encodeFixtures: EncodeFixture[] = [ + { name: 'null', expr: 'null', value: null }, + { name: 'boolean', expr: 'true', value: true }, + { name: 'int', expr: '42', value: 42 }, + { name: 'negative-int', expr: '-17', value: -17 }, + { name: 'float', expr: '1.5', value: 1.5 }, + { name: 'string', expr: '"hello"', value: 'hello' }, + { name: 'string-null-byte', expr: '"a\\u0000b"', value: 'a\u0000b' }, + { name: 'unicode', expr: '"\\u263a"', value: '\u263a' }, + { name: 'array', expr: '["hello", 1.5, -1]', value: ['hello', 1.5, -1] }, + { + name: 'object-ordering', + expr: '({ b: 2, aa: 1 })', + value: { b: 2, aa: 1 }, + }, + { + name: 'null-proto-object', + expr: '(() => { const o = Object.create(null); o.a = 1; o.b = "c"; return o; })()', + value: Object.assign(Object.create(null), { a: 1, b: 'c' }), + }, + { + name: 'nested', + expr: '({ nested: [1, { z: "hi" }], flag: false })', + value: { nested: [1, { z: 'hi' }], flag: false }, + }, + { + name: 'object-global-object-replacement', + expr: '(() => { function Fake() {} Fake.prototype = { hacked: true }; globalThis.Object = Fake; return { a: 1 }; })()', + value: { a: 1 }, + }, + { + name: 'emoji-non-bmp', + expr: '"\\uD83D\\uDE00"', + value: '\uD83D\uDE00', + }, + { name: 'empty-array', expr: '[]', value: [] }, + { name: 'empty-object', expr: '({})', value: {} }, + { name: 'negative-zero', expr: '-0', value: -0 }, +]; + +const encodeErrorFixtures: ErrorFixture[] = [ + { + name: 'encode-lone-surrogate', + expr: '"a\\uD800"', + value: 'a\uD800', + errorContains: 'lone surrogate code points', + }, +]; + +const decodeErrorFixtures: ErrorFixture[] = [ + { + name: 'decode-non-canonical-int-width', + hex: '1801', + errorContains: 'length not using shortest encoding', + }, + { + name: 'decode-float32', + hex: 'fa3f800000', + errorContains: 'only float64 is allowed', + }, + { + name: 'decode-byte-string', + hex: '40', + errorContains: 'unsupported CBOR major type', + }, + { + name: 'decode-trailing-bytes', + hex: 'f6f6', + errorContains: 'unexpected trailing bytes after DV value', + }, + { + name: 'decode-non-text-map-key', + hex: 'a10101', + errorContains: 'map keys must be text strings', + }, + { + name: 'decode-map-key-order', + hex: 'a262616101616202', + errorContains: 'map keys are not in canonical order', + }, +]; + +describe('dv parity', () => { + it('has a built native harness available', () => { + expect(hasBuiltNativeHarness()).toBe(true); + }); + + test.each(encodeFixtures)( + '$name encodes identically to the TS reference', + ({ expr, value }) => { + const expectedHex = bytesToHex(encodeDv(value)); + const result = runNativeHarness(['--dv-encode', '--eval', expr]); + + expect(result.status).toBe(0); + expect(result.stderr).toBe(''); + expect(result.stdout.startsWith('DV ')).toBe(true); + expect(result.stdout.slice('DV '.length)).toBe(expectedHex); + }, + ); + + test.each(encodeFixtures)( + '$name decodes identically to the TS reference', + ({ value }) => { + const encoded = encodeDv(value); + const result = runNativeHarness(['--dv-decode', bytesToHex(encoded)]); + + expect(result.status).toBe(0); + expect(result.stderr).toBe(''); + expect(result.stdout.startsWith('DVRESULT ')).toBe(true); + expect(result.stdout.slice('DVRESULT '.length)).toBe( + JSON.stringify(decodeDv(encoded)), + ); + }, + ); + + test.each(encodeErrorFixtures)( + '$name rejects invalid values during encode', + ({ expr, value, errorContains }) => { + expect(() => encodeDv(value)).toThrowError(new RegExp(errorContains)); + expect(expr).toBeDefined(); + + const result = runNativeHarness(['--dv-encode', '--eval', String(expr)]); + expect(result.status).not.toBe(0); + expect(result.stdout.startsWith('ERROR ')).toBe(true); + expect(result.stdout).toContain(errorContains); + }, + ); + + test.each(decodeErrorFixtures)( + '$name rejects invalid bytes during decode', + ({ hex, errorContains }) => { + expect(hex).toBeDefined(); + + expect(() => decodeDv(Buffer.from(String(hex), 'hex'))).toThrowError( + new RegExp(errorContains), + ); + + const result = runNativeHarness(['--dv-decode', String(hex)]); + expect(result.status).not.toBe(0); + expect(result.stdout.startsWith('ERROR ')).toBe(true); + expect(result.stdout).toContain(errorContains); + }, + ); +}); + +function bytesToHex(bytes: Uint8Array): string { + return Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join( + '', + ); +} diff --git a/libs/test-harness/src/lib/example-fixtures.ts b/libs/test-harness/src/lib/example-fixtures.ts new file mode 100644 index 0000000..304d6f2 --- /dev/null +++ b/libs/test-harness/src/lib/example-fixtures.ts @@ -0,0 +1,134 @@ +export type ExampleFixtureSuite = + | 'gas-sample' + | 'gas-boundary' + | 'module-pack' + | 'determinism' + | 'chess-library' + | 'binary-library'; + +export interface ExampleFixtureTarget { + suite: ExampleFixtureSuite; + fixtureName: string; +} + +export interface ExampleCorpusEntry { + id: number; + slug: string; + title: string; + profile: string | string[]; + sourcePaths: string[]; + coverage: ExampleFixtureTarget[]; +} + +export const EXAMPLE_CORPUS: ExampleCorpusEntry[] = [ + { + id: 1, + slug: 'basic-script', + title: 'Basic deterministic script', + profile: 'baseline-v1', + sourcePaths: ['examples/01-basic-script/program.js'], + coverage: [{ suite: 'gas-sample', fixtureName: 'return-1' }], + }, + { + id: 2, + slug: 'module-pack', + title: 'Standard ESM module-pack', + profile: 'baseline-v1', + sourcePaths: [ + 'examples/02-module-pack/entry.js', + 'examples/02-module-pack/values.js', + ], + coverage: [ + { suite: 'module-pack', fixtureName: 'module-pack-default-export' }, + ], + }, + { + id: 3, + slug: 'library-reuse', + title: 'Real npm library reuse', + profile: ['compat-general-v1', 'compat-binary-v1'], + sourcePaths: [ + 'examples/03-library-reuse/chess-entry.ts', + 'examples/03-library-reuse/binary-base64-entry.ts', + ], + coverage: [ + { suite: 'chess-library', fixtureName: 'chess-e2e6' }, + { suite: 'binary-library', fixtureName: 'base64-js-roundtrip' }, + { suite: 'binary-library', fixtureName: 'noble-sha256-hex' }, + ], + }, + { + id: 4, + slug: 'promises-async', + title: 'Promises / async / microtasks', + profile: 'compat-general-v1', + sourcePaths: ['examples/04-promises-async/program.js'], + coverage: [{ suite: 'determinism', fixtureName: 'async-promise-chain' }], + }, + { + id: 5, + slug: 'promises-library-host', + title: 'Promises + imported library + host call', + profile: 'compat-general-v1', + sourcePaths: [ + 'examples/05-promises-library-host/entry.js', + 'examples/05-promises-library-host/lib.js', + ], + coverage: [ + { + suite: 'module-pack', + fixtureName: 'module-pack-async-import-host-call', + }, + ], + }, + { + id: 6, + slug: 'binary-host-v2', + title: 'Binary / typed arrays / Host.v2 DV2', + profile: 'compat-binary-v1', + sourcePaths: ['examples/06-binary-host-v2/program.js'], + coverage: [ + { + suite: 'determinism', + fixtureName: 'compat-binary-host-v2-bytes-roundtrip', + }, + ], + }, + { + id: 7, + slug: 'console-shim', + title: 'Console shim determinism', + profile: 'compat-general-v1', + sourcePaths: ['examples/07-console-shim/program.js'], + coverage: [{ suite: 'determinism', fixtureName: 'compat-console-shim' }], + }, + { + id: 8, + slug: 'stable-sort', + title: 'Stable sort determinism', + profile: 'compat-general-v1', + sourcePaths: ['examples/08-stable-sort/program.js'], + coverage: [{ suite: 'determinism', fixtureName: 'compat-stable-sort' }], + }, + { + id: 9, + slug: 'kitchen-sink', + title: 'Kitchen sink app', + profile: 'compat-general-v1', + sourcePaths: [ + 'examples/09-kitchen-sink/entry.js', + 'examples/09-kitchen-sink/workflow.js', + ], + coverage: [ + { suite: 'module-pack', fixtureName: 'module-pack-kitchen-sink' }, + ], + }, + { + id: 10, + slug: 'max-gas-policy', + title: 'Max-gas policy / OOG boundary', + profile: 'baseline-v1', + sourcePaths: ['examples/10-max-gas-policy/program.js'], + coverage: [{ suite: 'gas-boundary', fixtureName: 'loop-10k' }], + }, +]; diff --git a/libs/test-harness/src/lib/gas-equivalence.spec.ts b/libs/test-harness/src/lib/gas-equivalence.spec.ts index 3be4ad0..076bc2d 100644 --- a/libs/test-harness/src/lib/gas-equivalence.spec.ts +++ b/libs/test-harness/src/lib/gas-equivalence.spec.ts @@ -4,7 +4,6 @@ import path from 'node:path'; import { fileURLToPath, pathToFileURL } from 'node:url'; import { describe, expect, test, beforeAll } from 'vitest'; import { decodeDv, encodeDv } from '@blue-quickjs/dv'; -import { getQuickjsWasmArtifacts } from '@blue-quickjs/quickjs-wasm-build'; import type { QuickjsWasmBuildType, QuickjsWasmVariant, @@ -27,6 +26,42 @@ interface ExpectedResult extends DeterministicOutput { value?: unknown; } +interface ExpectedTrace { + opcodeCount: bigint; + opcodeGas: bigint; + arrayCbBaseCount: bigint; + arrayCbBaseGas: bigint; + arrayCbPerElCount: bigint; + arrayCbPerElGas: bigint; + allocationCount: bigint; + allocationBytes: bigint; + allocationGas: bigint; + jsonParseCount: bigint; + jsonParseGas: bigint; + jsonParseInputBytes: bigint; + jsonParseValues: bigint; + jsonParseObjectEntries: bigint; + jsonParseArrayElements: bigint; + jsonStringifyCount: bigint; + jsonStringifyGas: bigint; + jsonStringifyOutputBytes: bigint; + jsonStringifyValues: bigint; + jsonStringifyObjectEntries: bigint; + jsonStringifyArrayElements: bigint; + jsonStringifySortComparisons: bigint; + hostCallPreCount: bigint; + hostCallPreGas: bigint; + hostCallPostCount: bigint; + hostCallPostGas: bigint; +} + +interface QuickjsWasmBuildModule { + getQuickjsWasmArtifacts: ( + variant: QuickjsWasmVariant, + buildType: QuickjsWasmBuildType, + ) => { loaderPath: string }; +} + const repoRoot = path.resolve( path.dirname(fileURLToPath(import.meta.url)), '../../../..', @@ -62,42 +97,180 @@ const cases = [ { name: 'loop-oog', fixture: 'loop-counter.js', - gasLimit: 600n, + gasLimit: 146n, }, { name: 'constant', fixture: 'constant.js', - gasLimit: 147n, + gasLimit: 37n, }, { name: 'addition', fixture: 'addition.js', - gasLimit: 154n, + gasLimit: 39n, }, { name: 'string-repeat', fixture: 'string-repeat.js', - gasLimit: 5000n, + gasLimit: 84n, }, { name: 'json-parse', fixture: 'json-parse-small.js', - gasLimit: 217n, + gasLimit: 77n, }, { name: 'json-parse-oog', fixture: 'json-parse-oog.js', - gasLimit: 216n, + gasLimit: 76n, }, { name: 'json-stringify', fixture: 'json-stringify-small.js', - gasLimit: 241n, + gasLimit: 82n, }, { name: 'json-stringify-oog', fixture: 'json-stringify-oog.js', - gasLimit: 240n, + gasLimit: 81n, + }, + { + name: 'array-map-single', + fixture: 'array-map-single.js', + gasLimit: 143n, + }, + { + name: 'array-map-single-oog', + fixture: 'array-map-single.js', + gasLimit: 142n, + }, + { + name: 'array-map-multi', + fixture: 'array-map-multi.js', + gasLimit: 179n, + }, + { + name: 'array-map-multi-oog', + fixture: 'array-map-multi.js', + gasLimit: 178n, + }, + { + name: 'array-filter-multi', + fixture: 'array-filter-multi.js', + gasLimit: 189n, + }, + { + name: 'array-filter-multi-oog', + fixture: 'array-filter-multi.js', + gasLimit: 188n, + }, + { + name: 'array-reduce-multi', + fixture: 'array-reduce-multi.js', + gasLimit: 189n, + }, + { + name: 'array-reduce-multi-oog', + fixture: 'array-reduce-multi.js', + gasLimit: 188n, + }, + { + name: 'gc-pending', + fixture: 'gc-pending.js', + gasLimit: 89n, + }, + { + name: 'gc-pending-oog', + fixture: 'gc-pending.js', + gasLimit: 88n, + }, +]; + +interface BoundaryFixtureCase { + name: string; + fixture: string; + expectedFirstSuccessGas: bigint; +} + +interface TraceFixtureCase { + name: string; + fixture: string; +} + +const boundaryCases: BoundaryFixtureCase[] = [ + { + name: 'opcode-addition', + fixture: 'addition.js', + expectedFirstSuccessGas: 39n, + }, + { + name: 'opcode-constant', + fixture: 'constant.js', + expectedFirstSuccessGas: 37n, + }, + { + name: 'loop-counter', + fixture: 'loop-counter.js', + expectedFirstSuccessGas: 146n, + }, + { + name: 'string-repeat', + fixture: 'string-repeat.js', + expectedFirstSuccessGas: 84n, + }, + { + name: 'json-parse-small', + fixture: 'json-parse-small.js', + expectedFirstSuccessGas: 77n, + }, + { + name: 'json-stringify-small', + fixture: 'json-stringify-small.js', + expectedFirstSuccessGas: 82n, + }, + { + name: 'array-map-single', + fixture: 'array-map-single.js', + expectedFirstSuccessGas: 143n, + }, + { + name: 'array-map-multi', + fixture: 'array-map-multi.js', + expectedFirstSuccessGas: 179n, + }, + { + name: 'array-filter-multi', + fixture: 'array-filter-multi.js', + expectedFirstSuccessGas: 189n, + }, + { + name: 'array-reduce-multi', + fixture: 'array-reduce-multi.js', + expectedFirstSuccessGas: 189n, + }, + { + name: 'gc-pending', + fixture: 'gc-pending.js', + expectedFirstSuccessGas: 89n, + }, +]; + +const traceCases: TraceFixtureCase[] = [ + { + name: 'addition', + fixture: 'addition.js', + }, + { + name: 'json-parse', + fixture: 'json-parse-small.js', + }, + { + name: 'json-stringify', + fixture: 'json-stringify-small.js', + }, + { + name: 'gc-pending', + fixture: 'gc-pending.js', }, ]; @@ -136,57 +309,237 @@ const wasm32Expectations: Record = { }, 'loop-oog': { kind: 'RESULT', - payload: '02016c', + payload: '03', value: 3, - gasRemaining: 203n, - gasUsed: 397n, + gasRemaining: 0n, + gasUsed: 146n, }, constant: { kind: 'RESULT', - payload: '02014b', + payload: '01', value: 1, - gasRemaining: 58n, - gasUsed: 89n, + gasRemaining: 0n, + gasUsed: 37n, }, addition: { kind: 'RESULT', - payload: '02016c', + payload: '03', value: 3, - gasRemaining: 58n, - gasUsed: 96n, + gasRemaining: 0n, + gasUsed: 39n, }, 'string-repeat': { kind: 'RESULT', - payload: '0201e980fa0c', + payload: '198000', value: 32768, - gasRemaining: 2687n, - gasUsed: 2313n, + gasRemaining: 0n, + gasUsed: 84n, }, 'json-parse': { kind: 'RESULT', payload: 'a261620262616101', value: { b: 2, aa: 1 }, gasRemaining: 0n, - gasUsed: 217n, + gasUsed: 77n, }, 'json-parse-oog': { kind: 'ERROR', payload: 'OutOfGas: out of gas', gasRemaining: 0n, - gasUsed: 216n, + gasUsed: 76n, }, 'json-stringify': { kind: 'RESULT', payload: '6e7b2262223a322c226161223a317d', value: '{"b":2,"aa":1}', gasRemaining: 0n, - gasUsed: 241n, + gasUsed: 82n, }, 'json-stringify-oog': { kind: 'ERROR', payload: 'OutOfGas: out of gas', gasRemaining: 0n, - gasUsed: 240n, + gasUsed: 81n, + }, + 'array-map-single': { + kind: 'RESULT', + payload: '01', + value: 1, + gasRemaining: 0n, + gasUsed: 143n, + }, + 'array-map-single-oog': { + kind: 'ERROR', + payload: 'OutOfGas: out of gas', + gasRemaining: 0n, + gasUsed: 142n, + }, + 'array-map-multi': { + kind: 'RESULT', + payload: '05', + value: 5, + gasRemaining: 0n, + gasUsed: 179n, + }, + 'array-map-multi-oog': { + kind: 'ERROR', + payload: 'OutOfGas: out of gas', + gasRemaining: 0n, + gasUsed: 178n, + }, + 'array-filter-multi': { + kind: 'RESULT', + payload: '05', + value: 5, + gasRemaining: 0n, + gasUsed: 189n, + }, + 'array-filter-multi-oog': { + kind: 'ERROR', + payload: 'OutOfGas: out of gas', + gasRemaining: 0n, + gasUsed: 188n, + }, + 'array-reduce-multi': { + kind: 'RESULT', + payload: '0f', + value: 15, + gasRemaining: 0n, + gasUsed: 189n, + }, + 'array-reduce-multi-oog': { + kind: 'ERROR', + payload: 'OutOfGas: out of gas', + gasRemaining: 0n, + gasUsed: 188n, + }, + 'gc-pending': { + kind: 'RESULT', + payload: '1a00124f80', + value: 1200000, + gasRemaining: 0n, + gasUsed: 89n, + }, + 'gc-pending-oog': { + kind: 'ERROR', + payload: 'OutOfGas: out of gas', + gasRemaining: 0n, + gasUsed: 88n, + }, +}; + +const wasm32TraceExpectations: Record = { + addition: { + opcodeCount: 5n, + opcodeGas: 5n, + arrayCbBaseCount: 0n, + arrayCbBaseGas: 0n, + arrayCbPerElCount: 0n, + arrayCbPerElGas: 0n, + allocationCount: 12n, + allocationBytes: 1112n, + allocationGas: 34n, + jsonParseCount: 0n, + jsonParseGas: 0n, + jsonParseInputBytes: 0n, + jsonParseValues: 0n, + jsonParseObjectEntries: 0n, + jsonParseArrayElements: 0n, + jsonStringifyCount: 0n, + jsonStringifyGas: 0n, + jsonStringifyOutputBytes: 0n, + jsonStringifyValues: 0n, + jsonStringifyObjectEntries: 0n, + jsonStringifyArrayElements: 0n, + jsonStringifySortComparisons: 0n, + hostCallPreCount: 0n, + hostCallPreGas: 0n, + hostCallPostCount: 0n, + hostCallPostGas: 0n, + }, + 'json-parse': { + opcodeCount: 6n, + opcodeGas: 6n, + arrayCbBaseCount: 0n, + arrayCbBaseGas: 0n, + arrayCbPerElCount: 0n, + arrayCbPerElGas: 0n, + allocationCount: 26n, + allocationBytes: 1704n, + allocationGas: 36n, + jsonParseCount: 1n, + jsonParseGas: 35n, + jsonParseInputBytes: 14n, + jsonParseValues: 3n, + jsonParseObjectEntries: 2n, + jsonParseArrayElements: 0n, + jsonStringifyCount: 0n, + jsonStringifyGas: 0n, + jsonStringifyOutputBytes: 0n, + jsonStringifyValues: 0n, + jsonStringifyObjectEntries: 0n, + jsonStringifyArrayElements: 0n, + jsonStringifySortComparisons: 0n, + hostCallPreCount: 0n, + hostCallPreGas: 0n, + hostCallPostCount: 0n, + hostCallPostGas: 0n, + }, + 'json-stringify': { + opcodeCount: 10n, + opcodeGas: 10n, + arrayCbBaseCount: 0n, + arrayCbBaseGas: 0n, + arrayCbPerElCount: 0n, + arrayCbPerElGas: 0n, + allocationCount: 31n, + allocationBytes: 1768n, + allocationGas: 36n, + jsonParseCount: 0n, + jsonParseGas: 0n, + jsonParseInputBytes: 0n, + jsonParseValues: 0n, + jsonParseObjectEntries: 0n, + jsonParseArrayElements: 0n, + jsonStringifyCount: 1n, + jsonStringifyGas: 36n, + jsonStringifyOutputBytes: 14n, + jsonStringifyValues: 3n, + jsonStringifyObjectEntries: 2n, + jsonStringifyArrayElements: 0n, + jsonStringifySortComparisons: 1n, + hostCallPreCount: 0n, + hostCallPreGas: 0n, + hostCallPostCount: 0n, + hostCallPostGas: 0n, + }, + 'gc-pending': { + opcodeCount: 18n, + opcodeGas: 18n, + arrayCbBaseCount: 0n, + arrayCbBaseGas: 0n, + arrayCbPerElCount: 0n, + arrayCbPerElGas: 0n, + allocationCount: 40n, + allocationBytes: 2520n, + allocationGas: 71n, + jsonParseCount: 0n, + jsonParseGas: 0n, + jsonParseInputBytes: 0n, + jsonParseValues: 0n, + jsonParseObjectEntries: 0n, + jsonParseArrayElements: 0n, + jsonStringifyCount: 0n, + jsonStringifyGas: 0n, + jsonStringifyOutputBytes: 0n, + jsonStringifyValues: 0n, + jsonStringifyObjectEntries: 0n, + jsonStringifyArrayElements: 0n, + jsonStringifySortComparisons: 0n, + hostCallPreCount: 0n, + hostCallPreGas: 0n, + hostCallPostCount: 0n, + hostCallPostGas: 0n, }, }; @@ -198,15 +551,25 @@ let wasmInit: contextPtr: WasmPtr, contextLength: number, gasLimit: bigint, + featureFlags: number, ) => WasmPtr) | null = null; let wasmEval: ((code: string) => WasmPtr) | null = null; let wasmFreeRuntime: (() => void) | null = null; let wasmMalloc: ((size: number) => WasmPtr) | null = null; let wasmFree: ((ptr: WasmPtr) => void) | null = null; +let wasmEnableTrace: ((enabled: number) => number) | null = null; +let wasmReadTrace: (() => WasmPtr) | null = null; let wasmModule: any = null; beforeAll(async () => { + // Keep this non-literal so no-emit spec typechecks do not require prebuilt declarations. + const quickjsWasmBuildPackage = ['@blue-quickjs', 'quickjs-wasm-build'].join( + '/', + ); + const { getQuickjsWasmArtifacts } = (await import( + quickjsWasmBuildPackage + )) as QuickjsWasmBuildModule; const { loaderPath } = getQuickjsWasmArtifacts(wasmVariant, wasmBuildType); if (!existsSync(loaderPath)) { throw new Error( @@ -228,14 +591,28 @@ beforeAll(async () => { ptrArgType, 'number', 'bigint', + 'number', ]); wasmEval = wasmModule.cwrap('qjs_det_eval', ptrReturnType, ['string']); wasmFreeRuntime = wasmModule.cwrap('qjs_det_free', null, []); wasmMalloc = wasmModule.cwrap('malloc', ptrReturnType, ['number']); wasmFree = wasmModule.cwrap('free', null, [ptrArgType]); + wasmEnableTrace = wasmModule.cwrap('qjs_det_enable_trace', 'number', [ + 'number', + ]); + wasmReadTrace = wasmModule.cwrap('qjs_det_read_trace', ptrReturnType, []); }); function runNative(code: string, gasLimit: bigint): DeterministicOutput { + const result = runNativeProcess(code, gasLimit); + return parseDeterministicOutput(result.stdout); +} + +function runNativeProcess( + code: string, + gasLimit: bigint, + extraArgs: string[] = [], +): { stdout: string } { const args = [ '--gas-limit', gasLimit.toString(), @@ -246,6 +623,7 @@ function runNative(code: string, gasLimit: bigint): DeterministicOutput { MANIFEST_HASH, '--context-blob-hex', CONTEXT_HEX, + ...extraArgs, '--eval', code, ]; @@ -255,16 +633,31 @@ function runNative(code: string, gasLimit: bigint): DeterministicOutput { if (result.error) { throw result.error; } - return parseDeterministicOutput(result.stdout); + return { + stdout: result.stdout.trim(), + }; } function runWasm(code: string, gasLimit: bigint): DeterministicOutput { + return runWasmWithOptions(code, gasLimit).output; +} + +function runWasmWithOptions( + code: string, + gasLimit: bigint, + options?: { gasTrace?: boolean }, +): { + output: DeterministicOutput; + trace?: ExpectedTrace; +} { if ( !wasmEval || !wasmInit || !wasmFreeRuntime || !wasmMalloc || !wasmFree || + !wasmEnableTrace || + !wasmReadTrace || !wasmModule ) { throw new Error('Wasm harness not initialized'); @@ -285,6 +678,7 @@ function runWasm(code: string, gasLimit: bigint): DeterministicOutput { contextPtr, CONTEXT_BLOB.length, gasLimit, + 0, ); if (errorPtr !== 0) { const message = readCString(wasmModule, errorPtr); @@ -292,10 +686,23 @@ function runWasm(code: string, gasLimit: bigint): DeterministicOutput { throw new Error(`wasm init failed: ${message}`); } + if (options?.gasTrace) { + const rc = wasmEnableTrace(1); + if (rc !== 0) { + throw new Error(`failed to enable wasm gas trace (rc=${String(rc)})`); + } + } + const ptr = wasmEval(code); const raw = readCString(wasmModule, ptr); wasmFree(ptr); - return parseDeterministicOutput(raw); + const trace = options?.gasTrace + ? readWasmTrace(wasmModule, wasmReadTrace, wasmFree) + : undefined; + return { + output: parseDeterministicOutput(raw), + ...(trace ? { trace } : {}), + }; } finally { wasmFree(manifestPtr); wasmFree(hashPtr); @@ -325,6 +732,61 @@ describe('wasm gas outputs', () => { }); }); +describe('exact OOG boundaries', () => { + test.each(boundaryCases)( + '$name has identical first-success and last-failure boundaries', + ({ fixture, expectedFirstSuccessGas }) => { + const code = readFileSync(path.join(fixturesRoot, fixture), 'utf8'); + + const wasmBoundary = findOutOfGasBoundary( + (gasLimit) => runWasm(code, gasLimit), + expectedFirstSuccessGas + 64n, + ); + expect(wasmBoundary.firstSuccessGas).toBe(expectedFirstSuccessGas); + expect(wasmBoundary.lastFailureGas).toBe(expectedFirstSuccessGas - 1n); + expect(wasmBoundary.firstSuccess.gasUsed).toBe( + wasmBoundary.firstSuccessGas, + ); + expect(wasmBoundary.firstSuccess.gasRemaining).toBe(0n); + expect(isOutOfGasError(wasmBoundary.lastFailure)).toBe(true); + + const nativeBoundary = findOutOfGasBoundary( + (gasLimit) => runNative(code, gasLimit), + expectedFirstSuccessGas + 64n, + ); + expect(nativeBoundary.firstSuccessGas).toBe(wasmBoundary.firstSuccessGas); + expect(nativeBoundary.lastFailureGas).toBe(wasmBoundary.lastFailureGas); + expect(nativeBoundary.firstSuccess.gasUsed).toBe( + nativeBoundary.firstSuccessGas, + ); + expect(nativeBoundary.firstSuccess.gasRemaining).toBe(0n); + expect(isOutOfGasError(nativeBoundary.lastFailure)).toBe(true); + }, + ); +}); + +describe('gas trace parity', () => { + test.each(traceCases)('$name trace matches', ({ name, fixture }) => { + const code = readFileSync(path.join(fixturesRoot, fixture), 'utf8'); + const wasm = runWasmWithOptions(code, 1_000_000n, { gasTrace: true }); + if (!wasm.trace) { + throw new Error(`missing wasm trace for ${name}`); + } + + if (useNativeBaseline) { + const native = runNativeWithTrace(code, 1_000_000n); + expectTraceResult(wasm.trace, native.trace); + return; + } + + const expected = wasm32TraceExpectations[name]; + if (!expected) { + throw new Error(`Missing wasm32 trace expectation for case ${name}`); + } + expectTraceResult(wasm.trace, expected); + }); +}); + function expectHarnessResult( actual: DeterministicOutput, expected: ExpectedResult, @@ -345,12 +807,181 @@ function expectHarnessResult( } } +function isOutOfGasError(output: DeterministicOutput): boolean { + return output.kind === 'ERROR' && output.payload.includes('OutOfGas'); +} + +function findOutOfGasBoundary( + run: (gasLimit: bigint) => DeterministicOutput, + initialUpperBound: bigint, +): { + firstSuccessGas: bigint; + lastFailureGas: bigint; + firstSuccess: DeterministicOutput; + lastFailure: DeterministicOutput; +} { + let upperGas = initialUpperBound; + let upperOutput = run(upperGas); + while (upperOutput.kind !== 'RESULT') { + upperGas *= 2n; + if (upperGas > 100_000_000n) { + throw new Error(`failed to find successful gas bound (last=${upperGas})`); + } + upperOutput = run(upperGas); + } + + let lowerGas = 0n; + let lowerOutput = run(lowerGas); + while (lowerGas + 1n < upperGas) { + const mid = (lowerGas + upperGas) >> 1n; + const midOutput = run(mid); + if (midOutput.kind === 'RESULT') { + upperGas = mid; + upperOutput = midOutput; + } else { + lowerGas = mid; + lowerOutput = midOutput; + } + } + + return { + firstSuccessGas: upperGas, + lastFailureGas: lowerGas, + firstSuccess: upperOutput, + lastFailure: lowerOutput, + }; +} + function bytesToHex(bytes: Uint8Array): string { return Array.from(bytes) .map((b) => b.toString(16).padStart(2, '0')) .join(''); } +function runNativeWithTrace( + code: string, + gasLimit: bigint, +): { output: DeterministicOutput; trace: ExpectedTrace } { + const result = runNativeProcess(code, gasLimit, ['--gas-trace']); + return { + output: parseDeterministicOutput(result.stdout), + trace: parseNativeTrace(result.stdout), + }; +} + +function readWasmTrace( + wasm: any, + readTrace: () => WasmPtr, + freeFn: (ptr: WasmPtr) => void, +): ExpectedTrace { + const ptr = readTrace(); + const raw = readCString(wasm, ptr); + freeFn(ptr); + return parseWasmTrace(raw); +} + +function parseWasmTrace(raw: string): ExpectedTrace { + const trace = JSON.parse(raw) as Record; + return { + opcodeCount: BigInt(trace.opcodeCount ?? '0'), + opcodeGas: BigInt(trace.opcodeGas ?? '0'), + arrayCbBaseCount: BigInt(trace.arrayCbBaseCount ?? '0'), + arrayCbBaseGas: BigInt(trace.arrayCbBaseGas ?? '0'), + arrayCbPerElCount: BigInt(trace.arrayCbPerElCount ?? '0'), + arrayCbPerElGas: BigInt(trace.arrayCbPerElGas ?? '0'), + allocationCount: BigInt(trace.allocationCount ?? '0'), + allocationBytes: BigInt(trace.allocationBytes ?? '0'), + allocationGas: BigInt(trace.allocationGas ?? '0'), + jsonParseCount: BigInt(trace.jsonParseCount ?? '0'), + jsonParseGas: BigInt(trace.jsonParseGas ?? '0'), + jsonParseInputBytes: BigInt(trace.jsonParseInputBytes ?? '0'), + jsonParseValues: BigInt(trace.jsonParseValues ?? '0'), + jsonParseObjectEntries: BigInt(trace.jsonParseObjectEntries ?? '0'), + jsonParseArrayElements: BigInt(trace.jsonParseArrayElements ?? '0'), + jsonStringifyCount: BigInt(trace.jsonStringifyCount ?? '0'), + jsonStringifyGas: BigInt(trace.jsonStringifyGas ?? '0'), + jsonStringifyOutputBytes: BigInt(trace.jsonStringifyOutputBytes ?? '0'), + jsonStringifyValues: BigInt(trace.jsonStringifyValues ?? '0'), + jsonStringifyObjectEntries: BigInt(trace.jsonStringifyObjectEntries ?? '0'), + jsonStringifyArrayElements: BigInt(trace.jsonStringifyArrayElements ?? '0'), + jsonStringifySortComparisons: BigInt( + trace.jsonStringifySortComparisons ?? '0', + ), + hostCallPreCount: BigInt(trace.hostCallPreCount ?? '0'), + hostCallPreGas: BigInt(trace.hostCallPreGas ?? '0'), + hostCallPostCount: BigInt(trace.hostCallPostCount ?? '0'), + hostCallPostGas: BigInt(trace.hostCallPostGas ?? '0'), + }; +} + +function parseNativeTrace(raw: string): ExpectedTrace { + const match = / TRACE (\{.+\})$/.exec(raw.trim()); + if (!match) { + throw new Error(`Unable to parse native trace from output: ${raw}`); + } + const trace = JSON.parse(match[1]) as { + opcodeCount?: number; + opcodeGas?: number; + arrayCbBase?: { count?: number; gas?: number }; + arrayCbPerEl?: { count?: number; gas?: number }; + alloc?: { count?: number; bytes?: number; gas?: number }; + jsonParse?: { + count?: number; + gas?: number; + inputBytes?: number; + values?: number; + objectEntries?: number; + arrayElements?: number; + }; + jsonStringify?: { + count?: number; + gas?: number; + outputBytes?: number; + values?: number; + objectEntries?: number; + arrayElements?: number; + sortComparisons?: number; + }; + hostCallPre?: { count?: number; gas?: number }; + hostCallPost?: { count?: number; gas?: number }; + }; + + return { + opcodeCount: BigInt(trace.opcodeCount ?? 0), + opcodeGas: BigInt(trace.opcodeGas ?? 0), + arrayCbBaseCount: BigInt(trace.arrayCbBase?.count ?? 0), + arrayCbBaseGas: BigInt(trace.arrayCbBase?.gas ?? 0), + arrayCbPerElCount: BigInt(trace.arrayCbPerEl?.count ?? 0), + arrayCbPerElGas: BigInt(trace.arrayCbPerEl?.gas ?? 0), + allocationCount: BigInt(trace.alloc?.count ?? 0), + allocationBytes: BigInt(trace.alloc?.bytes ?? 0), + allocationGas: BigInt(trace.alloc?.gas ?? 0), + jsonParseCount: BigInt(trace.jsonParse?.count ?? 0), + jsonParseGas: BigInt(trace.jsonParse?.gas ?? 0), + jsonParseInputBytes: BigInt(trace.jsonParse?.inputBytes ?? 0), + jsonParseValues: BigInt(trace.jsonParse?.values ?? 0), + jsonParseObjectEntries: BigInt(trace.jsonParse?.objectEntries ?? 0), + jsonParseArrayElements: BigInt(trace.jsonParse?.arrayElements ?? 0), + jsonStringifyCount: BigInt(trace.jsonStringify?.count ?? 0), + jsonStringifyGas: BigInt(trace.jsonStringify?.gas ?? 0), + jsonStringifyOutputBytes: BigInt(trace.jsonStringify?.outputBytes ?? 0), + jsonStringifyValues: BigInt(trace.jsonStringify?.values ?? 0), + jsonStringifyObjectEntries: BigInt(trace.jsonStringify?.objectEntries ?? 0), + jsonStringifyArrayElements: BigInt(trace.jsonStringify?.arrayElements ?? 0), + jsonStringifySortComparisons: BigInt( + trace.jsonStringify?.sortComparisons ?? 0, + ), + hostCallPreCount: BigInt(trace.hostCallPre?.count ?? 0), + hostCallPreGas: BigInt(trace.hostCallPre?.gas ?? 0), + hostCallPostCount: BigInt(trace.hostCallPost?.count ?? 0), + hostCallPostGas: BigInt(trace.hostCallPost?.gas ?? 0), + }; +} + +function expectTraceResult(actual: ExpectedTrace, expected: ExpectedTrace) { + expect(actual).toEqual(expected); +} + function tryDecodeExpectedPayload(payload: string): unknown { const hexish = /^[0-9a-f]+$/i.test(payload) && payload.length % 2 === 0; if (hexish) { diff --git a/libs/test-harness/src/lib/gas-fixtures.ts b/libs/test-harness/src/lib/gas-fixtures.ts index 9f7fc62..599ce6a 100644 --- a/libs/test-harness/src/lib/gas-fixtures.ts +++ b/libs/test-harness/src/lib/gas-fixtures.ts @@ -52,8 +52,8 @@ export const GAS_SAMPLE_FIXTURES: GasFixture[] = [ expected: { resultHash: '4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a', - gasUsed: 179n, - gasRemaining: 999821n, + gasUsed: 74n, + gasRemaining: 999926n, }, }, { @@ -77,8 +77,8 @@ export const GAS_SAMPLE_FIXTURES: GasFixture[] = [ expected: { resultHash: '5092d78885546599f50436ac88fee579843061290508ac2ef0efa541297e405b', - gasUsed: 17347n, - gasRemaining: 982653n, + gasUsed: 17099n, + gasRemaining: 982901n, }, }, { @@ -102,12 +102,12 @@ export const GAS_SAMPLE_FIXTURES: GasFixture[] = [ expected: { resultHash: 'a3fa3495623f19996818ce7b196fc524e687ef2cc4910a6ff628a76460c4e557', - gasUsed: 170347n, - gasRemaining: 829653n, + gasUsed: 170099n, + gasRemaining: 829901n, }, repeatSameContext: { count: 5, - expectedGasUsed: 170347n, + expectedGasUsed: 170099n, }, }, { @@ -131,8 +131,8 @@ export const GAS_SAMPLE_FIXTURES: GasFixture[] = [ expected: { resultHash: '5e8f74961ede79063fa728a34d36f7baf4a563b225df62e4eb9349b94d612a3f', - gasUsed: 61139n, - gasRemaining: 938861n, + gasUsed: 26100n, + gasRemaining: 973900n, }, }, { @@ -156,8 +156,8 @@ export const GAS_SAMPLE_FIXTURES: GasFixture[] = [ expected: { resultHash: '5e8f74961ede79063fa728a34d36f7baf4a563b225df62e4eb9349b94d612a3f', - gasUsed: 51115n, - gasRemaining: 948885n, + gasUsed: 26100n, + gasRemaining: 973900n, }, }, { @@ -185,8 +185,8 @@ export const GAS_SAMPLE_FIXTURES: GasFixture[] = [ expected: { resultHash: 'cbbec14103147af122feaff2419ad885d372d04bfd9d0af1714dd20dff24b6e3', - gasUsed: 40203n, - gasRemaining: 959797n, + gasUsed: 38144n, + gasRemaining: 961856n, }, }, ]; diff --git a/libs/test-harness/src/lib/gas-goldens.spec.ts b/libs/test-harness/src/lib/gas-goldens.spec.ts new file mode 100644 index 0000000..cd80516 --- /dev/null +++ b/libs/test-harness/src/lib/gas-goldens.spec.ts @@ -0,0 +1,112 @@ +import { existsSync, readFileSync } from 'node:fs'; +import { spawnSync } from 'node:child_process'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const repoRoot = path.resolve( + path.dirname(fileURLToPath(import.meta.url)), + '../../../..', +); + +const harnessRoot = path.join(repoRoot, 'tools', 'quickjs-native-harness'); +const fixturesRoot = path.join(harnessRoot, 'fixtures'); +const binPath = path.join(harnessRoot, 'dist', 'quickjs-native-harness'); +const goldensPath = path.join( + repoRoot, + 'libs', + 'test-harness', + 'fixtures', + 'gas-goldens.json', +); +const manifestHex = readFileSync( + path.join( + repoRoot, + 'libs', + 'test-harness', + 'fixtures', + 'abi-manifest', + 'host-v1.bytes.hex', + ), + 'utf8', +).replace(/[\r\n\s]+/g, ''); +const manifestHash = readFileSync( + path.join( + repoRoot, + 'libs', + 'test-harness', + 'fixtures', + 'abi-manifest', + 'host-v1.hash', + ), + 'utf8', +).trim(); + +interface GasGoldenCase { + name: string; + fixture: string; + args?: string[]; + expected: string; +} + +interface ParsedHarnessOutput { + kind: 'RESULT' | 'ERROR'; + payload: string; + gasRemaining: bigint; + gasUsed: bigint; + state?: string; + trace?: unknown; +} + +const cases = JSON.parse(readFileSync(goldensPath, 'utf8')) as GasGoldenCase[]; + +describe('gas goldens', () => { + it('has a built native harness available', () => { + expect(existsSync(binPath)).toBe(true); + }); + + test.each(cases)('$name', ({ fixture, args = [], expected }) => { + const code = readFileSync(path.join(fixturesRoot, fixture), 'utf8'); + const result = spawnSync( + binPath, + [ + '--abi-manifest-hex', + manifestHex, + '--abi-manifest-hash', + manifestHash, + ...args, + '--eval', + code, + ], + { encoding: 'utf8' }, + ); + + if (result.error) { + throw result.error; + } + + const actual = (result.stdout || '').trim(); + expect(parseHarnessOutput(actual)).toEqual(parseHarnessOutput(expected)); + }); +}); + +function parseHarnessOutput(raw: string): ParsedHarnessOutput { + const trimmed = raw.trim(); + const match = + /^(RESULT|ERROR)\s+(.+?)\s+GAS\s+remaining=(\d+)\s+used=(\d+)(?:\s+STATE\s+(.+?))?(?:\s+TRACE\s+(\{.+\}))?$/.exec( + trimmed, + ); + + if (!match) { + throw new Error(`Unable to parse harness output: ${trimmed}`); + } + + const [, kind, payload, remaining, used, state, trace] = match; + return { + kind: kind as 'RESULT' | 'ERROR', + payload, + gasRemaining: BigInt(remaining), + gasUsed: BigInt(used), + ...(state !== undefined ? { state } : {}), + ...(trace !== undefined ? { trace: JSON.parse(trace) } : {}), + }; +} diff --git a/libs/test-harness/src/lib/host-gas.spec.ts b/libs/test-harness/src/lib/host-gas.spec.ts new file mode 100644 index 0000000..0768752 --- /dev/null +++ b/libs/test-harness/src/lib/host-gas.spec.ts @@ -0,0 +1,131 @@ +import { + hasBuiltNativeHarness, + runNativeHarness, +} from './native-harness-test-utils.js'; + +interface HostGasCase { + name: string; + code: string; + requestExpr: string; + responseExpr: string; + units: number; + expectedStatus: number; + gas: { + base: number; + kArg: number; + kRet: number; + kUnits: number; + }; +} + +interface HostGasTrace { + opcodeGas?: number; + arrayCbBase?: { gas?: number }; + arrayCbPerEl?: { gas?: number }; + alloc?: { gas?: number }; + jsonParse?: { gas?: number }; + jsonStringify?: { gas?: number }; +} + +const cases: HostGasCase[] = [ + { + name: 'document-get-ok', + code: "Host.v1.document.get('foo')", + requestExpr: "['foo']", + responseExpr: "({ ok: 'foo', units: 1 })", + units: 1, + expectedStatus: 0, + gas: { base: 20, kArg: 1, kRet: 1, kUnits: 1 }, + }, + { + name: 'document-get-error', + code: "Host.v1.document.get('missing')", + requestExpr: "['missing']", + responseExpr: "({ err: { code: 'NOT_FOUND' }, units: 2 })", + units: 2, + expectedStatus: 1, + gas: { base: 20, kArg: 1, kRet: 1, kUnits: 1 }, + }, + { + name: 'emit-null', + code: 'Host.v1.emit({ a: 1 })', + requestExpr: '[{ a: 1 }]', + responseExpr: '({ ok: null, units: 0 })', + units: 0, + expectedStatus: 0, + gas: { base: 5, kArg: 1, kRet: 0, kUnits: 1 }, + }, +]; + +describe('host gas', () => { + it('has a built native harness available', () => { + expect(hasBuiltNativeHarness()).toBe(true); + }); + + test.each(cases)( + '$name charges the documented host gas formula', + (testCase) => { + const reqLen = dvLength(testCase.requestExpr); + const respLen = dvLength(testCase.responseExpr); + const expectedHostGas = + testCase.gas.base + + testCase.gas.kArg * reqLen + + testCase.gas.kRet * respLen + + testCase.gas.kUnits * testCase.units; + + const result = runNativeHarness([ + '--gas-limit', + '10000', + '--report-gas', + '--gas-trace', + '--eval', + testCase.code, + ]); + + expect(result.status).toBe(testCase.expectedStatus); + expect(result.stderr).toBe(''); + + const usedMatch = result.stdout.match(/used=(\d+)/); + const traceMatch = result.stdout.match(/TRACE (\{.*\})/); + + expect(usedMatch).not.toBeNull(); + expect(traceMatch).not.toBeNull(); + + if (!usedMatch || !traceMatch) { + throw new Error(`Missing gas or trace in output: ${result.stdout}`); + } + + const used = Number(usedMatch[1]); + const trace = JSON.parse(traceMatch[1]) as HostGasTrace; + const nonHostGas = computeNonHostGas(trace); + + expect(used - nonHostGas).toBe(expectedHostGas); + }, + ); +}); + +function dvLength(expr: string): number { + const result = runNativeHarness(['--dv-encode', '--eval', expr], { + includeManifest: false, + }); + expect(result.status).toBe(0); + expect(result.stderr).toBe(''); + + const match = result.stdout.match(/^DV\s+([0-9a-fA-F]+)$/); + expect(match).not.toBeNull(); + if (!match) { + throw new Error(`Unexpected dv encode output: ${result.stdout}`); + } + return match[1].replace(/\s+/g, '').length / 2; +} + +function computeNonHostGas(trace: HostGasTrace): number { + return ( + Number(trace.opcodeGas || 0) + + Number(trace.arrayCbBase?.gas || 0) + + Number(trace.arrayCbPerEl?.gas || 0) + + Number(trace.alloc?.gas || 0) + + Number(trace.jsonParse?.gas || 0) + + Number(trace.jsonStringify?.gas || 0) + ); +} diff --git a/libs/test-harness/src/lib/module-pack-fixtures.ts b/libs/test-harness/src/lib/module-pack-fixtures.ts new file mode 100644 index 0000000..6f7a54d --- /dev/null +++ b/libs/test-harness/src/lib/module-pack-fixtures.ts @@ -0,0 +1,356 @@ +import type { AbiManifest } from '@blue-quickjs/abi-manifest'; +import type { DV } from '@blue-quickjs/dv'; +import { HOST_V1_HASH, HOST_V1_MANIFEST } from './abi-manifest-fixtures.js'; +import { + createDeterminismHost, + DETERMINISM_GAS_LIMIT, + DETERMINISM_INPUT, + type DeterminismHostEnvironment, + type DeterminismInputEnvelope, +} from './determinism-fixtures.js'; + +export interface ModulePackV1FixtureModule { + specifier: string; + source: string; + sourceMap?: string; +} + +export interface ModulePackV1Fixture { + version: 1; + entrySpecifier: string; + entryExport?: string; + modules: ModulePackV1FixtureModule[]; + graphHash: string; + builderVersion: string; + dependencyIntegrity: string; +} + +export interface ProgramArtifactV2ModulePackFixture { + version: 2; + abiId: string; + abiVersion: number; + abiManifestHash: string; + executionProfile: 'baseline-v1' | 'compat-general-v1'; + sourceKind: 'module-pack'; + source: { + modulePack: ModulePackV1Fixture; + }; +} + +export type ModulePackFixtureExpected = + | { + ok: true; + value: DV; + } + | { + ok: false; + errorCode: + | 'MODULE_SPECIFIER_NOT_FOUND' + | 'MODULE_EXPORT_MISSING' + | 'MODULE_RESOLUTION_ERROR' + | 'MODULE_EVALUATION_ERROR'; + errorTag: 'vm/module_pack'; + }; + +export interface ModulePackFixture { + name: string; + program: ProgramArtifactV2ModulePackFixture; + input: DeterminismInputEnvelope; + gasLimit: bigint; + manifest: AbiManifest; + createHost: () => DeterminismHostEnvironment; + expected: ModulePackFixtureExpected; +} + +const MODULE_PACK_BASE = { + version: 2 as const, + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + executionProfile: 'baseline-v1' as const, + sourceKind: 'module-pack' as const, +}; + +const BUILDER_VERSION = 'deterministic-builder-v1'; +const DEPENDENCY_INTEGRITY = + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'; + +function createModulePack(options: { + entrySpecifier: string; + modules: ModulePackV1FixtureModule[]; + entryExport?: string; + graphHash: string; +}): ModulePackV1Fixture { + return { + version: 1, + entrySpecifier: options.entrySpecifier, + ...(options.entryExport ? { entryExport: options.entryExport } : {}), + modules: options.modules, + graphHash: options.graphHash, + builderVersion: BUILDER_VERSION, + dependencyIntegrity: DEPENDENCY_INTEGRITY, + }; +} + +export const MODULE_PACK_FIXTURES: ModulePackFixture[] = [ + { + name: 'module-pack-default-export', + program: { + ...MODULE_PACK_BASE, + source: { + modulePack: createModulePack({ + entrySpecifier: './entry.js', + graphHash: + '68df8be0dee6f4df62f54776c08a61cd42f9b39c74a4968d0217fc748b8b7863', + modules: [ + { + specifier: './entry.js', + source: + "import { base } from './values.js'; export default base + 1;\n", + }, + { + specifier: './values.js', + source: 'export const base = 6;\n', + }, + ], + }), + }, + }, + input: DETERMINISM_INPUT, + gasLimit: DETERMINISM_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + createHost: createDeterminismHost, + expected: { + ok: true, + value: 7, + }, + }, + { + name: 'module-pack-named-export', + program: { + ...MODULE_PACK_BASE, + source: { + modulePack: createModulePack({ + entrySpecifier: './entry.js', + entryExport: 'answer', + graphHash: + '212edbf5272cae51f21fbb306b41103ab57d94b37c0f0f90f0b234f4a8a81df8', + modules: [ + { + specifier: './entry.js', + source: + "import { left, right } from './parts.js'; export const answer = left + right;\n", + }, + { + specifier: './parts.js', + source: 'export const left = 20; export const right = 22;\n', + }, + ], + }), + }, + }, + input: DETERMINISM_INPUT, + gasLimit: DETERMINISM_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + createHost: createDeterminismHost, + expected: { + ok: true, + value: 42, + }, + }, + { + name: 'module-pack-cyclic-imports', + program: { + ...MODULE_PACK_BASE, + source: { + modulePack: createModulePack({ + entrySpecifier: './entry.js', + graphHash: + '4f66500f07dd2bbc0be1a9fb8121a3f9e30c633afdbc4753c269f5110f5d8ba4', + modules: [ + { + specifier: './entry.js', + source: + "import { valueFromB } from './b.js'; export default valueFromB;\n", + }, + { + specifier: './a.js', + source: + "import { getB } from './b.js'; export function getA() { return 40 + getB(); }\n", + }, + { + specifier: './b.js', + source: + "import { getA } from './a.js'; export function getB() { return 2; } export const valueFromB = getA();\n", + }, + ], + }), + }, + }, + input: DETERMINISM_INPUT, + gasLimit: DETERMINISM_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + createHost: createDeterminismHost, + expected: { + ok: true, + value: 42, + }, + }, + { + name: 'module-pack-host-call-tape', + program: { + ...MODULE_PACK_BASE, + source: { + modulePack: createModulePack({ + entrySpecifier: './entry.js', + graphHash: + '2cad30ee71aa78376357c526292004b4efc4864af0c93b0196a84a8e2730e67d', + modules: [ + { + specifier: './entry.js', + source: + "globalThis.Host.v1.emit({ kind: 'module-pack', path: 'path/to/module-pack-doc' });\nexport default { path: 'path/to/module-pack-doc', len: 23 };\n", + }, + ], + }), + }, + }, + input: DETERMINISM_INPUT, + gasLimit: DETERMINISM_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + createHost: createDeterminismHost, + expected: { + ok: true, + value: { path: 'path/to/module-pack-doc', len: 23 }, + }, + }, + { + name: 'module-pack-async-import-host-call', + program: { + ...MODULE_PACK_BASE, + executionProfile: 'compat-general-v1', + source: { + modulePack: createModulePack({ + entrySpecifier: './entry.js', + graphHash: + '629b89a6e192c62e9d7d0a1b6b2debd9bcad6b9110389e949ba5d86156bd000b', + modules: [ + { + specifier: './entry.js', + source: + 'import { plusOne } from "./lib.js";\nexport default Promise.resolve(plusOne(41)).then((value) => { Host.v1.emit({ phase: "async-lib", value }); return value; });\n', + }, + { + specifier: './lib.js', + source: 'export const plusOne = (value) => value + 1;\n', + }, + ], + }), + }, + }, + input: DETERMINISM_INPUT, + gasLimit: DETERMINISM_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + createHost: createDeterminismHost, + expected: { + ok: true, + value: 42, + }, + }, + { + name: 'module-pack-kitchen-sink', + program: { + ...MODULE_PACK_BASE, + executionProfile: 'compat-general-v1', + source: { + modulePack: createModulePack({ + entrySpecifier: './entry.js', + graphHash: + 'ce277312313ac06e3488d98b33b59213baf0d989beca4681b93cff31ba2532be', + modules: [ + { + specifier: './entry.js', + source: + 'import { summarize } from "./workflow.js";\nexport default (async () => {\n const doc = document("path/to/doc");\n const canonical = document.canonical("path/to/doc");\n const result = await summarize(doc.path, canonical.canonical);\n Host.v1.emit({ kind: "kitchen", result });\n return result;\n})();\n', + }, + { + specifier: './workflow.js', + source: + 'export async function summarize(path, canonical) {\n const queue = [];\n queueMicrotask(() => queue.push("micro"));\n await Promise.resolve();\n const records = [\n { id: "b", rank: 2 },\n { id: "a", rank: 1 },\n { id: "c", rank: 2 },\n ];\n records.sort((left, right) => left.rank - right.rank);\n return {\n path,\n canonical,\n order: records.map((record) => record.id).join(","),\n queue: queue.join(","),\n };\n}\n', + }, + ], + }), + }, + }, + input: DETERMINISM_INPUT, + gasLimit: DETERMINISM_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + createHost: createDeterminismHost, + expected: { + ok: true, + value: { + path: 'path/to/doc', + canonical: 'path/to/doc', + order: 'a,b,c', + queue: 'micro', + }, + }, + }, + { + name: 'module-pack-missing-entry-specifier', + program: { + ...MODULE_PACK_BASE, + source: { + modulePack: createModulePack({ + entrySpecifier: './missing.js', + graphHash: + 'd5708a847d11a9574dc665168733100dd503239075a444809380458ca05e608f', + modules: [ + { + specifier: './entry.js', + source: 'export default 1;\n', + }, + ], + }), + }, + }, + input: DETERMINISM_INPUT, + gasLimit: DETERMINISM_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + createHost: createDeterminismHost, + expected: { + ok: false, + errorCode: 'MODULE_SPECIFIER_NOT_FOUND', + errorTag: 'vm/module_pack', + }, + }, + { + name: 'module-pack-missing-export', + program: { + ...MODULE_PACK_BASE, + source: { + modulePack: createModulePack({ + entrySpecifier: './entry.js', + entryExport: 'missing', + graphHash: + '44d6a5d503fe3ddc0c932d2e0dbbaab85f996253d58ff0cfeb0eee905ff9d60e', + modules: [ + { + specifier: './entry.js', + source: 'export const value = 1;\n', + }, + ], + }), + }, + }, + input: DETERMINISM_INPUT, + gasLimit: DETERMINISM_GAS_LIMIT, + manifest: HOST_V1_MANIFEST, + createHost: createDeterminismHost, + expected: { + ok: false, + errorCode: 'MODULE_EXPORT_MISSING', + errorTag: 'vm/module_pack', + }, + }, +]; diff --git a/libs/test-harness/src/lib/module-pack-parity.spec.ts b/libs/test-harness/src/lib/module-pack-parity.spec.ts new file mode 100644 index 0000000..29a1f54 --- /dev/null +++ b/libs/test-harness/src/lib/module-pack-parity.spec.ts @@ -0,0 +1,164 @@ +import { encodeDv } from '@blue-quickjs/dv'; +import { + MODULE_PACK_FIXTURES, + type ModulePackFixture, +} from './module-pack-fixtures.js'; +import { + hasBuiltNativeHarness, + hostManifestArgs, + parseNativeParityOutput, + runNativeHarness, + sha256Hex, + type NativeParitySnapshot, +} from './native-harness-test-utils.js'; + +const MODULE_PACK_NATIVE_BASELINES: Record = { + 'module-pack-default-export': { + ok: true, + valueHash: + 'ca358758f6d27e6cf45272937977a748fd88391db679ceda7dc7bf1f005ee879', + errorCode: null, + errorTag: null, + gasUsed: '204', + gasRemaining: '49796', + tapeHash: null, + tapeLength: 0, + }, + 'module-pack-named-export': { + ok: true, + valueHash: + '7f83f7bda2d63959d34767689f06d47576683d378d9eb8d09386c9a020395c53', + errorCode: null, + errorTag: null, + gasUsed: '221', + gasRemaining: '49779', + tapeHash: null, + tapeLength: 0, + }, + 'module-pack-cyclic-imports': { + ok: true, + valueHash: + '7f83f7bda2d63959d34767689f06d47576683d378d9eb8d09386c9a020395c53', + errorCode: null, + errorTag: null, + gasUsed: '361', + gasRemaining: '49639', + tapeHash: null, + tapeLength: 0, + }, + 'module-pack-host-call-tape': { + ok: true, + valueHash: + 'da95a2e5e931c6478e2dbc7d03b381337d481020e16179cc7c45e0b4e3bf13fd', + errorCode: null, + errorTag: null, + gasUsed: '208', + gasRemaining: '49792', + tapeHash: + 'a5b1bdd5ceb469c9dbe33cceebff0225b36b30496f7af9a7d124bdaf7976b52d', + tapeLength: 1, + }, + 'module-pack-async-import-host-call': { + ok: true, + valueHash: + '7f83f7bda2d63959d34767689f06d47576683d378d9eb8d09386c9a020395c53', + errorCode: null, + errorTag: null, + gasUsed: '344', + gasRemaining: '49656', + tapeHash: + 'd4d5b078527e86afe555a5e7b3bfe31dc80f0325d14b15d5642dee7d4dc4566c', + tapeLength: 1, + }, + 'module-pack-kitchen-sink': { + ok: false, + valueHash: null, + errorCode: "ReferenceError: 'document' is not defined", + errorTag: null, + gasUsed: '425', + gasRemaining: '49575', + tapeHash: null, + tapeLength: 0, + }, + 'module-pack-missing-entry-specifier': { + ok: false, + valueHash: null, + errorCode: 'MODULE_SPECIFIER_NOT_FOUND', + errorTag: 'vm/module_pack', + gasUsed: '0', + gasRemaining: '50000', + tapeHash: null, + tapeLength: 0, + }, + 'module-pack-missing-export': { + ok: false, + valueHash: null, + errorCode: 'MODULE_EXPORT_MISSING', + errorTag: 'vm/module_pack', + gasUsed: '134', + gasRemaining: '49866', + tapeHash: null, + tapeLength: 0, + }, +}; + +const MODULE_PACK_ERROR_CODE_MAP = new Map([ + ['ModuleSpecifierNotFound', 'MODULE_SPECIFIER_NOT_FOUND'], + ['ModuleExportMissing', 'MODULE_EXPORT_MISSING'], + ['ModuleResolutionError', 'MODULE_RESOLUTION_ERROR'], + ['ModuleEvaluationError', 'MODULE_EVALUATION_ERROR'], +]); + +describe('module pack parity', () => { + it('has a built native harness available', () => { + expect(hasBuiltNativeHarness()).toBe(true); + }); + + test.each(MODULE_PACK_FIXTURES)( + '$name matches the native baseline snapshot', + (fixture) => { + const result = runNativeHarness(buildModulePackArgs(fixture), { + includeManifest: false, + }); + + expect(result.stderr).toBe(''); + + const actual = parseNativeParityOutput(result.stdout, { + valueToHash: (value: unknown) => + sha256Hex(Buffer.from(encodeDv(value))), + mapErrorCode: (message: string) => mapModulePackErrorCode(message), + }); + + expect(actual).toEqual(MODULE_PACK_NATIVE_BASELINES[fixture.name]); + }, + ); +}); + +function buildModulePackArgs(fixture: ModulePackFixture): string[] { + const modulePack = fixture.program.source.modulePack; + return [ + ...hostManifestArgs, + '--execution-profile', + fixture.program.executionProfile, + '--gas-limit', + fixture.gasLimit.toString(), + '--report-gas', + '--report-tape', + '--module-entry-specifier', + modulePack.entrySpecifier, + '--module-entry-export', + modulePack.entryExport ?? 'default', + '--module-pack-json', + JSON.stringify(modulePack.modules), + ]; +} + +function mapModulePackErrorCode(message: string): string | null { + for (const [needle, code] of MODULE_PACK_ERROR_CODE_MAP) { + if (message.includes(needle)) { + return code; + } + } + + return null; +} diff --git a/libs/test-harness/src/lib/native-harness-test-utils.ts b/libs/test-harness/src/lib/native-harness-test-utils.ts new file mode 100644 index 0000000..45b2668 --- /dev/null +++ b/libs/test-harness/src/lib/native-harness-test-utils.ts @@ -0,0 +1,183 @@ +import { existsSync } from 'node:fs'; +import path from 'node:path'; +import { spawnSync } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { fileURLToPath } from 'node:url'; +import { + HOST_V1_BYTES_HEX, + HOST_V1_HASH, + HOST_V2_BYTES_HEX, + HOST_V2_HASH, +} from './abi-manifest-fixtures.js'; +import { serializeHostTape, type SmokeTapeRecord } from './smoke-fixtures.js'; + +export const repoRoot = path.resolve( + path.dirname(fileURLToPath(import.meta.url)), + '../../../..', +); + +export const nativeHarnessPath = path.join( + repoRoot, + 'tools', + 'quickjs-native-harness', + 'dist', + 'quickjs-native-harness', +); + +export const nativeHarnessFixturesRoot = path.join( + repoRoot, + 'tools', + 'quickjs-native-harness', + 'fixtures', +); + +export const hostManifestArgs = [ + '--abi-manifest-hex', + HOST_V1_BYTES_HEX, + '--abi-manifest-hash', + HOST_V1_HASH, +] as const; + +export const hostV2ManifestArgs = [ + '--abi-manifest-hex', + HOST_V2_BYTES_HEX, + '--abi-manifest-hash', + HOST_V2_HASH, +] as const; + +export interface NativeHarnessRunResult { + stdout: string; + stderr: string; + status: number; +} + +export interface NativeParitySnapshot { + ok: boolean; + valueHash: string | null; + errorCode: string | null; + errorTag: string | null; + gasUsed: string; + gasRemaining: string; + tapeHash: string | null; + tapeLength: number; +} + +export function hasBuiltNativeHarness(): boolean { + return existsSync(nativeHarnessPath); +} + +export function runNativeHarness( + args: string[], + options?: { includeManifest?: boolean }, +): NativeHarnessRunResult { + const result = spawnSync( + nativeHarnessPath, + [...(options?.includeManifest === false ? [] : hostManifestArgs), ...args], + { + encoding: 'utf8', + }, + ); + + if (result.error) { + throw result.error; + } + + return { + stdout: (result.stdout ?? '').trim(), + stderr: (result.stderr ?? '').trim(), + status: result.status ?? 0, + }; +} + +export function sha256Hex(input: string | Uint8Array): string { + return createHash('sha256').update(input).digest('hex'); +} + +export function hashTape( + tape: SmokeTapeRecord[] | null | undefined, +): string | null { + if (!Array.isArray(tape) || tape.length === 0) { + return null; + } + + return sha256Hex(Buffer.from(serializeHostTape(tape))); +} + +export function normalizeNativeTape(tape: unknown): SmokeTapeRecord[] { + if (!Array.isArray(tape)) { + throw new Error(`native tape must be an array: ${JSON.stringify(tape)}`); + } + + return tape.map((record) => { + const entry = record as Record; + return { + fnId: Number(entry.fnId), + reqLen: Number(entry.reqLen), + respLen: Number(entry.respLen), + units: Number(entry.units), + gasPre: BigInt(entry.gasPre as string | number | bigint), + gasPost: BigInt(entry.gasPost as string | number | bigint), + isError: Boolean(entry.isError), + chargeFailed: Boolean(entry.chargeFailed), + reqHash: String(entry.reqHash), + respHash: String(entry.respHash), + } satisfies SmokeTapeRecord; + }); +} + +export function parseNativeParityOutput( + stdout: string, + options?: { + valueToHash?: (value: unknown) => string; + mapErrorCode?: (message: string) => string | null; + }, +): NativeParitySnapshot { + const gasMatch = stdout.match(/ GAS remaining=(\d+)(?: used=(\d+))?/); + if (!gasMatch || gasMatch.index == null) { + throw new Error(`missing gas suffix in native output: ${stdout}`); + } + + const tapeMarker = ' TAPE '; + const tapeIndex = stdout.lastIndexOf(tapeMarker); + if (tapeIndex < 0) { + throw new Error(`missing tape suffix in native output: ${stdout}`); + } + + const gasStart = gasMatch.index; + const gasRemaining = gasMatch[1]; + const gasUsed = gasMatch[2] ?? '0'; + const tapeJson = stdout.slice(tapeIndex + tapeMarker.length).trim(); + const tape = normalizeNativeTape(JSON.parse(tapeJson)); + + if (stdout.startsWith('RESULT ')) { + const valueJson = stdout.slice('RESULT '.length, gasStart); + const value = JSON.parse(valueJson); + return { + ok: true, + valueHash: options?.valueToHash ? options.valueToHash(value) : null, + errorCode: null, + errorTag: null, + gasUsed, + gasRemaining, + tapeHash: hashTape(tape), + tapeLength: tape.length, + }; + } + + if (stdout.startsWith('ERROR ')) { + const message = stdout.slice('ERROR '.length, gasStart); + const errorCode = options?.mapErrorCode?.(message) ?? message; + return { + ok: false, + valueHash: null, + errorCode, + errorTag: errorCode === message ? null : 'vm/module_pack', + gasUsed, + gasRemaining, + tapeHash: hashTape(tape), + tapeLength: tape.length, + }; + } + + throw new Error(`unexpected native output prefix: ${stdout}`); +} diff --git a/libs/test-harness/src/lib/smoke-fixtures.ts b/libs/test-harness/src/lib/smoke-fixtures.ts index 7c55d08..2284087 100644 --- a/libs/test-harness/src/lib/smoke-fixtures.ts +++ b/libs/test-harness/src/lib/smoke-fixtures.ts @@ -108,8 +108,8 @@ export const SMOKE_BASELINE: SmokeBaseline = { manifestHash: HOST_V1_HASH, resultHash: '4a13893d4d564c7c9e7dcb0b6bbc028b824268585a0cbbdb19ac28a34138f293', - gasUsed: 1638n, - gasRemaining: 48362n, + gasUsed: 397n, + gasRemaining: 49603n, emittedCount: 1, tapeLength: 3, tapeHash: '2ca437d26207d59b369ae74a448d497a79ae482071d61ff8b05fa78a7d5b570f', diff --git a/libs/test-harness/tsconfig.lib.json b/libs/test-harness/tsconfig.lib.json index ca2ab9c..d36da28 100644 --- a/libs/test-harness/tsconfig.lib.json +++ b/libs/test-harness/tsconfig.lib.json @@ -11,16 +11,16 @@ "include": ["src/**/*.ts"], "references": [ { - "path": "../abi-manifest/tsconfig.lib.json" + "path": "../dv/tsconfig.lib.json" }, { - "path": "../quickjs-wasm-build/tsconfig.lib.json" + "path": "../abi-manifest/tsconfig.lib.json" }, { "path": "../quickjs-wasm-constants/tsconfig.lib.json" }, { - "path": "../dv/tsconfig.lib.json" + "path": "../quickjs-wasm-build/tsconfig.lib.json" } ], "exclude": [ diff --git a/libs/test-harness/tsconfig.spec.json b/libs/test-harness/tsconfig.spec.json index f68d9d3..667fc87 100644 --- a/libs/test-harness/tsconfig.spec.json +++ b/libs/test-harness/tsconfig.spec.json @@ -29,6 +29,12 @@ "references": [ { "path": "./tsconfig.lib.json" + }, + { + "path": "../dv/tsconfig.lib.json" + }, + { + "path": "../quickjs-wasm-constants/tsconfig.lib.json" } ] } diff --git a/nx.json b/nx.json index 1322b48..db4ebfd 100644 --- a/nx.json +++ b/nx.json @@ -17,9 +17,9 @@ "!{projectRoot}/.eslintrc.json", "!{projectRoot}/eslint.config.mjs" ], - "quickjsSubmodule": [ - "{workspaceRoot}/vendor/quickjs", - "{workspaceRoot}/vendor/quickjs/**" + "quickjsSource": [ + "{workspaceRoot}/vendor/quickjs-patches/**", + "{workspaceRoot}/tools/scripts/prepare-quickjs-source.sh" ], "sharedGlobals": ["{workspaceRoot}/.github/workflows/ci.yml"] }, diff --git a/package.json b/package.json index a6ff8be..211792e 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "0.0.0", "license": "MIT", "engines": { - "node": ">=20.17.0" + "node": ">=22.0.0" }, "scripts": { "nx": "nx", @@ -11,7 +11,32 @@ "test": "nx run-many -t test", "build": "nx run-many -t build", "typecheck": "nx run-many -t typecheck", - "lint": "nx run-many -t lint --all" + "lint": "nx run-many -t lint --all", + "docs:check-freshness": "node tools/release-evidence/check-release-doc-freshness.mjs", + "playground:dev": "bash apps/bluequickjs-playground/scripts/dev.sh", + "playground:generate": "node apps/bluequickjs-playground/scripts/generate-playground-data.mjs", + "playground:check-generated": "node apps/bluequickjs-playground/scripts/generate-playground-data.mjs --check", + "release-evidence:synthesize": "node tools/release-evidence/synthesize-release-evidence.mjs", + "release-evidence:verify": "node tools/release-evidence/verify-release-evidence.mjs", + "release-evidence:test": "node --test tools/release-evidence/*.test.mjs", + "release-evidence:sbom": "node tools/release-evidence/generate-sbom.mjs", + "release-evidence:licenses": "node tools/release-evidence/generate-license-report.mjs", + "workload:check-public-package-versions": "node tools/workload-certification/check-public-package-versions.mjs", + "workload:check-public-package-coverage": "node tools/workload-certification/check-public-package-coverage.mjs", + "workload:test": "node --test tools/workload-certification/*.test.mjs", + "workload:check-pack-manifests": "node tools/workload-certification/check-pack-manifests.mjs", + "workload:compat-delta": "node apps/ecosystem-certifier/scripts/generate-compatibility-delta-report.mjs", + "typecheck:project-references": "node tools/scripts/check-ts-project-references.mjs", + "quickjs-source:test": "node --test tools/scripts/quickjs-source-prep.test.mjs", + "gas-spec:test": "node --test tools/gas-spec/*.test.mjs", + "test:coverage:critical": "nx run-many -t test --coverage --projects=quickjs-runtime,deterministic-bundler,deterministic-builder,abi-manifest,blue-quickjs-cli,ecosystem-certifier", + "publish-rehearsal:verdaccio": "node tools/workload-certification/run-verdaccio-publish-rehearsal.mjs", + "setup": "bash tools/scripts/setup-dev.sh", + "verify": "bash tools/scripts/verify-dev.sh", + "playground": "bash tools/scripts/playground.sh", + "evidence": "bash tools/scripts/evidence.sh", + "evidence:verify": "bash tools/scripts/evidence-verify.sh", + "doctor": "bash tools/scripts/doctor.sh" }, "private": true, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 485a757..18eb7a8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -99,6 +99,144 @@ importers: specifier: ^4.0.0 version: 4.0.15(@types/node@20.19.9)(@vitest/ui@4.0.15)(jiti@2.4.2)(jsdom@22.1.0)(terser@5.44.1)(yaml@2.8.2) + apps/bluequickjs-playground: + dependencies: + '@blue-quickjs/abi-manifest': + specifier: workspace:* + version: link:../../libs/abi-manifest + '@blue-quickjs/deterministic-builder': + specifier: workspace:* + version: link:../../libs/deterministic-builder + '@blue-quickjs/dv': + specifier: workspace:* + version: link:../../libs/dv + '@blue-quickjs/execution-profiles': + specifier: workspace:* + version: link:../../libs/execution-profiles + '@blue-quickjs/quickjs-runtime': + specifier: workspace:* + version: link:../../libs/quickjs-runtime + '@blue-quickjs/quickjs-wasm': + specifier: workspace:* + version: link:../../libs/quickjs-wasm + '@blue-quickjs/test-harness': + specifier: workspace:* + version: link:../../libs/test-harness + monaco-editor: + specifier: ^0.55.1 + version: 0.55.1 + tslib: + specifier: ^2.3.0 + version: 2.8.1 + + apps/ecosystem-certifier: + dependencies: + '@blue-quickjs/abi-manifest': + specifier: workspace:* + version: link:../../libs/abi-manifest + '@blue-quickjs/deterministic-builder': + specifier: workspace:* + version: link:../../libs/deterministic-builder + '@blue-quickjs/dv': + specifier: workspace:* + version: link:../../libs/dv + '@blue-quickjs/quickjs-runtime': + specifier: workspace:* + version: link:../../libs/quickjs-runtime + '@blue-quickjs/quickjs-wasm': + specifier: workspace:* + version: link:../../libs/quickjs-wasm + '@blue-quickjs/test-harness': + specifier: workspace:* + version: link:../../libs/test-harness + '@noble/hashes': + specifier: ^1.8.0 + version: 1.8.0 + array-move: + specifier: ^4.0.0 + version: 4.0.0 + base64-js: + specifier: ^1.5.1 + version: 1.5.1 + camelcase: + specifier: ^9.0.0 + version: 9.0.0 + chess.js: + specifier: ^1.4.0 + version: 1.4.0 + crc-32: + specifier: ^1.2.2 + version: 1.2.2 + decamelize: + specifier: ^6.0.1 + version: 6.0.1 + deepmerge: + specifier: ^4.3.1 + version: 4.3.1 + diff: + specifier: ^8.0.2 + version: 8.0.2 + dijkstrajs: + specifier: ^1.0.3 + version: 1.0.3 + escape-string-regexp: + specifier: ^5.0.0 + version: 5.0.0 + fast-deep-equal: + specifier: ^3.1.3 + version: 3.1.3 + fast-json-stable-stringify: + specifier: ^2.1.0 + version: 2.1.0 + fastest-levenshtein: + specifier: ^1.0.16 + version: 1.0.16 + fflate: + specifier: ^0.8.2 + version: 0.8.2 + graphlib: + specifier: ^2.1.8 + version: 2.1.8 + he: + specifier: ^1.2.0 + version: 1.2.0 + json-logic-js: + specifier: ^2.0.5 + version: 2.0.5 + linkify-it: + specifier: ^5.0.0 + version: 5.0.0 + lodash-es: + specifier: ^4.17.21 + version: 4.17.23 + markdown-it: + specifier: ^14.1.0 + version: 14.1.1 + path-to-regexp: + specifier: ^8.2.0 + version: 8.3.0 + query-string: + specifier: ^9.3.1 + version: 9.3.1 + semver: + specifier: ^7.7.3 + version: 7.7.3 + sort-keys: + specifier: ^6.0.0 + version: 6.0.0 + spark-md5: + specifier: ^3.0.2 + version: 3.0.2 + tinyqueue: + specifier: ^3.0.0 + version: 3.0.0 + tslib: + specifier: ^2.3.0 + version: 2.8.1 + yaml: + specifier: ^2.8.2 + version: 2.8.2 + apps/smoke-node: dependencies: '@blue-quickjs/dv': @@ -113,9 +251,16 @@ importers: tslib: specifier: ^2.3.0 version: 2.8.1 + devDependencies: + '@blue-quickjs/deterministic-bundler': + specifier: workspace:* + version: link:../../libs/deterministic-bundler apps/smoke-web: dependencies: + '@blue-quickjs/deterministic-bundler': + specifier: workspace:* + version: link:../../libs/deterministic-bundler '@blue-quickjs/dv': specifier: workspace:* version: link:../../libs/dv @@ -141,12 +286,42 @@ importers: specifier: ^2.3.0 version: 2.8.1 + libs/deterministic-builder: + dependencies: + '@blue-quickjs/deterministic-bundler': + specifier: workspace:* + version: link:../deterministic-bundler + tslib: + specifier: ^2.3.0 + version: 2.8.1 + + libs/deterministic-bundler: + dependencies: + '@blue-quickjs/execution-profiles': + specifier: workspace:* + version: link:../execution-profiles + acorn: + specifier: ^8.15.0 + version: 8.15.0 + esbuild: + specifier: ^0.27.4 + version: 0.27.4 + tslib: + specifier: ^2.3.0 + version: 2.8.1 + libs/dv: dependencies: tslib: specifier: ^2.3.0 version: 2.8.1 + libs/execution-profiles: + dependencies: + tslib: + specifier: ^2.3.0 + version: 2.8.1 + libs/quickjs-runtime: dependencies: '@blue-quickjs/abi-manifest': @@ -155,13 +330,22 @@ importers: '@blue-quickjs/dv': specifier: workspace:* version: link:../dv + '@blue-quickjs/execution-profiles': + specifier: workspace:* + version: link:../execution-profiles '@blue-quickjs/quickjs-wasm': specifier: workspace:* version: link:../quickjs-wasm + '@jridgewell/trace-mapping': + specifier: ^0.3.31 + version: 0.3.31 tslib: specifier: ^2.3.0 version: 2.8.1 devDependencies: + '@blue-quickjs/deterministic-bundler': + specifier: workspace:* + version: link:../deterministic-bundler '@blue-quickjs/test-harness': specifier: workspace:* version: link:../test-harness @@ -202,6 +386,15 @@ importers: '@blue-quickjs/dv': specifier: workspace:* version: link:../dv + '@noble/hashes': + specifier: ^1.8.0 + version: 1.8.0 + base64-js: + specifier: ^1.5.1 + version: 1.5.1 + chess.js: + specifier: ^1.4.0 + version: 1.4.0 tslib: specifier: ^2.3.0 version: 2.8.1 @@ -213,6 +406,24 @@ importers: specifier: workspace:* version: link:../quickjs-wasm-constants + tools/blue-quickjs-cli: + dependencies: + '@blue-quickjs/abi-manifest': + specifier: workspace:* + version: link:../../libs/abi-manifest + '@blue-quickjs/deterministic-builder': + specifier: workspace:* + version: link:../../libs/deterministic-builder + '@blue-quickjs/quickjs-runtime': + specifier: workspace:* + version: link:../../libs/quickjs-runtime + '@blue-quickjs/test-harness': + specifier: workspace:* + version: link:../../libs/test-harness + tslib: + specifier: ^2.3.0 + version: 2.8.1 + packages: '@babel/code-frame@7.27.1': @@ -775,156 +986,312 @@ packages: cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.27.4': + resolution: {integrity: sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/android-arm64@0.25.12': resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} engines: {node: '>=18'} cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.27.4': + resolution: {integrity: sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm@0.25.12': resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} engines: {node: '>=18'} cpu: [arm] os: [android] + '@esbuild/android-arm@0.27.4': + resolution: {integrity: sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-x64@0.25.12': resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} engines: {node: '>=18'} cpu: [x64] os: [android] + '@esbuild/android-x64@0.27.4': + resolution: {integrity: sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/darwin-arm64@0.25.12': resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.27.4': + resolution: {integrity: sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-x64@0.25.12': resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} engines: {node: '>=18'} cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.27.4': + resolution: {integrity: sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/freebsd-arm64@0.25.12': resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.27.4': + resolution: {integrity: sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-x64@0.25.12': resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.27.4': + resolution: {integrity: sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/linux-arm64@0.25.12': resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} engines: {node: '>=18'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.27.4': + resolution: {integrity: sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm@0.25.12': resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} engines: {node: '>=18'} cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.27.4': + resolution: {integrity: sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-ia32@0.25.12': resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} engines: {node: '>=18'} cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.27.4': + resolution: {integrity: sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-loong64@0.25.12': resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} engines: {node: '>=18'} cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.27.4': + resolution: {integrity: sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-mips64el@0.25.12': resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.27.4': + resolution: {integrity: sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-ppc64@0.25.12': resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.27.4': + resolution: {integrity: sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-riscv64@0.25.12': resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.27.4': + resolution: {integrity: sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-s390x@0.25.12': resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} engines: {node: '>=18'} cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.27.4': + resolution: {integrity: sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-x64@0.25.12': resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} engines: {node: '>=18'} cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.27.4': + resolution: {integrity: sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/netbsd-arm64@0.25.12': resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-arm64@0.27.4': + resolution: {integrity: sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-x64@0.25.12': resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.27.4': + resolution: {integrity: sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + '@esbuild/openbsd-arm64@0.25.12': resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-arm64@0.27.4': + resolution: {integrity: sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-x64@0.25.12': resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.27.4': + resolution: {integrity: sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/openharmony-arm64@0.25.12': resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] + '@esbuild/openharmony-arm64@0.27.4': + resolution: {integrity: sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + '@esbuild/sunos-x64@0.25.12': resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} engines: {node: '>=18'} cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.27.4': + resolution: {integrity: sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/win32-arm64@0.25.12': resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} engines: {node: '>=18'} cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.27.4': + resolution: {integrity: sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-ia32@0.25.12': resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} engines: {node: '>=18'} cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.27.4': + resolution: {integrity: sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-x64@0.25.12': resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} engines: {node: '>=18'} cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.27.4': + resolution: {integrity: sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@eslint-community/eslint-utils@4.9.0': resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1093,21 +1460,25 @@ packages: resolution: {integrity: sha512-rjjgq+w10GW3APiiIv++MGK28tUgLWFRuhawn0W2HplUXyVdBvEfcdsZgzO8qU34Q4P6yLdMBZl5FfbXMRgHqw==} cpu: [arm64] os: [linux] + libc: [glibc] '@nx/nx-linux-arm64-musl@22.2.2': resolution: {integrity: sha512-awJZJ+y5OcromwHtYiOeq5SZ89X5+PKZQZszHyygZjq/lYt9JnFRIOGsWDJGcb7A3EDXK4IdMaV5HmlMmErYzw==} cpu: [arm64] os: [linux] + libc: [musl] '@nx/nx-linux-x64-gnu@22.2.2': resolution: {integrity: sha512-1d+bz6qqqmVtKmNVXpPhWqTlLozhgq8Da5MV8c1oq+RdPyjMSGBKStDW88RmLuucScIoK88fH1VGQru8NmIrdw==} cpu: [x64] os: [linux] + libc: [glibc] '@nx/nx-linux-x64-musl@22.2.2': resolution: {integrity: sha512-tOEBaxDxk26K9Yh9Z7h42k4pFTxNHIcfdG7Xy9IAlEEDKZOrBt3i0XlTLpRKqhLycrnbKhavFtFg8ZkItMfaVA==} cpu: [x64] os: [linux] + libc: [musl] '@nx/nx-win32-arm64-msvc@22.2.2': resolution: {integrity: sha512-qxGkjSPemLpQtnoyyfplUsSiDRzbwi2kRJ+RbmLg01zsCiJ5UR5nlKxx8H7rnLAPo5XphR9FahVE2HTCfGFzgQ==} @@ -1205,56 +1576,67 @@ packages: resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.53.3': resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.53.3': resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.53.3': resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-loong64-gnu@4.53.3': resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==} cpu: [loong64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-ppc64-gnu@4.53.3': resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.53.3': resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.53.3': resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==} cpu: [riscv64] os: [linux] + libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.53.3': resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.53.3': resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.53.3': resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-openharmony-arm64@4.53.3': resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==} @@ -1360,24 +1742,28 @@ packages: engines: {node: '>=10'} cpu: [arm64] os: [linux] + libc: [glibc] '@swc/core-linux-arm64-musl@1.5.29': resolution: {integrity: sha512-TERh2OICAJz+SdDIK9+0GyTUwF6r4xDlFmpoiHKHrrD/Hh3u+6Zue0d7jQ/he/i80GDn4tJQkHlZys+RZL5UZg==} engines: {node: '>=10'} cpu: [arm64] os: [linux] + libc: [musl] '@swc/core-linux-x64-gnu@1.5.29': resolution: {integrity: sha512-WMDPqU7Ji9dJpA+Llek2p9t7pcy7Bob8ggPUvgsIlv3R/eesF9DIzSbrgl6j3EAEPB9LFdSafsgf6kT/qnvqFg==} engines: {node: '>=10'} cpu: [x64] os: [linux] + libc: [glibc] '@swc/core-linux-x64-musl@1.5.29': resolution: {integrity: sha512-DO14glwpdKY4POSN0201OnGg1+ziaSVr6/RFzuSLggshwXeeyVORiHv3baj7NENhJhWhUy3NZlDsXLnRFkmhHQ==} engines: {node: '>=10'} cpu: [x64] os: [linux] + libc: [musl] '@swc/core-win32-arm64-msvc@1.5.29': resolution: {integrity: sha512-V3Y1+a1zG1zpYXUMqPIHEMEOd+rHoVnIpO/KTyFwAmKVu8v+/xPEVx/AGoYE67x4vDAAvPQrKI3Aokilqa5yVg==} @@ -1456,6 +1842,9 @@ packages: '@types/responselike@1.0.0': resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==} + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + '@typescript-eslint/eslint-plugin@8.49.0': resolution: {integrity: sha512-JXij0vzIaTtCwu6SxTh8qBc66kmf1xs7pI4UOiMDFVct6q86G0Zs7KRcEoJgY3Cav3x5Tq0MF5jwgpgLqgKG3A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1841,6 +2230,10 @@ packages: array-flatten@1.1.1: resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} + array-move@4.0.0: + resolution: {integrity: sha512-+RY54S8OuVvg94THpneQvFRmqWdAHeqtMzgMW6JNurHxe8rsS07cHQdfGkXnTUXiBcyZ0j3SiDIxxj0RPiqCkQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + asn1@0.2.6: resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} @@ -2003,6 +2396,10 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} + camelcase@9.0.0: + resolution: {integrity: sha512-TO9xmyXTZ9HUHI8M1OnvExxYB0eYVS/1e5s7IDMTAoIcwUd+aNcFODs6Xk83mobk0velyHFQgA1yIrvYc6wclw==} + engines: {node: '>=20'} + caniuse-lite@1.0.30001760: resolution: {integrity: sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==} @@ -2017,6 +2414,9 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + chess.js@1.4.0: + resolution: {integrity: sha512-BBJgrrtKQOzFLonR0l+k64A98NLemPwNsCskwb+29bRwobUa4iTm51E1kwGPbWXAcfdDa18nad6vpPPKPWarqw==} + chrome-trace-event@1.0.4: resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} engines: {node: '>=6.0'} @@ -2128,6 +2528,11 @@ packages: resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} engines: {node: '>=10'} + crc-32@1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -2176,9 +2581,17 @@ packages: supports-color: optional: true + decamelize@6.0.1: + resolution: {integrity: sha512-G7Cqgaelq68XHJNGlZ7lrNQyhZGsFqpwtGFexqUv4IQdjKoSYF7ipZ9UuTJZUSQXFj/XaoBLuEVIVqr8EJngEQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + decimal.js@10.6.0: resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} + decode-uri-component@0.4.1: + resolution: {integrity: sha512-+8VxcR21HhTy8nOt6jf20w0c9CADrw1O8d+VZ/YzzCt4bJ3uBjw+D1q2osAB8RnpwwaeYBxy0HyKQxD5JBMuuQ==} + engines: {node: '>=14.16'} + decompress-response@6.0.0: resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} engines: {node: '>=10'} @@ -2186,6 +2599,10 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + defaults@1.0.4: resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} @@ -2218,11 +2635,17 @@ packages: resolution: {integrity: sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==} engines: {node: '>=0.3.1'} + dijkstrajs@1.0.3: + resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==} + domexception@4.0.0: resolution: {integrity: sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==} engines: {node: '>=12'} deprecated: Use your platform's native DOMException instead + dompurify@3.2.7: + resolution: {integrity: sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==} + dotenv-expand@11.0.7: resolution: {integrity: sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==} engines: {node: '>=12'} @@ -2321,6 +2744,11 @@ packages: engines: {node: '>=18'} hasBin: true + esbuild@0.27.4: + resolution: {integrity: sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==} + engines: {node: '>=18'} + hasBin: true + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -2336,6 +2764,10 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + eslint-config-prettier@10.1.8: resolution: {integrity: sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==} hasBin: true @@ -2482,6 +2914,10 @@ packages: fast-uri@3.1.0: resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + fastest-levenshtein@1.0.16: + resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==} + engines: {node: '>= 4.9.1'} + fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -2505,6 +2941,10 @@ packages: filelist@1.0.4: resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} + filter-obj@5.1.0: + resolution: {integrity: sha512-qWeTREPoT7I0bifpPUXtxkZJ1XJzxWtfoWWkdVGqa+eCr3SHW/Ocp89o8vLvbUuQnadybJpjOKu4V+RwO6sGng==} + engines: {node: '>=14.16'} + finalhandler@1.3.1: resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} engines: {node: '>= 0.8'} @@ -2627,6 +3067,9 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + graphlib@2.1.8: + resolution: {integrity: sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==} + gunzip-maybe@1.4.2: resolution: {integrity: sha512-4haO1M4mLO91PW57BMsDFf75UmwoRX0GkdD+Faw+Lr+r/OZrOCS0pIBwOL1xCKQqnQzbNFGgK2V2CpBUPeFNTw==} hasBin: true @@ -2771,6 +3214,10 @@ packages: resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} engines: {node: '>=8'} + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} @@ -2867,6 +3314,9 @@ packages: json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + json-logic-js@2.0.5: + resolution: {integrity: sha512-rTT2+lqcuUmj4DgWfmzupZqQDA64AdmYqizzMPWj3DxGdfFNsxPpcNVSaTj4l8W2tG/+hg7/mQhxjU3aPacO6g==} + json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} @@ -2935,6 +3385,9 @@ packages: resolution: {integrity: sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + linkify-it@5.0.0: + resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} + loader-runner@4.3.1: resolution: {integrity: sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==} engines: {node: '>=6.11.5'} @@ -2954,6 +3407,9 @@ packages: lockfile@1.0.4: resolution: {integrity: sha512-cvbTwETRfsFh4nHsL1eGWapU1XFi5Ot9E85sWAwia7Y7EgB7vfqcZhTKZ+l7hCGxSPoushMv5GKhT5PdLv03WA==} + lodash-es@4.17.23: + resolution: {integrity: sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==} + lodash.debounce@4.0.8: resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} @@ -3017,10 +3473,22 @@ packages: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} engines: {node: '>=10'} + markdown-it@14.1.1: + resolution: {integrity: sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==} + hasBin: true + + marked@14.0.0: + resolution: {integrity: sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==} + engines: {node: '>= 18'} + hasBin: true + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} + mdurl@2.0.0: + resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} + media-typer@0.3.0: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} @@ -3099,6 +3567,9 @@ packages: mlly@1.8.0: resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} + monaco-editor@0.55.1: + resolution: {integrity: sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==} + mrmime@2.0.1: resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} engines: {node: '>=10'} @@ -3262,6 +3733,9 @@ packages: path-to-regexp@0.1.12: resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} + path-to-regexp@8.3.0: + resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} + path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -3380,6 +3854,10 @@ packages: pumpify@1.5.1: resolution: {integrity: sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==} + punycode.js@2.3.1: + resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} + engines: {node: '>=6'} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -3398,6 +3876,10 @@ packages: quansync@0.2.11: resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} + query-string@9.3.1: + resolution: {integrity: sha512-5fBfMOcDi5SA9qj5jZhWAcTtDfKF5WFdd2uD9nVNlbxVv1baq65aALy6qofpNEGELHvisjjasxQp7BlM9gvMzw==} + engines: {node: '>=18'} + querystringify@2.2.0: resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} @@ -3594,6 +4076,10 @@ packages: sonic-boom@4.2.0: resolution: {integrity: sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==} + sort-keys@6.0.0: + resolution: {integrity: sha512-ueSlHJMwpIw42CJ4B11Uxzh/S0p0AlOyiNktlv2KOu5e1JpUE6DlC4AAUjXqesHdBRv/g0wC9Q4vwq0NP2pA9w==} + engines: {node: '>=20'} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -3608,6 +4094,13 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + spark-md5@3.0.2: + resolution: {integrity: sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw==} + + split-on-first@3.0.0: + resolution: {integrity: sha512-qxQJTx2ryR0Dw0ITYyekNQWpz6f8dGd7vffGNflQQ3Iqj9NJ6qiZ7ELpZsJ/QBhIVAiDfXdag3+Gp8RvWa62AA==} + engines: {node: '>=12'} + split2@4.2.0: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} @@ -3745,6 +4238,9 @@ packages: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} + tinyqueue@3.0.0: + resolution: {integrity: sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==} + tinyrainbow@3.0.3: resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} engines: {node: '>=14.0.0'} @@ -3834,6 +4330,9 @@ packages: engines: {node: '>=14.17'} hasBin: true + uc.micro@2.1.0: + resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} + ufo@1.6.1: resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} @@ -4052,6 +4551,7 @@ packages: whatwg-encoding@2.0.0: resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==} engines: {node: '>=12'} + deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation whatwg-mimetype@3.0.0: resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} @@ -4895,81 +5395,159 @@ snapshots: '@esbuild/aix-ppc64@0.25.12': optional: true + '@esbuild/aix-ppc64@0.27.4': + optional: true + '@esbuild/android-arm64@0.25.12': optional: true + '@esbuild/android-arm64@0.27.4': + optional: true + '@esbuild/android-arm@0.25.12': optional: true + '@esbuild/android-arm@0.27.4': + optional: true + '@esbuild/android-x64@0.25.12': optional: true + '@esbuild/android-x64@0.27.4': + optional: true + '@esbuild/darwin-arm64@0.25.12': optional: true + '@esbuild/darwin-arm64@0.27.4': + optional: true + '@esbuild/darwin-x64@0.25.12': optional: true + '@esbuild/darwin-x64@0.27.4': + optional: true + '@esbuild/freebsd-arm64@0.25.12': optional: true + '@esbuild/freebsd-arm64@0.27.4': + optional: true + '@esbuild/freebsd-x64@0.25.12': optional: true + '@esbuild/freebsd-x64@0.27.4': + optional: true + '@esbuild/linux-arm64@0.25.12': optional: true + '@esbuild/linux-arm64@0.27.4': + optional: true + '@esbuild/linux-arm@0.25.12': optional: true + '@esbuild/linux-arm@0.27.4': + optional: true + '@esbuild/linux-ia32@0.25.12': optional: true + '@esbuild/linux-ia32@0.27.4': + optional: true + '@esbuild/linux-loong64@0.25.12': optional: true + '@esbuild/linux-loong64@0.27.4': + optional: true + '@esbuild/linux-mips64el@0.25.12': optional: true + '@esbuild/linux-mips64el@0.27.4': + optional: true + '@esbuild/linux-ppc64@0.25.12': optional: true + '@esbuild/linux-ppc64@0.27.4': + optional: true + '@esbuild/linux-riscv64@0.25.12': optional: true + '@esbuild/linux-riscv64@0.27.4': + optional: true + '@esbuild/linux-s390x@0.25.12': optional: true + '@esbuild/linux-s390x@0.27.4': + optional: true + '@esbuild/linux-x64@0.25.12': optional: true + '@esbuild/linux-x64@0.27.4': + optional: true + '@esbuild/netbsd-arm64@0.25.12': optional: true + '@esbuild/netbsd-arm64@0.27.4': + optional: true + '@esbuild/netbsd-x64@0.25.12': optional: true + '@esbuild/netbsd-x64@0.27.4': + optional: true + '@esbuild/openbsd-arm64@0.25.12': optional: true + '@esbuild/openbsd-arm64@0.27.4': + optional: true + '@esbuild/openbsd-x64@0.25.12': optional: true + '@esbuild/openbsd-x64@0.27.4': + optional: true + '@esbuild/openharmony-arm64@0.25.12': optional: true + '@esbuild/openharmony-arm64@0.27.4': + optional: true + '@esbuild/sunos-x64@0.25.12': optional: true + '@esbuild/sunos-x64@0.27.4': + optional: true + '@esbuild/win32-arm64@0.25.12': optional: true + '@esbuild/win32-arm64@0.27.4': + optional: true + '@esbuild/win32-ia32@0.25.12': optional: true + '@esbuild/win32-ia32@0.27.4': + optional: true + '@esbuild/win32-x64@0.25.12': optional: true + '@esbuild/win32-x64@0.27.4': + optional: true + '@eslint-community/eslint-utils@4.9.0(eslint@9.39.1(jiti@2.4.2))': dependencies: eslint: 9.39.1(jiti@2.4.2) @@ -5569,6 +6147,9 @@ snapshots: dependencies: '@types/node': 20.19.9 + '@types/trusted-types@2.0.7': + optional: true + '@typescript-eslint/eslint-plugin@8.49.0(@typescript-eslint/parser@8.49.0(eslint@9.39.1(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.1(jiti@2.4.2))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 @@ -6121,6 +6702,8 @@ snapshots: array-flatten@1.1.1: {} + array-move@4.0.0: {} + asn1@0.2.6: dependencies: safer-buffer: 2.1.2 @@ -6305,6 +6888,8 @@ snapshots: callsites@3.1.0: {} + camelcase@9.0.0: {} + caniuse-lite@1.0.30001760: {} caseless@0.12.0: {} @@ -6316,6 +6901,8 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 + chess.js@1.4.0: {} + chrome-trace-event@1.0.4: {} cli-cursor@3.1.0: @@ -6420,6 +7007,8 @@ snapshots: path-type: 4.0.0 yaml: 1.10.2 + crc-32@1.2.2: {} + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -6456,14 +7045,20 @@ snapshots: dependencies: ms: 2.1.3 + decamelize@6.0.1: {} + decimal.js@10.6.0: {} + decode-uri-component@0.4.1: {} + decompress-response@6.0.0: dependencies: mimic-response: 3.1.0 deep-is@0.1.4: {} + deepmerge@4.3.1: {} + defaults@1.0.4: dependencies: clone: 1.0.4 @@ -6487,10 +7082,16 @@ snapshots: diff@8.0.2: {} + dijkstrajs@1.0.3: {} + domexception@4.0.0: dependencies: webidl-conversions: 7.0.0 + dompurify@3.2.7: + optionalDependencies: + '@types/trusted-types': 2.0.7 + dotenv-expand@11.0.7: dependencies: dotenv: 16.4.7 @@ -6604,6 +7205,35 @@ snapshots: '@esbuild/win32-ia32': 0.25.12 '@esbuild/win32-x64': 0.25.12 + esbuild@0.27.4: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.4 + '@esbuild/android-arm': 0.27.4 + '@esbuild/android-arm64': 0.27.4 + '@esbuild/android-x64': 0.27.4 + '@esbuild/darwin-arm64': 0.27.4 + '@esbuild/darwin-x64': 0.27.4 + '@esbuild/freebsd-arm64': 0.27.4 + '@esbuild/freebsd-x64': 0.27.4 + '@esbuild/linux-arm': 0.27.4 + '@esbuild/linux-arm64': 0.27.4 + '@esbuild/linux-ia32': 0.27.4 + '@esbuild/linux-loong64': 0.27.4 + '@esbuild/linux-mips64el': 0.27.4 + '@esbuild/linux-ppc64': 0.27.4 + '@esbuild/linux-riscv64': 0.27.4 + '@esbuild/linux-s390x': 0.27.4 + '@esbuild/linux-x64': 0.27.4 + '@esbuild/netbsd-arm64': 0.27.4 + '@esbuild/netbsd-x64': 0.27.4 + '@esbuild/openbsd-arm64': 0.27.4 + '@esbuild/openbsd-x64': 0.27.4 + '@esbuild/openharmony-arm64': 0.27.4 + '@esbuild/sunos-x64': 0.27.4 + '@esbuild/win32-arm64': 0.27.4 + '@esbuild/win32-ia32': 0.27.4 + '@esbuild/win32-x64': 0.27.4 + escalade@3.2.0: {} escape-html@1.0.3: {} @@ -6612,6 +7242,8 @@ snapshots: escape-string-regexp@4.0.0: {} + escape-string-regexp@5.0.0: {} + eslint-config-prettier@10.1.8(eslint@9.39.1(jiti@2.4.2)): dependencies: eslint: 9.39.1(jiti@2.4.2) @@ -6792,6 +7424,8 @@ snapshots: fast-uri@3.1.0: {} + fastest-levenshtein@1.0.16: {} + fdir@6.5.0(picomatch@4.0.3): optionalDependencies: picomatch: 4.0.3 @@ -6810,6 +7444,8 @@ snapshots: dependencies: minimatch: 5.1.6 + filter-obj@5.1.0: {} + finalhandler@1.3.1: dependencies: debug: 2.6.9 @@ -6935,6 +7571,10 @@ snapshots: graceful-fs@4.2.11: {} + graphlib@2.1.8: + dependencies: + lodash: 4.17.21 + gunzip-maybe@1.4.2: dependencies: browserify-zlib: 0.1.4 @@ -7087,6 +7727,8 @@ snapshots: is-interactive@1.0.0: {} + is-plain-obj@4.1.0: {} + is-potential-custom-element-name@1.0.1: {} is-promise@2.2.2: {} @@ -7198,6 +7840,8 @@ snapshots: json-buffer@3.0.1: {} + json-logic-js@2.0.5: {} + json-parse-even-better-errors@2.3.1: {} json-schema-traverse@0.4.1: {} @@ -7275,6 +7919,10 @@ snapshots: lines-and-columns@2.0.3: {} + linkify-it@5.0.0: + dependencies: + uc.micro: 2.1.0 + loader-runner@4.3.1: {} loader-utils@2.0.4: @@ -7297,6 +7945,8 @@ snapshots: dependencies: signal-exit: 3.0.7 + lodash-es@4.17.23: {} + lodash.debounce@4.0.8: {} lodash.includes@4.3.0: {} @@ -7356,8 +8006,21 @@ snapshots: dependencies: semver: 7.7.3 + markdown-it@14.1.1: + dependencies: + argparse: 2.0.1 + entities: 4.5.0 + linkify-it: 5.0.0 + mdurl: 2.0.0 + punycode.js: 2.3.1 + uc.micro: 2.1.0 + + marked@14.0.0: {} + math-intrinsics@1.1.0: {} + mdurl@2.0.0: {} + media-typer@0.3.0: {} merge-descriptors@1.0.3: {} @@ -7417,6 +8080,11 @@ snapshots: pkg-types: 1.3.1 ufo: 1.6.1 + monaco-editor@0.55.1: + dependencies: + dompurify: 3.2.7 + marked: 14.0.0 + mrmime@2.0.1: {} ms@2.0.0: {} @@ -7593,6 +8261,8 @@ snapshots: path-to-regexp@0.1.12: {} + path-to-regexp@8.3.0: {} + path-type@4.0.0: {} pathe@2.0.3: {} @@ -7722,6 +8392,8 @@ snapshots: inherits: 2.0.4 pump: 2.0.1 + punycode.js@2.3.1: {} + punycode@2.3.1: {} pure-rand@7.0.1: {} @@ -7736,6 +8408,12 @@ snapshots: quansync@0.2.11: {} + query-string@9.3.1: + dependencies: + decode-uri-component: 0.4.1 + filter-obj: 5.1.0 + split-on-first: 3.0.0 + querystringify@2.2.0: {} quick-format-unescaped@4.0.4: {} @@ -7977,6 +8655,10 @@ snapshots: dependencies: atomic-sleep: 1.0.0 + sort-keys@6.0.0: + dependencies: + is-plain-obj: 4.1.0 + source-map-js@1.2.1: {} source-map-support@0.5.19: @@ -7991,6 +8673,10 @@ snapshots: source-map@0.6.1: {} + spark-md5@3.0.2: {} + + split-on-first@3.0.0: {} + split2@4.2.0: {} sprintf-js@1.0.3: {} @@ -8137,6 +8823,8 @@ snapshots: fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 + tinyqueue@3.0.0: {} + tinyrainbow@3.0.3: {} tldts-core@6.1.86: {} @@ -8214,6 +8902,8 @@ snapshots: typescript@5.9.3: {} + uc.micro@2.1.0: {} + ufo@1.6.1: {} uglify-js@3.19.3: diff --git a/tools/blue-quickjs-cli/README.md b/tools/blue-quickjs-cli/README.md new file mode 100644 index 0000000..7f337ef --- /dev/null +++ b/tools/blue-quickjs-cli/README.md @@ -0,0 +1,20 @@ +# blue-quickjs CLI + +Deterministic command-line interface for build/run/inspect workflows. + +## Commands + +- `build` — build a deterministic module-pack artifact from an entry path. +- `compat` — emit compatibility diagnostics for an entry path/profile. +- `run` — evaluate an artifact JSON against a manifest/input envelope. +- `inspect` — print artifact metadata including module list, graph hash, + provenance/package hints, and source-map presence. +- `explain-error` — map VM payloads to structured runtime error shapes and + extract source locations (`path:line:column`) from mapped diagnostics. +- `consensus-report` — run wasm-node vs wasm-browser consensus reproducibility + report generation (`tools/consensus-parity/...`), with optional + `--browser chromium|firefox|webkit`. +- `native-report` — run native reproducibility archive generation (diagnostic by + default; add `--strict` to assert zero mismatches). +- `native-parity` — run native parity report helper with strict/trace/baseline + switches. diff --git a/tools/blue-quickjs-cli/eslint.config.mjs b/tools/blue-quickjs-cli/eslint.config.mjs new file mode 100644 index 0000000..3f9aadf --- /dev/null +++ b/tools/blue-quickjs-cli/eslint.config.mjs @@ -0,0 +1,11 @@ +import baseConfig from '../../eslint.config.mjs'; + +export default [ + ...baseConfig, + { + files: ['**/*.ts'], + rules: { + '@typescript-eslint/no-explicit-any': 'off', + }, + }, +]; diff --git a/tools/blue-quickjs-cli/package.json b/tools/blue-quickjs-cli/package.json new file mode 100644 index 0000000..d4923b0 --- /dev/null +++ b/tools/blue-quickjs-cli/package.json @@ -0,0 +1,35 @@ +{ + "name": "@blue-quickjs/blue-quickjs-cli", + "version": "0.0.1", + "private": true, + "type": "module", + "bin": { + "blue-quickjs": "./dist/cli.js" + }, + "main": "./dist/index.js", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + "./package.json": "./package.json", + ".": { + "@blue-quickjs/source": "./src/index.ts", + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" + } + }, + "files": [ + "dist", + "!**/*.tsbuildinfo" + ], + "nx": { + "name": "blue-quickjs-cli" + }, + "dependencies": { + "@blue-quickjs/abi-manifest": "workspace:*", + "@blue-quickjs/deterministic-builder": "workspace:*", + "@blue-quickjs/quickjs-runtime": "workspace:*", + "@blue-quickjs/test-harness": "workspace:*", + "tslib": "^2.3.0" + } +} diff --git a/tools/blue-quickjs-cli/src/cli.ts b/tools/blue-quickjs-cli/src/cli.ts new file mode 100644 index 0000000..976030d --- /dev/null +++ b/tools/blue-quickjs-cli/src/cli.ts @@ -0,0 +1,5 @@ +#!/usr/bin/env node +import { runCli } from './lib/cli.js'; + +const exitCode = await runCli(process.argv.slice(2)); +process.exit(exitCode); diff --git a/tools/blue-quickjs-cli/src/index.ts b/tools/blue-quickjs-cli/src/index.ts new file mode 100644 index 0000000..5f2db8f --- /dev/null +++ b/tools/blue-quickjs-cli/src/index.ts @@ -0,0 +1 @@ +export { runCli, parseArgMap } from './lib/cli.js'; diff --git a/tools/blue-quickjs-cli/src/lib/cli.integration.spec.ts b/tools/blue-quickjs-cli/src/lib/cli.integration.spec.ts new file mode 100644 index 0000000..6070f0e --- /dev/null +++ b/tools/blue-quickjs-cli/src/lib/cli.integration.spec.ts @@ -0,0 +1,185 @@ +import { + existsSync, + mkdtempSync, + readFileSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { HOST_V2_HASH } from '@blue-quickjs/abi-manifest'; +import { describe, expect, it, vi } from 'vitest'; +import { runCli } from './cli.js'; + +describe('blue-quickjs-cli integration behavior', () => { + it('prints help for help and no-command invocations', async () => { + const logSpy = vi.spyOn(console, 'log').mockImplementation(() => { + // Suppress expected CLI help output. + }); + + try { + await expect(runCli(['help'])).resolves.toBe(0); + await expect(runCli([])).resolves.toBe(2); + expect(logSpy).toHaveBeenCalledWith(expect.stringContaining('Commands:')); + } finally { + logSpy.mockRestore(); + } + }); + + it('returns a controlled error for unknown commands', async () => { + const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => { + // Suppress expected CLI error output. + }); + + try { + await expect(runCli(['unknown-command'])).resolves.toBe(1); + expect(errorSpy).toHaveBeenCalledWith( + expect.stringContaining('unknown command: unknown-command'), + ); + } finally { + errorSpy.mockRestore(); + } + }); + + it('builds a Host.v2 ProgramArtifact without falling back to Host.v1', async () => { + const logSpy = vi.spyOn(console, 'log').mockImplementation(() => { + // Suppress expected CLI JSON output. + }); + const tempDir = mkdtempSync(path.join(tmpdir(), 'blue-qjs-cli-build-')); + const entryPath = path.join(tempDir, 'entry.js'); + const outPath = path.join(tempDir, 'program.json'); + writeFileSync( + entryPath, + 'export default function main(input) { return input.value ?? 42; }\n', + 'utf8', + ); + + try { + const exitCode = await runCli([ + 'build', + '--entry', + entryPath, + '--cwd', + tempDir, + '--out', + outPath, + '--profile', + 'compat-binary-v1', + '--abi-id', + 'Host.v2', + '--abi-version', + '2', + ]); + + expect(exitCode).toBe(0); + const payload = JSON.parse(readFileSync(outPath, 'utf8')); + expect(payload.programArtifact.abiId).toBe('Host.v2'); + expect(payload.programArtifact.abiVersion).toBe(2); + expect(payload.programArtifact.abiManifestHash).toBe(HOST_V2_HASH); + expect(payload.programArtifact.sourceKind).toBe('module-pack'); + expect(payload.modulePack.graphHash).toMatch(/^[0-9a-f]{64}$/); + } finally { + logSpy.mockRestore(); + rmSync(tempDir, { recursive: true, force: true }); + } + }); + + it('rejects unsupported ABI IDs before writing an artifact', async () => { + const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => { + // Suppress expected CLI error output. + }); + const tempDir = mkdtempSync(path.join(tmpdir(), 'blue-qjs-cli-bad-abi-')); + const entryPath = path.join(tempDir, 'entry.js'); + const outPath = path.join(tempDir, 'program.json'); + writeFileSync( + entryPath, + 'export default function main() { return 1; }\n', + 'utf8', + ); + + try { + const exitCode = await runCli([ + 'build', + '--entry', + entryPath, + '--cwd', + tempDir, + '--out', + outPath, + '--abi-id', + 'Host.v22', + ]); + + expect(exitCode).toBe(1); + expect(errorSpy).toHaveBeenCalledWith( + expect.stringContaining('unsupported ABI Host.v22'), + ); + expect(existsSync(outPath)).toBe(false); + } finally { + errorSpy.mockRestore(); + rmSync(tempDir, { recursive: true, force: true }); + } + }); + + it('maps raw VM errors through explain-error', async () => { + const logSpy = vi.spyOn(console, 'log').mockImplementation(() => { + // Suppress expected CLI JSON output. + }); + + try { + await expect( + runCli([ + 'explain-error', + '--raw', + 'ERROR ModuleSpecifierNotFound: ./missing.js at ./entry.js:3:1 GAS remaining=10', + ]), + ).resolves.toBe(0); + + const output = JSON.parse(String(logSpy.mock.calls.at(-1)?.[0])); + expect(output.kind).toBe('module-pack'); + expect(output.code).toBe('MODULE_SPECIFIER_NOT_FOUND'); + expect(output.mappedLocations).toEqual([ + { source: './entry.js', line: 3, column: 1 }, + ]); + } finally { + logSpy.mockRestore(); + } + }); + + it.each([ + ['OutOfGas', 'out-of-gas', 'OUT_OF_GAS'], + ['HostError: document.get failed', 'host', 'HOST_ERROR'], + [ + 'ModuleExportMissing: missing default export', + 'module-pack', + 'MODULE_EXPORT_MISSING', + ], + [ + 'ModuleResolutionError: unsupported specifier', + 'module-pack', + 'MODULE_RESOLUTION_ERROR', + ], + [ + 'ModuleEvaluationError: thrown from entry', + 'module-pack', + 'MODULE_EVALUATION_ERROR', + ], + ['ReferenceError: value is not defined', 'js-exception', 'JS_EXCEPTION'], + ])('maps %s VM payloads through explain-error', async (raw, kind, code) => { + const logSpy = vi.spyOn(console, 'log').mockImplementation(() => { + // Suppress expected CLI JSON output. + }); + + try { + await expect(runCli(['explain-error', '--payload', raw])).resolves.toBe( + 0, + ); + + const output = JSON.parse(String(logSpy.mock.calls.at(-1)?.[0])); + expect(output.kind).toBe(kind); + expect(output.code).toBe(code); + } finally { + logSpy.mockRestore(); + } + }); +}); diff --git a/tools/blue-quickjs-cli/src/lib/cli.spec.ts b/tools/blue-quickjs-cli/src/lib/cli.spec.ts new file mode 100644 index 0000000..b189e0a --- /dev/null +++ b/tools/blue-quickjs-cli/src/lib/cli.spec.ts @@ -0,0 +1,261 @@ +import { existsSync, mkdtempSync, rmSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { HOST_V1_HASH, HOST_V2_HASH } from '@blue-quickjs/abi-manifest'; +import { + buildConsensusReportArgs, + buildNativeArchiveArgs, + buildNativeParityArgs, + extractStackLocations, + parseArgMap, + resolveBuildAbiOptions, + runCli, +} from './cli.js'; + +describe('blue-quickjs-cli argument parsing', () => { + it('parses command and key/value options', () => { + const parsed = parseArgMap([ + 'build', + '--entry', + 'src/main.ts', + '--profile', + 'compat-binary-v1', + '--allow-incompatible', + ]); + + expect(parsed.command).toBe('build'); + expect(parsed.options.get('entry')).toBe('src/main.ts'); + expect(parsed.options.get('profile')).toBe('compat-binary-v1'); + expect(parsed.options.get('allow-incompatible')).toBe(true); + }); + + it('throws on unexpected positional options', () => { + expect(() => parseArgMap(['run', '--artifact', 'a.json', 'extra'])).toThrow( + /unexpected positional argument/i, + ); + }); + + it('extracts and de-duplicates stack locations', () => { + const locations = extractStackLocations( + 'ModuleEvaluationError: Error at src/app.ts:12:4 and src/app.ts:12:4, helper ./entry.js:3:1', + ); + + expect(locations).toEqual([ + { source: 'src/app.ts', line: 12, column: 4 }, + { source: './entry.js', line: 3, column: 1 }, + ]); + }); + + it('builds consensus-report forwarded arguments', () => { + const { options } = parseArgMap([ + 'consensus-report', + '--out-dir', + 'artifacts/custom', + '--base-url', + 'http://127.0.0.1:4300', + '--browser', + 'firefox', + '--reuse-server', + ]); + + expect(buildConsensusReportArgs(options)).toEqual([ + '--out-dir', + 'artifacts/custom', + '--base-url', + 'http://127.0.0.1:4300', + '--browser', + 'firefox', + '--reuse-server', + ]); + }); + + it('builds native-report forwarded arguments', () => { + const { options } = parseArgMap([ + 'native-report', + '--strict', + '--out-dir', + 'artifacts/native', + '--gas-charge-tape-capacity', + '512', + ]); + + expect(buildNativeArchiveArgs(options)).toEqual([ + '--strict', + '--out-dir', + 'artifacts/native', + '--gas-charge-tape-capacity', + '512', + ]); + }); + + it('builds native-parity forwarded arguments', () => { + const { options } = parseArgMap([ + 'native-parity', + '--out', + 'parity.json', + '--compare', + 'baseline.json', + '--gas-charge-tape-capacity', + '128', + '--assert-match', + '--include-gas-trace', + '--include-gas-charge-tape', + ]); + + expect(buildNativeParityArgs(options)).toEqual([ + '--out', + 'parity.json', + '--compare', + 'baseline.json', + '--gas-charge-tape-capacity', + '128', + '--assert-match', + '--include-gas-trace', + '--include-gas-charge-tape', + ]); + }); + + it('resolves Host.v1@1 to the Host.v1 manifest hash', () => { + const { options } = parseArgMap(['build', '--entry', 'src/main.ts']); + + expect(resolveBuildAbiOptions(options)).toEqual({ + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + }); + }); + + it('resolves Host.v2@2 to the Host.v2 manifest hash', () => { + const { options } = parseArgMap([ + 'build', + '--entry', + 'src/main.ts', + '--abi-id', + 'Host.v2', + ]); + + expect(resolveBuildAbiOptions(options)).toEqual({ + abiId: 'Host.v2', + abiVersion: 2, + abiManifestHash: HOST_V2_HASH, + }); + }); + + it('rejects unsupported ABI id/version pairs', () => { + const cases = [ + [ + 'build', + '--entry', + 'src/main.ts', + '--abi-id', + 'Host.v2', + '--abi-version', + '1', + ], + [ + 'build', + '--entry', + 'src/main.ts', + '--abi-id', + 'Host.v1', + '--abi-version', + '2', + ], + [ + 'build', + '--entry', + 'src/main.ts', + '--abi-id', + 'Host.v3', + '--abi-version', + '3', + ], + ['build', '--entry', 'src/main.ts', '--abi-id', 'Host.v22'], + ]; + + for (const args of cases) { + const { options } = parseArgMap(args); + expect(() => resolveBuildAbiOptions(options)).toThrow(/unsupported ABI/i); + } + }); + + it('rejects explicit ABI manifest hashes that do not match the selected ABI pair', () => { + const { options } = parseArgMap([ + 'build', + '--entry', + 'src/main.ts', + '--abi-id', + 'Host.v2', + '--abi-version', + '2', + '--abi-manifest-hash', + HOST_V1_HASH, + ]); + + expect(() => resolveBuildAbiOptions(options)).toThrow( + /abi manifest hash mismatch/i, + ); + }); + + it('fails unsupported ABI builds before writing an artifact', async () => { + const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => { + // Suppress expected CLI error output for this negative-path test. + }); + const tempDir = mkdtempSync(path.join(tmpdir(), 'blue-qjs-cli-')); + const outPath = path.join(tempDir, 'unsupported-abi.program.json'); + expect(existsSync(outPath)).toBe(false); + + try { + const exitCode = await runCli([ + 'build', + '--entry', + 'missing-entry.ts', + '--abi-id', + 'Host.v3', + '--abi-version', + '3', + '--out', + outPath, + ]); + + expect(exitCode).toBe(1); + expect(errorSpy).toHaveBeenCalledWith( + expect.stringContaining('unsupported ABI Host.v3@3'), + ); + expect(existsSync(outPath)).toBe(false); + } finally { + errorSpy.mockRestore(); + rmSync(tempDir, { recursive: true, force: true }); + } + }); + + it('rejects malformed gas versions before writing an artifact', async () => { + const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => { + // Suppress expected CLI error output for this negative-path test. + }); + const tempDir = mkdtempSync(path.join(tmpdir(), 'blue-qjs-cli-')); + const outPath = path.join(tempDir, 'bad-gas.program.json'); + expect(existsSync(outPath)).toBe(false); + + try { + const exitCode = await runCli([ + 'build', + '--entry', + 'missing-entry.ts', + '--gas-version', + '3foo', + '--out', + outPath, + ]); + + expect(exitCode).toBe(1); + expect(errorSpy).toHaveBeenCalledWith( + expect.stringContaining('--gas-version must be a u32 integer'), + ); + expect(existsSync(outPath)).toBe(false); + } finally { + errorSpy.mockRestore(); + rmSync(tempDir, { recursive: true, force: true }); + } + }); +}); diff --git a/tools/blue-quickjs-cli/src/lib/cli.ts b/tools/blue-quickjs-cli/src/lib/cli.ts new file mode 100644 index 0000000..6201d24 --- /dev/null +++ b/tools/blue-quickjs-cli/src/lib/cli.ts @@ -0,0 +1,763 @@ +import { spawnSync } from 'node:child_process'; +import { existsSync } from 'node:fs'; +import { readFile, writeFile } from 'node:fs/promises'; +import path from 'node:path'; +import process from 'node:process'; +import { + HOST_V1_HASH, + HOST_V1_MANIFEST, + HOST_V2_HASH, + HOST_V2_MANIFEST, + type AbiManifest, + validateAbiManifest, +} from '@blue-quickjs/abi-manifest'; +import { + buildDeterministicModulePack, + type DeterministicExecutionProfile, +} from '@blue-quickjs/deterministic-builder'; +import { + type ProgramArtifact, + type ProgramArtifactV2, + type HostDispatcherHandlers, + evaluate, + validateInputEnvelope, + validateProgramArtifact, + validateProgramArtifactV2, +} from '@blue-quickjs/quickjs-runtime'; +import { DETERMINISM_INPUT } from '@blue-quickjs/test-harness'; + +type ArgValue = string | true; +type ArgMap = Map; +type StackLocation = { + source: string; + line: number; + column: number; +}; +type SupportedAbiOptions = { + abiId: 'Host.v1' | 'Host.v2'; + abiVersion: 1 | 2; + abiManifestHash: string; +}; + +export function parseArgMap(args: string[]): { + command: string | null; + options: ArgMap; +} { + if (args.length === 0) { + return { command: null, options: new Map() }; + } + + const [command, ...rest] = args; + const options = new Map(); + + for (let i = 0; i < rest.length; i += 1) { + const token = rest[i]; + if (!token.startsWith('--')) { + throw new Error(`unexpected positional argument: ${token}`); + } + const key = token.slice(2); + const maybeValue = rest[i + 1]; + if (maybeValue && !maybeValue.startsWith('--')) { + options.set(key, maybeValue); + i += 1; + continue; + } + options.set(key, true); + } + + return { command, options }; +} + +export async function runCli(args: string[]): Promise { + try { + const { command, options } = parseArgMap(args); + if (!command) { + printHelp(); + return 2; + } + + switch (command) { + case 'build': + return await runBuild(options); + case 'run': + return await runEvaluate(options); + case 'consensus-report': + return await runConsensusReport(options); + case 'native-report': + return await runNativeArchiveReport(options); + case 'native-parity': + return await runNativeParityReport(options); + case 'compat': + return await runCompat(options); + case 'inspect': + return await runInspect(options); + case 'explain-error': + return await runExplainError(options); + case 'help': + case '--help': + case '-h': + printHelp(); + return 0; + default: + throw new Error(`unknown command: ${command}`); + } + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + console.error(`blue-quickjs-cli error: ${message}`); + return 1; + } +} + +async function runBuild(options: ArgMap): Promise { + const entryPath = getRequiredString(options, 'entry'); + const profile = (getOptionalString(options, 'profile') ?? + 'baseline-v1') as DeterministicExecutionProfile; + const cwd = getOptionalString(options, 'cwd') ?? process.cwd(); + const allowIncompatible = options.has('allow-incompatible'); + const { abiId, abiVersion, abiManifestHash } = + resolveBuildAbiOptions(options); + const gasVersionRaw = getOptionalString(options, 'gas-version'); + const gasVersion = + gasVersionRaw !== undefined + ? parseU32Option('gas-version', gasVersionRaw) + : undefined; + const outPath = + getOptionalString(options, 'out') ?? + path.resolve(cwd, `${path.basename(entryPath)}.program.json`); + + const result = await buildDeterministicModulePack({ + entryPath, + absWorkingDir: cwd, + profile, + emitProgramArtifact: true, + rejectIncompatible: !allowIncompatible, + abiId, + abiVersion, + abiManifestHash, + ...(gasVersion !== undefined ? { gasVersion } : {}), + }); + + if (!result.programArtifact) { + throw new Error('builder did not emit ProgramArtifact.v2'); + } + + const payload = { + programArtifact: result.programArtifact, + modulePack: result.modulePack, + compatibilityReport: result.compatibilityReport, + }; + await writeJsonFile(outPath, payload); + + console.log( + JSON.stringify( + { + outPath, + profile, + compatibilityOk: result.compatibility.ok, + moduleCount: result.modulePack.modules.length, + graphHash: result.modulePack.graphHash, + }, + null, + 2, + ), + ); + + return result.compatibility.ok ? 0 : 2; +} + +async function runCompat(options: ArgMap): Promise { + const entryPath = getRequiredString(options, 'entry'); + const profile = (getOptionalString(options, 'profile') ?? + 'baseline-v1') as DeterministicExecutionProfile; + const cwd = getOptionalString(options, 'cwd') ?? process.cwd(); + const outPath = getOptionalString(options, 'out'); + + const result = await buildDeterministicModulePack({ + entryPath, + absWorkingDir: cwd, + profile, + rejectIncompatible: false, + emitProgramArtifact: false, + }); + + if (outPath) { + await writeJsonFile(outPath, result.compatibilityReport); + } + + console.log(JSON.stringify(result.compatibilityReport, null, 2)); + return result.compatibilityReport.ok ? 0 : 2; +} + +async function runInspect(options: ArgMap): Promise { + const artifactPath = getRequiredString(options, 'artifact'); + const artifactJson = await readJsonFile(artifactPath); + const program = normalizeProgramArtifact(artifactJson); + const summary = summarizeProgramArtifact(program); + console.log(JSON.stringify(summary, null, 2)); + return 0; +} + +async function runEvaluate(options: ArgMap): Promise { + const artifactPath = getRequiredString(options, 'artifact'); + const manifestPath = getOptionalString(options, 'manifest'); + const inputPath = getOptionalString(options, 'input'); + const gasLimit = BigInt(getOptionalString(options, 'gas-limit') ?? '5000000'); + + const artifactJson = await readJsonFile(artifactPath); + const program = normalizeProgramArtifact(artifactJson); + const manifest = manifestPath + ? validateAbiManifest((await readJsonFile(manifestPath)) as AbiManifest) + : defaultManifestForProgram(program); + const input = inputPath + ? validateInputEnvelope(await readJsonFile(inputPath)) + : validateInputEnvelope(DETERMINISM_INPUT); + + const result = await evaluate({ + program, + input, + gasLimit, + manifest, + handlers: createCliHostHandlers(), + tape: { capacity: 64 }, + }); + + if (result.ok) { + console.log( + JSON.stringify( + { + ok: true, + value: result.value, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + tapeLength: (result.tape ?? []).length, + }, + null, + 2, + ), + ); + return 0; + } + + const mappedLocations = extractStackLocations(result.message); + console.log( + JSON.stringify( + { + ok: false, + type: result.type, + code: result.error.code, + tag: 'tag' in result.error ? result.error.tag : null, + message: result.message, + mappedLocations, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + }, + null, + 2, + ), + ); + return 1; +} + +async function runExplainError(options: ArgMap): Promise { + const raw = getOptionalString(options, 'raw'); + const payloadOption = getOptionalString(options, 'payload'); + const manifestPath = getOptionalString(options, 'manifest'); + + const payload = payloadOption ?? extractPayloadFromRaw(raw); + if (!payload) { + throw new Error('explain-error requires --payload or --raw'); + } + + const manifest = manifestPath + ? validateAbiManifest((await readJsonFile(manifestPath)) as AbiManifest) + : HOST_V1_MANIFEST; + const mapped = mapVmPayload(payload, manifest); + const mappedLocations = extractStackLocations(payload); + console.log( + JSON.stringify( + { + ...mapped, + mappedLocations, + }, + null, + 2, + ), + ); + return 0; +} + +async function runConsensusReport(options: ArgMap): Promise { + const cwd = resolveCliRepoRoot(getOptionalString(options, 'cwd')); + const scriptPath = path.join( + cwd, + 'tools/consensus-parity/scripts/archive-consensus-reproducibility-report.mjs', + ); + const args = buildConsensusReportArgs(options); + return runNodeScript(scriptPath, args, cwd); +} + +async function runNativeArchiveReport(options: ArgMap): Promise { + const cwd = resolveCliRepoRoot(getOptionalString(options, 'cwd')); + const scriptPath = path.join( + cwd, + 'tools/quickjs-native-harness/scripts/archive-reproducibility-report.mjs', + ); + const args = buildNativeArchiveArgs(options); + return runNodeScript(scriptPath, args, cwd); +} + +async function runNativeParityReport(options: ArgMap): Promise { + const cwd = resolveCliRepoRoot(getOptionalString(options, 'cwd')); + const scriptPath = path.join( + cwd, + 'tools/quickjs-native-harness/scripts/parity-report.mjs', + ); + const args = buildNativeParityArgs(options); + return runNodeScript(scriptPath, args, cwd); +} + +function createCliHostHandlers(): HostDispatcherHandlers { + return { + document: { + get: (path: string) => ({ ok: { path }, units: 1 }), + getCanonical: (path: string) => ({ ok: { canonical: path }, units: 1 }), + }, + emit: () => ({ ok: null, units: 0 }), + }; +} + +function normalizeProgramArtifact( + value: unknown, +): ProgramArtifact | ProgramArtifactV2 { + if (value && typeof value === 'object' && !Array.isArray(value)) { + const record = value as Record; + if (record.programArtifact) { + return validateProgramArtifactV2(record.programArtifact); + } + if (record.program) { + const program = record.program; + if ( + program && + typeof program === 'object' && + !Array.isArray(program) && + (program as { version?: unknown }).version === 2 + ) { + return validateProgramArtifactV2(program); + } + return validateProgramArtifact(program); + } + if (record.version === 2) { + return validateProgramArtifactV2(record); + } + } + + return validateProgramArtifact(value); +} + +function summarizeProgramArtifact( + program: ProgramArtifact | ProgramArtifactV2, +): Record { + if (isProgramArtifactV2(program)) { + const modulePack = + program.sourceKind === 'module-pack' && 'modulePack' in program.source + ? program.source.modulePack + : null; + const moduleSpecifiers = modulePack + ? modulePack.modules.map((module) => module.specifier) + : []; + const modulesWithSourceMap = modulePack + ? modulePack.modules.filter((module) => !!module.sourceMap).length + : 0; + const packages = modulePack + ? [ + ...new Set( + modulePack.modules + .map((module) => module.originMeta?.packageName) + .filter((value): value is string => Boolean(value)), + ), + ].sort() + : []; + return { + version: program.version, + sourceKind: program.sourceKind, + executionProfile: program.executionProfile, + abiId: program.abiId, + abiVersion: program.abiVersion, + abiManifestHash: program.abiManifestHash, + engineBuildHash: program.engineBuildHash ?? null, + gasVersion: program.gasVersion ?? null, + entrySpecifier: modulePack?.entrySpecifier ?? null, + entryExport: modulePack?.entryExport ?? 'default', + moduleCount: modulePack ? modulePack.modules.length : null, + graphHash: modulePack ? modulePack.graphHash : null, + builderVersion: modulePack?.builderVersion ?? null, + dependencyIntegrity: modulePack?.dependencyIntegrity ?? null, + moduleSpecifiers, + modulesWithSourceMap, + diagnosticsMeta: modulePack?.diagnosticsMeta ?? null, + npmPackages: packages, + }; + } + + const legacy = program; + return { + version: 1, + sourceKind: 'script', + executionProfile: legacy.executionProfile ?? 'baseline-v1', + abiId: legacy.abiId, + abiVersion: legacy.abiVersion, + abiManifestHash: legacy.abiManifestHash, + gasVersion: legacy.gasVersion ?? null, + codeUnits: legacy.code.length, + }; +} + +export function extractStackLocations(message: string): StackLocation[] { + const matches = message.matchAll( + /([^\s:()]+(?:\.[cm]?js|\.ts|\.tsx|\.jsx|\.mjs)):(\d+):(\d+)/g, + ); + const dedup = new Set(); + const locations: StackLocation[] = []; + + for (const match of matches) { + const source = match[1]; + const line = Number(match[2]); + const column = Number(match[3]); + if ( + !source || + !Number.isInteger(line) || + !Number.isInteger(column) || + line <= 0 || + column <= 0 + ) { + continue; + } + const key = `${source}:${line}:${column}`; + if (dedup.has(key)) { + continue; + } + dedup.add(key); + locations.push({ source, line, column }); + } + + return locations; +} + +export function resolveBuildAbiOptions(options: ArgMap): SupportedAbiOptions { + const abiId = getOptionalString(options, 'abi-id') ?? 'Host.v1'; + const rawAbiVersion = getOptionalString(options, 'abi-version'); + const abiVersion = + rawAbiVersion === undefined + ? defaultAbiVersionForId(abiId) + : parseAbiVersion(rawAbiVersion); + const supportedAbi = resolveSupportedAbi({ id: abiId, version: abiVersion }); + const expectedManifestHash = supportedAbi.abiManifestHash; + const abiManifestHash = + getOptionalString(options, 'abi-manifest-hash') ?? expectedManifestHash; + + if (abiManifestHash !== expectedManifestHash) { + throw new Error( + `abi manifest hash mismatch for ${abiId}@${abiVersion}: expected ${expectedManifestHash}`, + ); + } + + return { + abiId: supportedAbi.abiId, + abiVersion: supportedAbi.abiVersion, + abiManifestHash, + }; +} + +function defaultAbiVersionForId(abiId: string): 1 | 2 { + if (abiId === 'Host.v1') { + return 1; + } + if (abiId === 'Host.v2') { + return 2; + } + throw new Error(`unsupported ABI ${abiId}`); +} + +function parseAbiVersion(rawAbiVersion: string): number { + const abiVersion = Number.parseInt(rawAbiVersion, 10); + if (!/^\d+$/.test(rawAbiVersion) || !Number.isSafeInteger(abiVersion)) { + throw new Error('--abi-version must be a non-negative integer'); + } + return abiVersion; +} + +function resolveSupportedAbi(abi: { + id: string; + version: number; +}): SupportedAbiOptions { + if (abi.id === 'Host.v1' && abi.version === 1) { + return { + abiId: 'Host.v1', + abiVersion: 1, + abiManifestHash: HOST_V1_HASH, + }; + } + if (abi.id === 'Host.v2' && abi.version === 2) { + return { + abiId: 'Host.v2', + abiVersion: 2, + abiManifestHash: HOST_V2_HASH, + }; + } + throw new Error(`unsupported ABI ${abi.id}@${abi.version}`); +} + +function defaultManifestForProgram( + program: ProgramArtifact | ProgramArtifactV2, +): AbiManifest { + if (program.abiId === 'Host.v2') { + return HOST_V2_MANIFEST; + } + return HOST_V1_MANIFEST; +} + +function extractPayloadFromRaw(raw?: string): string | null { + if (!raw) { + return null; + } + const trimmed = raw.trim(); + if (trimmed.startsWith('ERROR ')) { + const gasMarker = ' GAS remaining='; + const gasIndex = trimmed.lastIndexOf(gasMarker); + if (gasIndex >= 0) { + return trimmed.slice('ERROR '.length, gasIndex).trim(); + } + return trimmed.slice('ERROR '.length).trim(); + } + return trimmed; +} + +function getRequiredString(options: ArgMap, key: string): string { + const value = getOptionalString(options, key); + if (!value) { + throw new Error(`missing required option --${key}`); + } + return value; +} + +function getOptionalString(options: ArgMap, key: string): string | undefined { + const value = options.get(key); + return typeof value === 'string' ? value : undefined; +} + +function parseU32Option(key: string, value: string): number { + if (!/^\d+$/.test(value)) { + throw new Error(`--${key} must be a u32 integer`); + } + const parsed = Number(value); + if (!Number.isSafeInteger(parsed) || parsed > 0xffffffff) { + throw new Error(`--${key} must be a u32 integer`); + } + return parsed; +} + +function resolveCliRepoRoot(cwdOverride?: string): string { + const start = path.resolve(cwdOverride ?? process.cwd()); + const root = findWorkspaceRoot(start); + if (!root) { + throw new Error( + 'unable to resolve workspace root (expected pnpm-workspace.yaml in parent directories)', + ); + } + return root; +} + +function findWorkspaceRoot(start: string): string | null { + let cursor = start; + while (true) { + if (existsSync(path.join(cursor, 'pnpm-workspace.yaml'))) { + return cursor; + } + const parent = path.dirname(cursor); + if (parent === cursor) { + return null; + } + cursor = parent; + } +} + +function runNodeScript( + scriptPath: string, + args: string[], + cwd: string, +): number { + if (!existsSync(scriptPath)) { + throw new Error(`script not found: ${scriptPath}`); + } + const result = spawnSync(process.execPath, [scriptPath, ...args], { + cwd, + stdio: 'inherit', + }); + if (result.error) { + throw result.error; + } + if (result.status === null) { + throw new Error(`script exited without status: ${scriptPath}`); + } + return result.status; +} + +export function buildConsensusReportArgs(options: ArgMap): string[] { + const args: string[] = []; + appendStringOption(args, options, 'out-dir'); + appendStringOption(args, options, 'base-url'); + appendStringOption(args, options, 'browser'); + appendBooleanFlag(args, options, 'reuse-server'); + return args; +} + +export function buildNativeArchiveArgs(options: ArgMap): string[] { + const args: string[] = []; + appendBooleanFlag(args, options, 'strict'); + appendStringOption(args, options, 'out-dir'); + appendStringOption(args, options, 'gas-charge-tape-capacity'); + return args; +} + +export function buildNativeParityArgs(options: ArgMap): string[] { + const args: string[] = []; + appendStringOption(args, options, 'out'); + appendStringOption(args, options, 'compare'); + appendStringOption(args, options, 'gas-charge-tape-capacity'); + appendStringOption(args, options, 'gas-delta-baseline'); + appendStringOption(args, options, 'write-gas-delta-baseline'); + appendBooleanFlag(args, options, 'assert-match'); + appendBooleanFlag(args, options, 'ignore-gas'); + appendBooleanFlag(args, options, 'include-gas-trace'); + appendBooleanFlag(args, options, 'include-gas-charge-tape'); + return args; +} + +function appendStringOption( + args: string[], + options: ArgMap, + key: string, +): void { + const value = getOptionalString(options, key); + if (value !== undefined) { + args.push(`--${key}`, value); + } +} + +function appendBooleanFlag(args: string[], options: ArgMap, key: string): void { + if (options.has(key)) { + args.push(`--${key}`); + } +} + +async function readJsonFile(filePath: string): Promise { + const text = await readFile(path.resolve(filePath), 'utf8'); + return JSON.parse(text); +} + +async function writeJsonFile( + filePath: string, + payload: unknown, +): Promise { + await writeFile( + path.resolve(filePath), + `${JSON.stringify(payload, null, 2)}\n`, + 'utf8', + ); +} + +function mapVmPayload(payload: string, manifest: AbiManifest) { + const canonicalManifest = validateAbiManifest(manifest); + if (payload.includes('OutOfGas')) { + return { + kind: 'out-of-gas', + code: 'OUT_OF_GAS', + tag: 'vm/out_of_gas', + message: payload, + manifestAbiId: canonicalManifest.abi_id, + manifestAbiVersion: canonicalManifest.abi_version, + }; + } + if (payload.includes('ModuleSpecifierNotFound')) { + return { + kind: 'module-pack', + code: 'MODULE_SPECIFIER_NOT_FOUND', + tag: 'vm/module_pack', + message: payload, + manifestAbiId: canonicalManifest.abi_id, + manifestAbiVersion: canonicalManifest.abi_version, + }; + } + if (payload.includes('ModuleExportMissing')) { + return { + kind: 'module-pack', + code: 'MODULE_EXPORT_MISSING', + tag: 'vm/module_pack', + message: payload, + manifestAbiId: canonicalManifest.abi_id, + manifestAbiVersion: canonicalManifest.abi_version, + }; + } + if (payload.includes('ModuleResolutionError')) { + return { + kind: 'module-pack', + code: 'MODULE_RESOLUTION_ERROR', + tag: 'vm/module_pack', + message: payload, + manifestAbiId: canonicalManifest.abi_id, + manifestAbiVersion: canonicalManifest.abi_version, + }; + } + if (payload.includes('ModuleEvaluationError')) { + return { + kind: 'module-pack', + code: 'MODULE_EVALUATION_ERROR', + tag: 'vm/module_pack', + message: payload, + manifestAbiId: canonicalManifest.abi_id, + manifestAbiVersion: canonicalManifest.abi_version, + }; + } + if (payload.includes('HostError')) { + return { + kind: 'host', + code: 'HOST_ERROR', + tag: 'vm/host', + message: payload, + manifestAbiId: canonicalManifest.abi_id, + manifestAbiVersion: canonicalManifest.abi_version, + }; + } + return { + kind: 'js-exception', + code: 'JS_EXCEPTION', + tag: 'vm/js_exception', + message: payload, + manifestAbiId: canonicalManifest.abi_id, + manifestAbiVersion: canonicalManifest.abi_version, + }; +} + +function isProgramArtifactV2( + program: ProgramArtifact | ProgramArtifactV2, +): program is ProgramArtifactV2 { + return 'version' in program && program.version === 2; +} + +function printHelp(): void { + console.log( + [ + 'blue-quickjs CLI', + '', + 'Commands:', + ' build --entry [--profile compat-binary-v1] [--out artifact.json] [--abi-id Host.v2] [--abi-version 2] [--abi-manifest-hash ] [--gas-version ] [--allow-incompatible]', + ' compat --entry [--profile baseline-v1] [--out report.json]', + ' run --artifact [--manifest ] [--input ] [--gas-limit ]', + ' inspect --artifact ', + ' explain-error --payload | --raw "ERROR ..."', + ' consensus-report [--out-dir artifacts/reproducibility-consensus] [--base-url http://127.0.0.1:4300] [--browser chromium|firefox|webkit] [--reuse-server]', + ' native-report [--strict] [--out-dir artifacts/reproducibility] [--gas-charge-tape-capacity ]', + ' native-parity [--assert-match] [--out parity.json] [--compare previous.json] [--ignore-gas] [--include-gas-trace] [--include-gas-charge-tape]', + ].join('\n'), + ); +} diff --git a/tools/blue-quickjs-cli/tsconfig.json b/tools/blue-quickjs-cli/tsconfig.json new file mode 100644 index 0000000..62ebbd9 --- /dev/null +++ b/tools/blue-quickjs-cli/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../tsconfig.base.json", + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/tools/blue-quickjs-cli/tsconfig.lib.json b/tools/blue-quickjs-cli/tsconfig.lib.json new file mode 100644 index 0000000..346335a --- /dev/null +++ b/tools/blue-quickjs-cli/tsconfig.lib.json @@ -0,0 +1,33 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo", + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": false, + "types": ["node"] + }, + "include": ["src/**/*.ts"], + "exclude": [ + "vite.config.ts", + "eslint.config.mjs", + "src/**/*.spec.ts", + "src/**/*.test.ts" + ], + "references": [ + { + "path": "../../libs/test-harness/tsconfig.lib.json" + }, + { + "path": "../../libs/quickjs-runtime/tsconfig.lib.json" + }, + { + "path": "../../libs/deterministic-builder/tsconfig.lib.json" + }, + { + "path": "../../libs/abi-manifest/tsconfig.lib.json" + } + ] +} diff --git a/tools/blue-quickjs-cli/tsconfig.spec.json b/tools/blue-quickjs-cli/tsconfig.spec.json new file mode 100644 index 0000000..a20948c --- /dev/null +++ b/tools/blue-quickjs-cli/tsconfig.spec.json @@ -0,0 +1,29 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "dist/test", + "tsBuildInfoFile": "dist/tsconfig.spec.tsbuildinfo", + "types": ["vitest/globals", "vitest/importMeta", "node"] + }, + "include": [ + "vite.config.ts", + "src/**/*.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.d.ts" + ], + "references": [ + { + "path": "../../libs/test-harness/tsconfig.lib.json" + }, + { + "path": "../../libs/quickjs-runtime/tsconfig.lib.json" + }, + { + "path": "../../libs/deterministic-builder/tsconfig.lib.json" + }, + { + "path": "../../libs/abi-manifest/tsconfig.lib.json" + } + ] +} diff --git a/tools/blue-quickjs-cli/vite.config.ts b/tools/blue-quickjs-cli/vite.config.ts new file mode 100644 index 0000000..404161b --- /dev/null +++ b/tools/blue-quickjs-cli/vite.config.ts @@ -0,0 +1,29 @@ +/// +import { defineConfig } from 'vite'; + +export default defineConfig(() => ({ + root: import.meta.dirname, + cacheDir: '../../node_modules/.vite/tools/blue-quickjs-cli', + plugins: [], + test: { + name: 'blue-quickjs-cli', + watch: false, + globals: true, + environment: 'node', + include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], + reporters: ['default'], + coverage: { + reportsDirectory: './test-output/vitest/coverage', + provider: 'v8' as const, + all: true, + include: ['src/**/*.{ts,mts}'], + exclude: ['src/cli.ts', 'src/index.ts', 'src/**/*.{test,spec}.{ts,mts}'], + thresholds: { + lines: 40, + functions: 40, + branches: 40, + statements: 40, + }, + }, + }, +})); diff --git a/tools/consensus-parity/scripts/archive-consensus-reproducibility-report.mjs b/tools/consensus-parity/scripts/archive-consensus-reproducibility-report.mjs new file mode 100644 index 0000000..d20548f --- /dev/null +++ b/tools/consensus-parity/scripts/archive-consensus-reproducibility-report.mjs @@ -0,0 +1,797 @@ +#!/usr/bin/env node + +import { chromium, firefox, webkit } from '@playwright/test'; +import { createHash } from 'node:crypto'; +import { mkdir, writeFile } from 'node:fs/promises'; +import path from 'node:path'; +import process from 'node:process'; +import { fileURLToPath } from 'node:url'; +import jiti from 'jiti'; +import { createServer } from 'vite'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const repoRoot = path.resolve(__dirname, '..', '..', '..'); +const smokeWebConfigPath = path.join(repoRoot, 'apps/smoke-web/vite.config.mts'); +const require = jiti(import.meta.url, { interopDefault: true }); + +const { encodeDv } = require('../../../libs/dv/src/index.ts'); +const { bundleDeterministicProgram } = require( + '../../../libs/deterministic-bundler/src/index.ts', +); +const { createRuntime, evaluate, initializeDeterministicVm } = require( + '../../../libs/quickjs-runtime/src/index.ts', +); +const { + BINARY_LIBRARY_FIXTURES, + BINARY_LIBRARY_GAS_LIMIT, + BINARY_LIBRARY_INPUT, + BINARY_LIBRARY_MANIFEST, + BINARY_LIBRARY_PROGRAM_BASE, + CHESS_LIBRARY_ENTRY_PATH, + CHESS_LIBRARY_GAS_LIMIT, + CHESS_LIBRARY_INPUT, + CHESS_LIBRARY_MANIFEST, + CHESS_LIBRARY_PROGRAM_BASE, + DETERMINISM_FIXTURES, + GAS_SAMPLE_FIXTURES, + MODULE_PACK_FIXTURES, + createDeterminismHost, + parseDeterministicEvalOutput, + serializeHostTape, +} = require('../../../libs/test-harness/src/index.ts'); +const { loadQuickjsWasmBinary, loadQuickjsWasmMetadata } = require( + '../../../libs/quickjs-wasm/src/index.ts', +); + +const args = parseArgs(process.argv.slice(2)); +const browserType = resolveBrowserType(args.browser); + +const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); +const outDir = path.resolve(repoRoot, args.outDir); +const reportPath = path.join(outDir, `consensus-parity-report-${timestamp}.json`); + +await mkdir(outDir, { recursive: true }); + +const metadata = await loadQuickjsWasmMetadata(); +const wasmBinary = await loadQuickjsWasmBinary('wasm32', 'release', metadata); +const variantMetadata = metadata.variants?.wasm32?.release ?? null; + +const viteServer = args.reuseServer + ? null + : await createServer({ + configFile: smokeWebConfigPath, + server: { + host: '127.0.0.1', + port: 4300, + strictPort: true, + }, + clearScreen: false, + }); + +if (viteServer) { + await viteServer.listen(); +} + +const baseUrl = args.baseUrl ?? 'http://127.0.0.1:4300'; +const browser = await browserType.launch({ headless: true }); +const context = await browser.newContext({ baseURL: baseUrl }); + +try { + const chessBundle = await bundleDeterministicProgram({ + absWorkingDir: repoRoot, + entryPath: CHESS_LIBRARY_ENTRY_PATH, + profile: 'compat-general-v1', + }); + const binaryBundles = await Promise.all( + BINARY_LIBRARY_FIXTURES.map(async (fixture) => ({ + name: fixture.name, + code: ( + await bundleDeterministicProgram({ + absWorkingDir: repoRoot, + entryPath: fixture.entryPath, + profile: 'compat-binary-v1', + }) + ).code, + })), + ); + + const nodeSnapshots = await collectNodeSnapshots({ + metadata, + wasmBinary, + chessCode: chessBundle.code, + binaryBundles, + }); + const browserSnapshots = await collectBrowserSnapshots({ + context, + chessCode: chessBundle.code, + binaryBundles, + }); + + const suites = [ + compareNamedSuite( + 'determinism-fixtures', + nodeSnapshots.determinism, + browserSnapshots.determinism, + ), + compareNamedSuite( + 'gas-sample-fixtures', + nodeSnapshots.gasSamples, + browserSnapshots.gasSamples, + ), + compareNamedSuite( + 'gas-boundary-fixtures', + nodeSnapshots.gasBoundaries, + browserSnapshots.gasBoundaries, + ), + compareNamedSuite( + 'module-pack-fixtures', + nodeSnapshots.modulePack, + browserSnapshots.modulePack, + ), + compareNamedSuite('chess-library', nodeSnapshots.chess, browserSnapshots.chess), + compareNamedSuite( + 'binary-library', + nodeSnapshots.binary, + browserSnapshots.binary, + ), + ]; + + const mismatchCount = suites.reduce( + (sum, suite) => sum + suite.mismatchCount, + 0, + ); + const fixtureCount = suites.reduce((sum, suite) => sum + suite.fixtureCount, 0); + + const report = { + generatedAt: new Date().toISOString(), + consensusExecutors: { + primary: 'wasm-node', + secondary: `wasm-browser:${args.browser}`, + }, + metadata: { + gasVersion: metadata.gasVersion ?? null, + engineBuildHash: metadata.engineBuildHash ?? null, + executionProfile: 'fixture-defined', + wasmVariant: 'wasm32', + wasmBuildType: 'release', + wasmFilename: variantMetadata?.wasm?.filename ?? null, + wasmLoaderFilename: variantMetadata?.loader?.filename ?? null, + baseUrl, + browser: args.browser, + }, + suiteCount: suites.length, + fixtureCount, + mismatchCount, + suites, + }; + const signatureDigest = sha256Hex(JSON.stringify(report)); + const signedReport = { + ...report, + signature: { + algorithm: 'sha256', + digest: signatureDigest, + }, + }; + + const reportText = `${JSON.stringify(signedReport, null, 2)}\n`; + await writeFile(reportPath, reportText, 'utf8'); + + const checksumPath = `${reportPath}.sha256`; + const fileDigest = sha256Hex(reportText); + await writeFile( + checksumPath, + `${fileDigest} ${path.basename(reportPath)}\n`, + 'utf8', + ); + + process.stdout.write( + [ + `consensus reproducibility report: ${reportPath}`, + `report signature digest: ${signatureDigest}`, + `file sha256: ${fileDigest}`, + `file checksum: ${checksumPath}`, + `total fixtures: ${fixtureCount}`, + `total mismatches: ${mismatchCount}`, + `browser: ${args.browser}`, + ].join('\n') + '\n', + ); + + if (mismatchCount > 0) { + throw new Error( + `consensus parity mismatches detected (${mismatchCount} fixtures)`, + ); + } +} finally { + await context.close(); + await browser.close(); + if (viteServer) { + await viteServer.close(); + } +} + +async function collectNodeSnapshots(options) { + return { + determinism: await runNodeDeterminismSnapshots( + options.metadata, + options.wasmBinary, + ), + gasSamples: await runNodeGasSampleSnapshots(options.metadata, options.wasmBinary), + gasBoundaries: await runNodeGasBoundarySnapshots( + options.metadata, + options.wasmBinary, + ), + modulePack: await runNodeModulePackSnapshots(options.metadata, options.wasmBinary), + chess: [ + { + name: 'chess-e2e6', + snapshot: await runNodeChessSnapshot(options.chessCode), + }, + ], + binary: await Promise.all( + options.binaryBundles.map(async (bundle) => ({ + name: bundle.name, + snapshot: await runNodeBinarySnapshot(bundle.code), + })), + ), + }; +} + +async function collectBrowserSnapshots(options) { + const determinismResults = await readBrowserResults( + options.context, + '/determinism.html', + '__DETERMINISM_RESULTS__', + ); + const gasSampleResults = await readBrowserResults( + options.context, + '/gas-samples.html', + '__GAS_SAMPLE_RESULTS__', + ); + const gasBoundaryResults = await readBrowserResults( + options.context, + '/gas-samples.html', + '__GAS_BOUNDARY_RESULTS__', + ); + const modulePackResults = await readBrowserResults( + options.context, + '/module-pack-fixtures.html', + '__MODULE_PACK_FIXTURE_RESULTS__', + ); + + const chessResult = await readBrowserInjectedResult(options.context, { + url: '/chess-library-reuse.html', + initKey: '__CHESS_BUNDLED_CODE__', + resultKey: '__CHESS_LIBRARY_REUSE_RESULT__', + code: options.chessCode, + }); + + const binaryResults = await Promise.all( + options.binaryBundles.map(async (bundle) => ({ + name: bundle.name, + snapshot: await readBrowserInjectedResult(options.context, { + url: '/binary-library-reuse.html', + initKey: '__BINARY_BUNDLED_CODE__', + resultKey: '__BINARY_LIBRARY_REUSE_RESULT__', + code: bundle.code, + }), + })), + ); + + return { + determinism: determinismResults.map((entry) => ({ + name: entry.name, + snapshot: entry, + })), + gasSamples: gasSampleResults.map((entry) => ({ + name: entry.name, + snapshot: entry, + })), + gasBoundaries: gasBoundaryResults.map((entry) => ({ + name: entry.name, + snapshot: entry, + })), + modulePack: modulePackResults.map((entry) => ({ + name: entry.name, + snapshot: entry, + })), + chess: [ + { + name: 'chess-e2e6', + snapshot: chessResult, + }, + ], + binary: binaryResults, + }; +} + +async function runNodeDeterminismSnapshots(metadata, wasmBinary) { + const results = []; + for (const fixture of DETERMINISM_FIXTURES) { + const host = fixture.createHost(); + const result = await evaluate({ + program: fixture.program, + input: fixture.input, + gasLimit: fixture.gasLimit, + manifest: fixture.manifest, + handlers: host.handlers, + metadata, + wasmBinary, + tape: { capacity: 32 }, + }); + const tape = result.tape ?? []; + results.push({ + name: fixture.name, + snapshot: { + name: fixture.name, + expected: { + resultHash: fixture.expected.resultHash, + errorCode: fixture.expected.errorCode, + errorTag: fixture.expected.errorTag, + gasUsed: fixture.expected.gasUsed.toString(), + gasRemaining: fixture.expected.gasRemaining.toString(), + tapeHash: fixture.expected.tapeHash, + tapeLength: fixture.expected.tapeLength, + }, + actual: { + resultHash: result.ok ? hashDv(result.value) : null, + errorCode: result.ok ? null : result.error.code, + errorTag: + result.ok || !('tag' in result.error) ? null : result.error.tag, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + tapeHash: hashTape(tape), + tapeLength: tape.length, + }, + matches: { + resultHash: + (result.ok ? hashDv(result.value) : null) === + fixture.expected.resultHash, + errorCode: + (result.ok ? null : result.error.code) === fixture.expected.errorCode, + errorTag: + (result.ok || !('tag' in result.error) ? null : result.error.tag) === + fixture.expected.errorTag, + gasUsed: + result.gasUsed.toString() === fixture.expected.gasUsed.toString(), + gasRemaining: + result.gasRemaining.toString() === + fixture.expected.gasRemaining.toString(), + tapeHash: hashTape(tape) === fixture.expected.tapeHash, + tapeLength: tape.length === fixture.expected.tapeLength, + }, + }, + }); + } + return results; +} + +async function runNodeGasSampleSnapshots(metadata, wasmBinary) { + const snapshots = []; + for (const fixture of GAS_SAMPLE_FIXTURES) { + const host = fixture.createHost(); + const result = await evaluate({ + program: fixture.program, + input: fixture.input, + gasLimit: fixture.gasLimit, + manifest: fixture.manifest, + handlers: host.handlers, + metadata, + wasmBinary, + }); + if (!result.ok) { + throw new Error(`gas sample fixture ${fixture.name} failed: ${result.error.code}`); + } + + const actual = { + resultHash: hashDv(result.value), + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + }; + const expected = { + resultHash: fixture.expected.resultHash, + gasUsed: fixture.expected.gasUsed.toString(), + gasRemaining: fixture.expected.gasRemaining.toString(), + }; + const repeatSameContext = fixture.repeatSameContext + ? await runRepeatSameContext(fixture, metadata, wasmBinary) + : undefined; + + snapshots.push({ + name: fixture.name, + snapshot: { + name: fixture.name, + actual, + expected, + matches: { + resultHash: actual.resultHash === expected.resultHash, + gasUsed: actual.gasUsed === expected.gasUsed, + gasRemaining: actual.gasRemaining === expected.gasRemaining, + }, + ...(repeatSameContext ? { repeatSameContext } : {}), + }, + }); + } + return snapshots; +} + +async function runNodeGasBoundarySnapshots(metadata, wasmBinary) { + const fixtureNames = new Set([ + 'return-1', + 'loop-1k', + 'loop-10k', + 'string-concat', + 'object-alloc', + 'array-ops', + ]); + const selected = GAS_SAMPLE_FIXTURES.filter((fixture) => + fixtureNames.has(fixture.name), + ); + return Promise.all( + selected.map(async (fixture) => ({ + name: fixture.name, + snapshot: await findOutOfGasBoundary(fixture, metadata, wasmBinary), + })), + ); +} + +async function runNodeModulePackSnapshots(metadata, wasmBinary) { + const snapshots = []; + for (const fixture of MODULE_PACK_FIXTURES) { + const host = fixture.createHost(); + const result = await evaluate({ + program: fixture.program, + input: fixture.input, + gasLimit: fixture.gasLimit, + manifest: fixture.manifest, + handlers: host.handlers, + metadata, + wasmBinary, + tape: { capacity: 16 }, + }); + const tape = result.tape ?? []; + snapshots.push({ + name: fixture.name, + snapshot: { + name: fixture.name, + expectedOk: fixture.expected.ok, + actual: { + ok: result.ok, + valueHash: result.ok ? hashDv(result.value) : null, + errorCode: result.ok ? null : result.error.code, + errorTag: + result.ok || !('tag' in result.error) ? null : result.error.tag, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + tapeHash: hashTape(tape), + tapeLength: tape.length, + }, + }, + }); + } + return snapshots; +} + +async function runNodeChessSnapshot(code) { + const host = createDeterminismHost(); + const result = await evaluate({ + program: { + ...CHESS_LIBRARY_PROGRAM_BASE, + code, + }, + input: CHESS_LIBRARY_INPUT, + gasLimit: CHESS_LIBRARY_GAS_LIMIT, + manifest: CHESS_LIBRARY_MANIFEST, + handlers: host.handlers, + }); + + if (result.ok) { + return { + ok: true, + value: result.value, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + errorCode: null, + errorTag: null, + }; + } + + return { + ok: false, + value: null, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + errorCode: result.error.code, + errorTag: 'tag' in result.error ? result.error.tag : null, + }; +} + +async function runNodeBinarySnapshot(code) { + const host = createDeterminismHost(); + const result = await evaluate({ + program: { + ...BINARY_LIBRARY_PROGRAM_BASE, + code, + }, + input: BINARY_LIBRARY_INPUT, + gasLimit: BINARY_LIBRARY_GAS_LIMIT, + manifest: BINARY_LIBRARY_MANIFEST, + handlers: host.handlers, + }); + + if (result.ok) { + return { + ok: true, + value: result.value, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + errorCode: null, + errorTag: null, + }; + } + + return { + ok: false, + value: null, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + errorCode: result.error.code, + errorTag: 'tag' in result.error ? result.error.tag : null, + }; +} + +async function runRepeatSameContext(fixture, metadata, wasmBinary) { + const host = fixture.createHost(); + const runtime = await createRuntime({ + manifest: fixture.manifest, + handlers: host.handlers, + metadata, + wasmBinary, + }); + const vm = initializeDeterministicVm( + runtime, + fixture.program, + fixture.input, + fixture.gasLimit, + ); + + const samples = []; + try { + vm.setGasLimit(fixture.gasLimit); + const warmup = parseDeterministicEvalOutput(vm.eval(fixture.program.code)); + if (warmup.kind === 'error') { + throw new Error(`${fixture.name} warmup failed: ${warmup.error}`); + } + + for (let i = 0; i < fixture.repeatSameContext.count; i += 1) { + vm.setGasLimit(fixture.gasLimit); + const output = parseDeterministicEvalOutput(vm.eval(fixture.program.code)); + if (output.kind === 'error') { + throw new Error(`${fixture.name} failed: ${output.error}`); + } + samples.push(output.gasUsed.toString()); + } + } finally { + vm.dispose(); + } + + const expectedGasUsed = fixture.repeatSameContext.expectedGasUsed.toString(); + return { + samples, + expectedGasUsed, + match: + samples.length > 0 && samples.every((sample) => sample === expectedGasUsed), + }; +} + +async function findOutOfGasBoundary(fixture, metadata, wasmBinary) { + let upperGas = fixture.expected.gasUsed; + let upper = await runFixtureAtGasLimit(fixture, upperGas, metadata, wasmBinary); + while (!upper.ok) { + upperGas *= 2n; + upper = await runFixtureAtGasLimit(fixture, upperGas, metadata, wasmBinary); + } + + let lowerGas = 0n; + let lower = await runFixtureAtGasLimit(fixture, lowerGas, metadata, wasmBinary); + while (lowerGas + 1n < upperGas) { + const mid = (lowerGas + upperGas) >> 1n; + const current = await runFixtureAtGasLimit(fixture, mid, metadata, wasmBinary); + if (current.ok) { + upperGas = mid; + upper = current; + } else { + lowerGas = mid; + lower = current; + } + } + + if (!upper.ok || lower.ok) { + throw new Error(`boundary search failed for ${fixture.name}`); + } + + return { + name: fixture.name, + firstSuccessGas: upperGas.toString(), + lastFailureGas: lowerGas.toString(), + successGasUsed: upper.gasUsed.toString(), + successGasRemaining: upper.gasRemaining.toString(), + failureGasUsed: lower.gasUsed.toString(), + failureGasRemaining: lower.gasRemaining.toString(), + failureCode: lower.error.code, + failureTag: 'tag' in lower.error ? lower.error.tag : null, + }; +} + +async function runFixtureAtGasLimit(fixture, gasLimit, metadata, wasmBinary) { + const host = fixture.createHost(); + return evaluate({ + program: fixture.program, + input: fixture.input, + gasLimit, + manifest: fixture.manifest, + handlers: host.handlers, + metadata, + wasmBinary, + }); +} + +async function readBrowserResults(context, url, key) { + const page = await context.newPage(); + try { + await page.goto(url); + await page.waitForSelector('[data-runstate="done"]', { timeout: 60000 }); + const results = await page.evaluate( + (resultKey) => globalThis[resultKey] ?? null, + key, + ); + if (!Array.isArray(results)) { + throw new Error(`browser results missing for ${url} (${key})`); + } + return results; + } finally { + await page.close(); + } +} + +async function readBrowserInjectedResult(context, options) { + const page = await context.newPage(); + try { + await page.addInitScript( + ({ key, bundledCode }) => { + globalThis[key] = bundledCode; + }, + { key: options.initKey, bundledCode: options.code }, + ); + await page.goto(options.url); + await page.waitForSelector('[data-runstate="done"]', { timeout: 60000 }); + const result = await page.evaluate((resultKey) => globalThis[resultKey] ?? null, options.resultKey); + if (!result || Array.isArray(result) || typeof result !== 'object') { + throw new Error(`browser injected result missing for ${options.url}`); + } + return result; + } finally { + await page.close(); + } +} + +function compareNamedSuite(name, nodeRecords, browserRecords) { + const nodeByName = new Map(nodeRecords.map((entry) => [entry.name, entry.snapshot])); + const browserByName = new Map( + browserRecords.map((entry) => [entry.name, entry.snapshot]), + ); + const fixtureNames = Array.from( + new Set([...nodeByName.keys(), ...browserByName.keys()]), + ).sort(); + + const fixtures = fixtureNames.map((fixtureName) => { + const node = nodeByName.get(fixtureName); + const browser = browserByName.get(fixtureName); + const match = node !== undefined && browser !== undefined && deepEqual(node, browser); + + return { + name: fixtureName, + match, + node: node ?? null, + browser: browser ?? null, + ...(node === undefined + ? { reason: 'missing-node-snapshot' } + : browser === undefined + ? { reason: 'missing-browser-snapshot' } + : {}), + }; + }); + + return { + name, + fixtureCount: fixtures.length, + mismatchCount: fixtures.filter((fixture) => !fixture.match).length, + fixtures, + }; +} + +function deepEqual(left, right) { + return JSON.stringify(normalizeJson(left)) === JSON.stringify(normalizeJson(right)); +} + +function normalizeJson(value) { + if (Array.isArray(value)) { + return value.map((entry) => normalizeJson(entry)); + } + if (value && typeof value === 'object') { + const normalized = {}; + for (const key of Object.keys(value).sort()) { + normalized[key] = normalizeJson(value[key]); + } + return normalized; + } + return value; +} + +function hashDv(value) { + return sha256Hex(Buffer.from(encodeDv(value))); +} + +function hashTape(tape) { + if (!Array.isArray(tape) || tape.length === 0) { + return null; + } + return sha256Hex(Buffer.from(serializeHostTape(tape))); +} + +function sha256Hex(input) { + return createHash('sha256').update(input).digest('hex'); +} + +function parseArgs(argv) { + let outDir = 'artifacts/reproducibility-consensus'; + let baseUrl = null; + let reuseServer = false; + let browser = 'chromium'; + + for (let i = 0; i < argv.length; i += 1) { + const arg = argv[i]; + if (arg === '--') { + continue; + } + if (arg === '--out-dir') { + outDir = argv[i + 1] ?? outDir; + i += 1; + continue; + } + if (arg === '--base-url') { + baseUrl = argv[i + 1] ?? baseUrl; + i += 1; + continue; + } + if (arg === '--reuse-server') { + reuseServer = true; + continue; + } + if (arg === '--browser') { + browser = argv[i + 1] ?? browser; + i += 1; + continue; + } + throw new Error(`unknown argument: ${arg}`); + } + + return { + outDir, + baseUrl, + reuseServer, + browser, + }; +} + +function resolveBrowserType(browser) { + if (browser === 'chromium') { + return chromium; + } + if (browser === 'firefox') { + return firefox; + } + if (browser === 'webkit') { + return webkit; + } + throw new Error(`unsupported browser: ${browser}`); +} diff --git a/tools/gas-spec/gas-spec.v3.json b/tools/gas-spec/gas-spec.v3.json new file mode 100644 index 0000000..32a2bbe --- /dev/null +++ b/tools/gas-spec/gas-spec.v3.json @@ -0,0 +1,84 @@ +{ + "gasVersion": 8, + "allocation": { + "base": 0, + "perByteShift": 4, + "normalization": { + "mode": "none", + "notes": "Canonical allocation charging no longer uses pointer-width normalization heuristics." + }, + "canonicalClasses": { + "objectHeaderBytes": 64, + "propertySlotBytes": 16, + "shapeHeaderBytes": 48, + "shapePropertyBytes": 12, + "stringHeaderBytes": 0, + "arraySlotBytes": 8, + "moduleRecordBytes": 128, + "moduleEntryBytes": 24, + "promiseJobBaseBytes": 48, + "promiseJobArgBytes": 8, + "arrayBufferHeaderBytes": 48, + "typedArrayBackingUnitBytes": 1, + "typedArrayRecordBytes": 40, + "compilerFunctionDefBytes": 512, + "closureVarEntryBytes": 16, + "varRefPointerBytes": 8, + "varRefRecordBytes": 32, + "genericArrayUnitBytes": 16, + "unknownSmallFloorBytes": 64, + "unknownSmallFloorMaxBytes": 4096, + "unknownClassCharged": false, + "objectHeaderCharged": false, + "propertySlotCharged": false, + "shapeCharged": false, + "arrayBufferHeaderCharged": false, + "typedArrayBackingCharged": false, + "typedArrayRecordCharged": false + } + }, + "opcode": { + "defaultDispatchCost": 1 + }, + "arrayCallback": { + "base": 5, + "perElement": 2, + "methods": [ + "every", + "some", + "forEach", + "map", + "filter", + "reduce", + "reduceRight" + ], + "includesTypedArrays": true + }, + "jsonParse": { + "base": 8, + "inputByte": 1, + "value": 3, + "objectEntry": 2, + "arrayElement": 2 + }, + "jsonStringify": { + "base": 8, + "value": 3, + "objectEntry": 2, + "arrayElement": 2, + "outputByte": 1, + "sortComparison": 1 + }, + "gc": { + "deterministicThresholdBytes": 524288, + "chargeModel": "allocation-amortized", + "notes": "Automatic heuristics disabled in deterministic mode; checkpoints run at deterministic boundaries." + }, + "hostCall": { + "formula": { + "pre": "base + (k_arg_bytes * request_bytes)", + "post": "(k_ret_bytes * response_bytes) + (k_units * units)" + }, + "overflowError": "TypeError: host_call gas overflow" + } +} diff --git a/tools/gas-spec/render-gas-artifacts.mjs b/tools/gas-spec/render-gas-artifacts.mjs new file mode 100644 index 0000000..50d1c17 --- /dev/null +++ b/tools/gas-spec/render-gas-artifacts.mjs @@ -0,0 +1,213 @@ +#!/usr/bin/env node +import { readFile, writeFile } from 'node:fs/promises'; +import path from 'node:path'; +import process from 'node:process'; +import { fileURLToPath } from 'node:url'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const repoRoot = path.resolve(__dirname, '..', '..'); +const specPath = path.join(__dirname, 'gas-spec.v3.json'); +const gasScheduleDocPath = path.join(repoRoot, 'docs', 'gas-schedule.md'); + +const CHECK_MODE = process.argv.includes('--check'); + +export function renderGasSchedule(spec) { + return `# Gas Schedule (Baseline #1) + +> This file is generated from \`tools/gas-spec/gas-spec.v3.json\`. +> Update the gas spec source and rerun \`node tools/gas-spec/render-gas-artifacts.mjs\`. + +Baseline anchor: see \`docs/baseline-1.md\` (determinism + canonical gas) and \`docs/baseline-2.md\` (host-call ABI/gas parameters). + +Scope: define canonical gas units for QuickJS execution and host calls per Baseline #1. This document is normative and must match harness assertions. + +## Gas version and limits + +- \`JS_GAS_VERSION_LATEST = ${spec.gasVersion}\` +- Gas amounts are uint64. +- \`JS_GAS_UNLIMITED\` disables charging and reports gas used as 0. +- \`JS_UseGas\` subtracts from \`gas_remaining\`; if \`amount > gas_remaining\`, it sets \`gas_remaining = 0\` and throws an uncatchable \`OutOfGas: out of gas\` error. + +## Opcode gas + +- Every bytecode opcode defined in \`quickjs-opcode.h\` costs \`${spec.opcode.defaultDispatchCost}\` gas per dispatch. +- Temporary or unknown opcodes (outside \`OP_COUNT\`) cost \`0\`. + +## Builtin callback gas + +The following array methods charge deterministic callback gas: ${spec.arrayCallback.methods + .map((method) => `\`${method}\``) + .join(', ')}${ + spec.arrayCallback.includesTypedArrays + ? ' (including typed arrays).' + : '.' + } + +Charges: + +- Base: \`JS_GAS_ARRAY_CB_BASE = ${spec.arrayCallback.base}\` once per call, before the loop starts. +- Per element: \`JS_GAS_ARRAY_CB_PER_ELEMENT = ${spec.arrayCallback.perElement}\` before each element is processed. + +The per-element charge is applied for each iteration step, even when a hole is skipped or a callback returns early. + +## Allocation gas + +Each allocation charges: + +- Base: \`JS_GAS_ALLOC_BASE = ${spec.allocation.base}\` +- Byte charge: \`1\` gas per \`${2 ** spec.allocation.perByteShift}\` requested bytes (\`JS_GAS_ALLOC_PER_BYTE_SHIFT = ${spec.allocation.perByteShift}\`) + +Formula: + +- \`JS_GAS_ALLOC_BASE + ceil(size / ${2 ** spec.allocation.perByteShift})\` where \`size\` is the requested allocation size. + +Current deterministic normalization model: + +- Mode: \`${spec.allocation.normalization.mode}\` +- Note: ${spec.allocation.normalization.notes} +${ + spec.allocation.normalization.mode === 'legacy-64bit-26-31' + ? `- 64-bit path: \`normalized_size = floor((size * ${spec.allocation.normalization.numerator} + ${spec.allocation.normalization.offset}) / ${spec.allocation.normalization.denominator})\`` + : '- No pointer-width normalization is applied.' + } + +Canonical allocation classes (width-independent charged-byte formulas): + +- Object header: \`${spec.allocation.canonicalClasses.objectHeaderBytes}\` +- Property slot: \`${spec.allocation.canonicalClasses.propertySlotBytes}\` +- Shape header: \`${spec.allocation.canonicalClasses.shapeHeaderBytes}\` +- Shape property entry: \`${spec.allocation.canonicalClasses.shapePropertyBytes}\` +- String header: \`${spec.allocation.canonicalClasses.stringHeaderBytes}\` +- Array slot: \`${spec.allocation.canonicalClasses.arraySlotBytes}\` +- Module record: \`${spec.allocation.canonicalClasses.moduleRecordBytes}\` +- Module entry: \`${spec.allocation.canonicalClasses.moduleEntryBytes}\` +- Promise/job base: \`${spec.allocation.canonicalClasses.promiseJobBaseBytes}\` +- Promise/job arg unit: \`${spec.allocation.canonicalClasses.promiseJobArgBytes}\` +- ArrayBuffer header: \`${spec.allocation.canonicalClasses.arrayBufferHeaderBytes}\` +- TypedArray backing unit: \`${spec.allocation.canonicalClasses.typedArrayBackingUnitBytes}\` +- TypedArray record: \`${spec.allocation.canonicalClasses.typedArrayRecordBytes}\` +- Compiler function-def record: \`${spec.allocation.canonicalClasses.compilerFunctionDefBytes}\` +- Closure-var entry: \`${spec.allocation.canonicalClasses.closureVarEntryBytes}\` +- Var-ref pointer entry: \`${spec.allocation.canonicalClasses.varRefPointerBytes}\` +- Var-ref record: \`${spec.allocation.canonicalClasses.varRefRecordBytes}\` +- Generic dynamic-array unit: \`${spec.allocation.canonicalClasses.genericArrayUnitBytes}\` +- Unknown-class small-allocation floor: \`${spec.allocation.canonicalClasses.unknownSmallFloorBytes}\` +- Unknown-class small-allocation max size: \`${spec.allocation.canonicalClasses.unknownSmallFloorMaxBytes}\` +- Unknown-class charges enabled: \`${spec.allocation.canonicalClasses.unknownClassCharged}\` +- Object-header charges enabled: \`${spec.allocation.canonicalClasses.objectHeaderCharged}\` +- Property-slot charges enabled: \`${spec.allocation.canonicalClasses.propertySlotCharged}\` +- Shape charges enabled: \`${spec.allocation.canonicalClasses.shapeCharged}\` +- ArrayBuffer-header charges enabled: \`${spec.allocation.canonicalClasses.arrayBufferHeaderCharged}\` +- TypedArray-backing charges enabled: \`${spec.allocation.canonicalClasses.typedArrayBackingCharged}\` +- TypedArray-record charges enabled: \`${spec.allocation.canonicalClasses.typedArrayRecordCharged}\` + +## Deterministic JSON builtin gas + +Deterministic mode exposes metered \`JSON.parse\` / \`JSON.stringify\` built-ins. These +charges apply only to those deterministic wrappers; they do **not** change the behavior +of the public C APIs \`JS_ParseJSON*\` / \`JS_JSONStringify\` used by non-deterministic +contexts or host-side helpers. + +### \`JSON.parse\` + +Charges: + +- Base: \`JS_GAS_JSON_PARSE_BASE = ${spec.jsonParse.base}\` +- Input bytes: \`JS_GAS_JSON_PARSE_INPUT_BYTE = ${spec.jsonParse.inputByte}\` +- Value visit: \`JS_GAS_JSON_PARSE_VALUE = ${spec.jsonParse.value}\` +- Object entry: \`JS_GAS_JSON_PARSE_OBJECT_ENTRY = ${spec.jsonParse.objectEntry}\` +- Array element: \`JS_GAS_JSON_PARSE_ARRAY_ELEMENT = ${spec.jsonParse.arrayElement}\` + +Interpretation: + +- Base is charged once per call, before deterministic argument validation finishes. +- Input-byte gas is charged on the UTF-8 byte length of the input string before the + parser runs. +- The deterministic wrapper performs a metered structural preflight on the JSON text + before calling \`JS_ParseJSON\`, charging \`VALUE\`, \`OBJECT_ENTRY\`, and + \`ARRAY_ELEMENT\` as it validates the deterministic subset and size limits. +- Limit/type/syntax failures consume the work charged before the failure point; the + full native parse does not run after a failing preflight. + +### \`JSON.stringify\` + +Charges: + +- Base: \`JS_GAS_JSON_STRINGIFY_BASE = ${spec.jsonStringify.base}\` +- Value visit: \`JS_GAS_JSON_STRINGIFY_VALUE = ${spec.jsonStringify.value}\` +- Object entry: \`JS_GAS_JSON_STRINGIFY_OBJECT_ENTRY = ${spec.jsonStringify.objectEntry}\` +- Array element: \`JS_GAS_JSON_STRINGIFY_ARRAY_ELEMENT = ${spec.jsonStringify.arrayElement}\` +- Output bytes: \`JS_GAS_JSON_STRINGIFY_OUTPUT_BYTE = ${spec.jsonStringify.outputByte}\` +- Key sort comparison: \`JS_GAS_JSON_STRINGIFY_SORT_COMPARISON = ${spec.jsonStringify.sortComparison}\` + +Interpretation: + +- Base is charged once per call, before deterministic option validation finishes. +- \`VALUE\`, \`OBJECT_ENTRY\`, and \`ARRAY_ELEMENT\` are charged during the recursive walk. +- \`OUTPUT_BYTE\` is charged on emitted UTF-8 bytes of the final JSON string. +- \`SORT_COMPARISON\` is charged for each comparison performed by the deterministic key + sorter used for canonical object key ordering. +- Unsupported values/options and cycle errors still consume the work charged before the + failure point. + +## Garbage collection (GC) checkpoints + +- Automatic GC heuristics are disabled in deterministic mode (\`js_trigger_gc\` is a no-op and GC threshold is set to \`-1\`). +- A deterministic counter tracks charged allocation bytes. When it reaches \`JS_DET_GC_THRESHOLD_BYTES = ${spec.gc.deterministicThresholdBytes}\`, \`det_gc_pending\` is set. +- \`JS_RunGCCheckpoint(ctx)\` runs GC only when \`det_gc_pending\` is set; it then clears the flag and counter. +- GC costs \`0\` gas; allocation gas amortizes it. +- Checkpoints are invoked at deterministic points (pre/post eval and around host calls). + +## Host-call gas (Baseline #2) + +Host-call gas uses parameters from the ABI manifest \`gas\` fields (see \`docs/abi-manifest.md\`). + +- Pre-charge before the host call: + - \`${spec.hostCall.formula.pre}\` +- Post-charge after response parse: + - \`${spec.hostCall.formula.post}\` + +Where: + +- \`request_bytes\` is the encoded DV args array. +- \`response_bytes\` is the encoded DV response envelope. + +Overflow during charge throws \`${spec.hostCall.overflowError}\`. OOG on pre-charge aborts before the host call executes; OOG on post-charge aborts after response parse with host effects already applied. + +## Gas trace (optional) + +- \`JS_EnableGasTrace\` reports aggregate counts for: + - opcode gas, + - array callback gas, + - allocation gas, + - deterministic \`JSON.parse\` gas, + - deterministic \`JSON.stringify\` gas. +- Host-call gas is billed and tracked in dedicated host pre/post counters. +`; +} + +export function renderGasScheduleDocument(spec) { + return `${renderGasSchedule(spec).trimEnd()}\n`; +} + +export async function main() { + const specRaw = await readFile(specPath, 'utf8'); + const spec = JSON.parse(specRaw); + const renderedSchedule = renderGasScheduleDocument(spec); + + if (CHECK_MODE) { + const current = await readFile(gasScheduleDocPath, 'utf8'); + if (current !== renderedSchedule) { + throw new Error( + `Generated docs differ. Re-run: node tools/gas-spec/render-gas-artifacts.mjs`, + ); + } + return; + } + + await writeFile(gasScheduleDocPath, renderedSchedule, 'utf8'); +} + +if (process.argv[1] === fileURLToPath(import.meta.url)) { + await main(); +} diff --git a/tools/gas-spec/render-gas-artifacts.test.mjs b/tools/gas-spec/render-gas-artifacts.test.mjs new file mode 100644 index 0000000..cee266d --- /dev/null +++ b/tools/gas-spec/render-gas-artifacts.test.mjs @@ -0,0 +1,18 @@ +import assert from 'node:assert/strict'; +import { readFile } from 'node:fs/promises'; +import path from 'node:path'; +import { test } from 'node:test'; +import { fileURLToPath } from 'node:url'; + +import { renderGasScheduleDocument } from './render-gas-artifacts.mjs'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const specPath = path.join(__dirname, 'gas-spec.v3.json'); + +test('rendered gas schedule ends with exactly one newline', async () => { + const spec = JSON.parse(await readFile(specPath, 'utf8')); + const rendered = renderGasScheduleDocument(spec); + + assert.match(rendered, /\n$/); + assert.doesNotMatch(rendered, /\n\n$/); +}); diff --git a/tools/quickjs-native-harness/README.md b/tools/quickjs-native-harness/README.md index 09a322f..bd9926c 100644 --- a/tools/quickjs-native-harness/README.md +++ b/tools/quickjs-native-harness/README.md @@ -5,15 +5,85 @@ Minimal native harness for the QuickJS fork. Builds a standalone binary that eva ## Usage - Build: `pnpm nx build quickjs-native-harness` - Test: `pnpm nx test quickjs-native-harness` +- Legacy shell suite: `pnpm nx run quickjs-native-harness:test-legacy` - Manual run: `tools/quickjs-native-harness/dist/quickjs-native-harness --eval "1 + 2"` -- Gas goldens: `tools/quickjs-native-harness/scripts/gas-goldens.mjs` consumes fixtures under - `tools/quickjs-native-harness/fixtures/gas` and is invoked by the test script. +- The default `nx test quickjs-native-harness` target is a focused Vitest suite + covering the deterministic-runtime contract introduced by patch `0001` + (`JS_NewDeterministicRuntime`, disabled `eval` / `Function`, and `Host.v1` + bootstrap shape). +- Gas goldens now live in the new harness as + `libs/test-harness/src/lib/gas-goldens.spec.ts`, using fixture data from + `libs/test-harness/fixtures/gas-goldens.json`. +- DV parity now lives in `libs/test-harness/src/lib/dv-parity.spec.ts`. +- Host-call gas accounting now lives in + `libs/test-harness/src/lib/host-gas.spec.ts`. +- Binary-library parity now lives in + `libs/test-harness/src/lib/binary-library-parity.spec.ts`. +- Module-pack parity now lives in + `libs/test-harness/src/lib/module-pack-parity.spec.ts`. +- Parity report: `tools/quickjs-native-harness/scripts/parity-report.mjs` runs + determinism/module-pack/binary fixture suites through wasm-node + native, + emits signed JSON snapshots, and supports: + - `--out ` write report artifact, + - `--assert-match` fail when node/native snapshots diverge, + - `--ignore-gas` compare only result/error/tape fields while still reporting + gas deltas, + - `--gas-delta-baseline ` require per-fixture gas deltas to match an + expected baseline file, + - `--write-gas-delta-baseline ` emit the current gas delta baseline, + - `--include-gas-trace` attach node/native gas-trace counters and + per-counter deltas to each fixture in the report output (this mode disables + gas-delta baseline enforcement because gas tracing perturbs counters), plus + an aggregated `gasTraceSummary` section ranking hottest counter deltas and + top fixtures by allocation-gas drift and residual untraced gas delta + (including host-call pre/post gas counters, residual signature histograms, + and profile rollups), + - `--include-gas-charge-tape` attach per-charge event sequences and sequence + hashes, and report the first divergent charge index/site for mismatching + fixtures (plus top per-site gas/count deltas for quick hotspot triage), + - `--gas-charge-tape-capacity ` control diagnostic charge-tape ring + capacity (default `256`, max `8192`) when charge tape capture is enabled, + - `--compare ` compare current run against a prior report. + The harness test script runs this report in diagnostic mode by default. + Set `NATIVE_PARITY_STRICT=1` to require strict `--assert-match` mode. + +- Reproducibility archive helper: + `tools/quickjs-native-harness/scripts/archive-reproducibility-report.mjs` + executes parity report + charge-tape capture and writes: + - a signed parity report JSON under `artifacts/reproducibility/`, + - a sidecar `.sha256` checksum file. + By default this is diagnostic (non-strict). Add `--strict` to fail on + mismatches and enforce zero-delta parity. + + This is intended for release-candidate reproducibility report archival. + + **Release policy note:** `--gas-delta-baseline` is diagnostic-only scaffolding. + Release gates must use strict equality mode (no delta baseline normalization) + for consensus executors. - Manifest validation: pass `--abi-manifest-hex ` (or `--abi-manifest-hex-file `) and `--abi-manifest-hash ` to initialize the VM with a pinned ABI manifest. An optional `--context-blob-hex ` can be provided for future context blobs. +- Execution profile: `--execution-profile baseline-v1|compat-general-v1|compat-binary-v1` + selects deterministic feature flags for initialization (`baseline-v1` is the default). +- Module-pack eval: `--module-entry-specifier ` plus either + `--module-pack-json ""` or `--module-pack-file ` executes + deterministic static ESM module packs; `--module-entry-export ` selects + the exported binding (defaults to `default`). +- Parity eval mode: `--parity-eval` (eval-mode only) routes script evaluation + through a DV encode/decode path so parity tooling can mirror wasm runtime + evaluation semantics while keeping human-readable `RESULT ` output. +- Tape reporting: `--report-tape` appends host tape JSON (`TAPE [...]`) to + output lines for parity checks. - SHA helper: `--sha256-hex ` prints the SHA-256 digest for the provided hex bytes (handy for cross-checking vectors). Notes: -- Uses the fork's deterministic init (`JS_NewDeterministicRuntime`): global scope excludes `Date`, `eval`, `Function`, `Proxy`, `RegExp`, typed arrays, `Promise`/`WeakRef` and reserves a null-prototype `Host.v1` placeholder. +- Uses the fork's deterministic init (`JS_NewDeterministicRuntime`): baseline + global scope excludes `Date`, `eval`, `Function`, `Proxy`, `RegExp`, typed + arrays, `Promise`/`WeakRef` and reserves a null-prototype `Host.v1` + placeholder. `compat-general-v1` / `compat-binary-v1` enable Promise jobs, + deterministic `queueMicrotask`, console shim routing via `Host.v1.emit`, and + deterministic stable `Array.prototype.sort`. `compat-binary-v1` additionally + enables typed-array intrinsics so Host.v2/DV2 byte-string boundaries roundtrip + via `Uint8Array`. - Build artifacts live under `tools/quickjs-native-harness/dist`. diff --git a/tools/quickjs-native-harness/project.json b/tools/quickjs-native-harness/project.json index ffdc2b6..9f258a3 100644 --- a/tools/quickjs-native-harness/project.json +++ b/tools/quickjs-native-harness/project.json @@ -8,13 +8,22 @@ "build": { "executor": "nx:run-commands", "cache": true, - "inputs": ["default", "quickjsSubmodule"], + "inputs": ["default", "quickjsSource"], "outputs": ["{workspaceRoot}/tools/quickjs-native-harness/dist"], "options": { "command": "bash tools/quickjs-native-harness/scripts/build.sh" } }, "test": { + "executor": "nx:run-commands", + "dependsOn": ["build"], + "outputs": ["{projectRoot}/test-output/vitest/coverage"], + "options": { + "command": "vitest", + "cwd": "tools/quickjs-native-harness" + } + }, + "test-legacy": { "executor": "nx:run-commands", "dependsOn": ["build"], "options": { diff --git a/tools/quickjs-native-harness/scripts/archive-reproducibility-report.mjs b/tools/quickjs-native-harness/scripts/archive-reproducibility-report.mjs new file mode 100644 index 0000000..49f8dea --- /dev/null +++ b/tools/quickjs-native-harness/scripts/archive-reproducibility-report.mjs @@ -0,0 +1,117 @@ +#!/usr/bin/env node + +import { mkdir, readFile, writeFile } from 'node:fs/promises'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { createHash } from 'node:crypto'; +import { spawnSync } from 'node:child_process'; + +const scriptDir = path.dirname(fileURLToPath(import.meta.url)); +const repoRoot = path.resolve(scriptDir, '../../..'); +const parityReportScriptPath = path.join(scriptDir, 'parity-report.mjs'); + +const args = parseArgs(process.argv.slice(2)); + +const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); +const outDir = path.resolve(repoRoot, args.outDir); +const reportPath = path.join(outDir, `parity-report-${timestamp}.json`); + +await mkdir(outDir, { recursive: true }); + +const reportArgs = [ + parityReportScriptPath, + '--include-gas-charge-tape', + '--out', + reportPath, +]; +if (args.strict) { + reportArgs.push('--assert-match'); +} +if (args.chargeTapeCapacity !== null) { + reportArgs.push( + '--gas-charge-tape-capacity', + String(args.chargeTapeCapacity), + ); +} + +const run = spawnSync(process.execPath, reportArgs, { + cwd: repoRoot, + encoding: 'utf8', +}); + +if (run.status !== 0) { + process.stdout.write(run.stdout ?? ''); + process.stderr.write(run.stderr ?? ''); + throw new Error( + `reproducibility report generation failed (exit ${run.status ?? 'unknown'})`, + ); +} + +const reportText = await readFile(reportPath, 'utf8'); +const report = JSON.parse(reportText); +if (args.strict && report.mismatchCount !== 0) { + throw new Error( + `strict reproducibility report mismatchCount is ${report.mismatchCount}, expected 0`, + ); +} +if ( + !report.signature || + report.signature.algorithm !== 'sha256' || + typeof report.signature.digest !== 'string' +) { + throw new Error('reproducibility report signature is missing or invalid'); +} + +const fileDigest = sha256Hex(reportText); +const digestPath = `${reportPath}.sha256`; +await writeFile( + digestPath, + `${fileDigest} ${path.basename(reportPath)}\n`, + 'utf8', +); + +process.stdout.write( + [ + `reproducibility report: ${reportPath}`, + `report signature digest: ${report.signature.digest}`, + `file sha256: ${fileDigest}`, + `file checksum: ${digestPath}`, + ].join('\n') + '\n', +); + +function sha256Hex(input) { + return createHash('sha256').update(input).digest('hex'); +} + +function parseArgs(argv) { + let outDir = 'artifacts/reproducibility'; + let chargeTapeCapacity = null; + let strict = false; + + for (let i = 0; i < argv.length; i += 1) { + const arg = argv[i]; + if (arg === '--strict') { + strict = true; + continue; + } + if (arg === '--out-dir') { + outDir = argv[i + 1] ?? outDir; + i += 1; + continue; + } + if (arg === '--gas-charge-tape-capacity') { + const parsed = Number.parseInt(argv[i + 1] ?? '', 10); + if (!Number.isInteger(parsed) || parsed < 0) { + throw new Error( + '--gas-charge-tape-capacity must be a non-negative integer', + ); + } + chargeTapeCapacity = parsed; + i += 1; + continue; + } + throw new Error(`unknown argument: ${arg}`); + } + + return { outDir, chargeTapeCapacity, strict }; +} diff --git a/tools/quickjs-native-harness/scripts/build.sh b/tools/quickjs-native-harness/scripts/build.sh index 65d5e67..3545195 100755 --- a/tools/quickjs-native-harness/scripts/build.sh +++ b/tools/quickjs-native-harness/scripts/build.sh @@ -7,6 +7,8 @@ QJS_DIR="${REPO_ROOT}/vendor/quickjs" OUT_DIR="${REPO_ROOT}/tools/quickjs-native-harness/dist" CC_BIN="${CC:-cc}" +bash "${REPO_ROOT}/tools/scripts/prepare-quickjs-source.sh" + VERSION="$(cat "${QJS_DIR}/VERSION")" mkdir -p "${OUT_DIR}" diff --git a/tools/quickjs-native-harness/scripts/dv-parity.mjs b/tools/quickjs-native-harness/scripts/dv-parity.mjs deleted file mode 100644 index bd90e9f..0000000 --- a/tools/quickjs-native-harness/scripts/dv-parity.mjs +++ /dev/null @@ -1,254 +0,0 @@ -#!/usr/bin/env node -import assert from 'node:assert/strict'; -import { existsSync, readFileSync } from 'node:fs'; -import { spawnSync } from 'node:child_process'; -import path from 'node:path'; -import { fileURLToPath } from 'node:url'; -import jiti from 'jiti'; - -const __dirname = path.dirname(fileURLToPath(import.meta.url)); -const repoRoot = path.resolve(__dirname, '../../..'); -const harnessPath = path.join( - repoRoot, - 'tools', - 'quickjs-native-harness', - 'dist', - 'quickjs-native-harness', -); -const manifestHex = readFileSync( - path.join( - repoRoot, - 'libs', - 'test-harness', - 'fixtures', - 'abi-manifest', - 'host-v1.bytes.hex', - ), - 'utf8', -).replace(/[\r\n\s]+/g, ''); -const manifestHash = readFileSync( - path.join( - repoRoot, - 'libs', - 'test-harness', - 'fixtures', - 'abi-manifest', - 'host-v1.hash', - ), - 'utf8', -).trim(); -const manifestArgs = [ - '--abi-manifest-hex', - manifestHex, - '--abi-manifest-hash', - manifestHash, -]; - -if (!existsSync(harnessPath)) { - throw new Error( - `Native harness not found at ${harnessPath}. Build quickjs-native-harness first.`, - ); -} - -const require = jiti(import.meta.url); -const { encodeDv, decodeDv } = require('../../../libs/dv/src/index.ts'); - -const encodeFixtures = [ - { name: 'null', expr: 'null', value: null }, - { name: 'boolean', expr: 'true', value: true }, - { name: 'int', expr: '42', value: 42 }, - { name: 'negative-int', expr: '-17', value: -17 }, - { name: 'float', expr: '1.5', value: 1.5 }, - { name: 'string', expr: '"hello"', value: 'hello' }, - { name: 'string-null-byte', expr: '"a\\u0000b"', value: 'a\u0000b' }, - { name: 'unicode', expr: '"\\u263a"', value: '\u263a' }, - { name: 'array', expr: '["hello", 1.5, -1]', value: ['hello', 1.5, -1] }, - { - name: 'object-ordering', - expr: '({ b: 2, aa: 1 })', - value: { b: 2, aa: 1 }, - }, - { - name: 'null-proto-object', - expr: '(() => { const o = Object.create(null); o.a = 1; o.b = "c"; return o; })()', - value: Object.assign(Object.create(null), { a: 1, b: 'c' }), - }, - { - name: 'nested', - expr: '({ nested: [1, { z: "hi" }], flag: false })', - value: { nested: [1, { z: 'hi' }], flag: false }, - }, - { - name: 'object-global-object-replacement', - expr: '(() => { function Fake() {} Fake.prototype = { hacked: true }; globalThis.Object = Fake; return { a: 1 }; })()', - value: { a: 1 }, - }, - { - name: 'emoji-non-bmp', - expr: '"\\uD83D\\uDE00"', - value: '\uD83D\uDE00', - }, - { name: 'empty-array', expr: '[]', value: [] }, - { name: 'empty-object', expr: '({})', value: {} }, - { name: 'negative-zero', expr: '-0', value: -0 }, -]; - -const encodeErrorFixtures = [ - { - name: 'encode-lone-surrogate', - expr: '"a\\uD800"', - value: 'a\uD800', - errorContains: 'lone surrogate code points', - }, -]; - -const decodeErrorFixtures = [ - { - name: 'decode-non-canonical-int-width', - hex: '1801', - errorContains: 'length not using shortest encoding', - }, - { - name: 'decode-float32', - hex: 'fa3f800000', - errorContains: 'only float64 is allowed', - }, - { - name: 'decode-byte-string', - hex: '40', - errorContains: 'unsupported CBOR major type', - }, - { - name: 'decode-trailing-bytes', - hex: 'f6f6', - errorContains: 'unexpected trailing bytes after DV value', - }, - { - name: 'decode-non-text-map-key', - hex: 'a10101', - errorContains: 'map keys must be text strings', - }, - { - name: 'decode-map-key-order', - hex: 'a262616101616202', - errorContains: 'map keys are not in canonical order', - }, -]; - -const toHex = (bytes) => - Array.from(bytes) - .map((b) => b.toString(16).padStart(2, '0')) - .join(''); - -const runHarness = (args, label) => { - const result = spawnSync(harnessPath, [...manifestArgs, ...args], { - encoding: 'utf8', - }); - if (result.error) { - throw result.error; - } - return { - stdout: (result.stdout ?? '').trim(), - stderr: (result.stderr ?? '').trim(), - status: result.status ?? 0, - label, - }; -}; - -const expectSuccess = (result, prefix) => { - if (result.status !== 0) { - throw new Error( - `${result.label ?? 'harness'} exited with ${result.status}: stdout="${result.stdout}" stderr="${result.stderr}"`, - ); - } - if (!result.stdout.startsWith(prefix)) { - throw new Error( - `Unexpected output for ${result.label ?? 'harness'}: stdout="${result.stdout}" stderr="${result.stderr}"`, - ); - } -}; - -const expectError = (result, context) => { - if (result.status === 0) { - throw new Error( - `Expected harness error for ${context}, got status=0 stdout="${result.stdout}" stderr="${result.stderr}"`, - ); - } - const prefix = 'ERROR '; - if (!result.stdout.startsWith(prefix)) { - throw new Error( - `Expected error output for ${context}: stdout="${result.stdout}" stderr="${result.stderr}" status=${result.status}`, - ); - } - return result.stdout.slice(prefix.length); -}; - -const runHarnessEncode = (expr) => { - const result = runHarness(['--dv-encode', '--eval', expr], `encode ${expr}`); - expectSuccess(result, 'DV '); - return result.stdout.slice('DV '.length); -}; - -const runHarnessDecode = (hex) => { - const result = runHarness(['--dv-decode', hex], `decode ${hex}`); - expectSuccess(result, 'DVRESULT '); - return result.stdout.slice('DVRESULT '.length); -}; - -const runHarnessEncodeError = (expr) => { - const result = runHarness(['--dv-encode', '--eval', expr], `encode ${expr}`); - return expectError(result, `encode ${expr}`); -}; - -const runHarnessDecodeError = (hex) => { - const result = runHarness(['--dv-decode', hex], `decode ${hex}`); - return expectError(result, `decode ${hex}`); -}; - -for (const fixture of encodeFixtures) { - const encoded = encodeDv(fixture.value); - const expectedHex = toHex(encoded); - const harnessHex = runHarnessEncode(fixture.expr); - assert.strictEqual( - harnessHex, - expectedHex, - `encode mismatch for ${fixture.name}`, - ); - - const expectedJson = JSON.stringify(decodeDv(encoded)); - const harnessJson = runHarnessDecode(expectedHex); - assert.strictEqual( - harnessJson, - expectedJson, - `decode mismatch for ${fixture.name}`, - ); -} - -for (const fixture of encodeErrorFixtures) { - assert.throws( - () => encodeDv(fixture.value), - new RegExp(fixture.errorContains), - `TS encode should reject ${fixture.name}`, - ); - const harnessError = runHarnessEncodeError(fixture.expr); - assert.ok( - harnessError.includes(fixture.errorContains), - `encode error mismatch for ${fixture.name}: ${harnessError}`, - ); -} - -for (const fixture of decodeErrorFixtures) { - assert.throws( - () => decodeDv(Buffer.from(fixture.hex, 'hex')), - new RegExp(fixture.errorContains), - `TS decode should reject ${fixture.name}`, - ); - const harnessError = runHarnessDecodeError(fixture.hex); - assert.ok( - harnessError.includes(fixture.errorContains), - `decode error mismatch for ${fixture.name}: ${harnessError}`, - ); -} - -console.log('DV parity against TS reference: ok'); -console.log('DV rejection parity cases: ok'); diff --git a/tools/quickjs-native-harness/scripts/gas-goldens.mjs b/tools/quickjs-native-harness/scripts/gas-goldens.mjs deleted file mode 100644 index ee4005b..0000000 --- a/tools/quickjs-native-harness/scripts/gas-goldens.mjs +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/env node -import { readFileSync, existsSync } from 'fs'; -import { fileURLToPath } from 'url'; -import { dirname, join, resolve } from 'path'; -import { spawnSync } from 'child_process'; - -const scriptDir = dirname(fileURLToPath(import.meta.url)); -const repoRoot = resolve(scriptDir, '..', '..', '..'); -const harnessRoot = join(repoRoot, 'tools', 'quickjs-native-harness'); -const fixturesRoot = join(harnessRoot, 'fixtures'); -const binPath = join(harnessRoot, 'dist', 'quickjs-native-harness'); -const fixturesPath = join(scriptDir, 'gas-goldens.json'); -const manifestHex = readFileSync( - join( - repoRoot, - 'libs', - 'test-harness', - 'fixtures', - 'abi-manifest', - 'host-v1.bytes.hex', - ), - 'utf8', -).replace(/[\r\n\s]+/g, ''); -const manifestHash = readFileSync( - join( - repoRoot, - 'libs', - 'test-harness', - 'fixtures', - 'abi-manifest', - 'host-v1.hash', - ), - 'utf8', -).trim(); -const manifestArgs = [ - '--abi-manifest-hex', - manifestHex, - '--abi-manifest-hash', - manifestHash, -]; - -if (!existsSync(binPath)) { - console.error(`Harness binary not found at ${binPath}. Run build first.`); - process.exit(1); -} - -const cases = JSON.parse(readFileSync(fixturesPath, 'utf8')); - -const failures = []; - -for (const testCase of cases) { - const codePath = join(fixturesRoot, testCase.fixture); - const code = readFileSync(codePath, 'utf8'); - const args = [...manifestArgs, ...(testCase.args || []), '--eval', code]; - - const result = spawnSync(binPath, args, { encoding: 'utf8' }); - const stdout = (result.stdout || '').trim(); - if (result.error) { - failures.push({ - name: testCase.name, - expected: testCase.expected, - actual: `spawn error: ${result.error.message}`, - }); - continue; - } - - if (stdout !== testCase.expected) { - failures.push({ - name: testCase.name, - expected: testCase.expected, - actual: stdout, - }); - } -} - -if (failures.length > 0) { - console.error('Gas golden mismatches:'); - for (const failure of failures) { - console.error(`- ${failure.name}`); - console.error(` expected: ${failure.expected}`); - console.error(` actual: ${failure.actual}`); - } - process.exit(1); -} - -console.log(`Gas golden suite passed (${cases.length} cases)`); diff --git a/tools/quickjs-native-harness/scripts/host-gas.mjs b/tools/quickjs-native-harness/scripts/host-gas.mjs deleted file mode 100644 index 44295e8..0000000 --- a/tools/quickjs-native-harness/scripts/host-gas.mjs +++ /dev/null @@ -1,156 +0,0 @@ -#!/usr/bin/env node -import { existsSync, readFileSync } from 'fs'; -import { spawnSync } from 'child_process'; -import { dirname, join, resolve } from 'path'; -import { fileURLToPath } from 'url'; - -const scriptDir = dirname(fileURLToPath(import.meta.url)); -const repoRoot = resolve(scriptDir, '..', '..', '..'); -const harnessRoot = join(repoRoot, 'tools', 'quickjs-native-harness'); -const fixturesRoot = join( - repoRoot, - 'libs', - 'test-harness', - 'fixtures', - 'abi-manifest', -); -const binPath = join(harnessRoot, 'dist', 'quickjs-native-harness'); - -if (!existsSync(binPath)) { - console.error(`Harness binary not found at ${binPath}. Run build first.`); - process.exit(1); -} - -const manifestHex = readFileSync( - join(fixturesRoot, 'host-v1.bytes.hex'), - 'utf8', -).replace(/[\r\n\s]+/g, ''); -const manifestHash = readFileSync(join(fixturesRoot, 'host-v1.hash'), 'utf8') - .replace(/[\r\n\s]+/g, '') - .trim(); -const manifestArgs = [ - '--abi-manifest-hex', - manifestHex, - '--abi-manifest-hash', - manifestHash, -]; - -const cases = [ - { - name: 'document-get-ok', - code: "Host.v1.document.get('foo')", - requestExpr: "['foo']", - responseExpr: "({ ok: 'foo', units: 1 })", - units: 1, - gas: { base: 20, kArg: 1, kRet: 1, kUnits: 1 }, - }, - { - name: 'document-get-error', - code: "Host.v1.document.get('missing')", - requestExpr: "['missing']", - responseExpr: "({ err: { code: 'NOT_FOUND' }, units: 2 })", - units: 2, - gas: { base: 20, kArg: 1, kRet: 1, kUnits: 1 }, - }, - { - name: 'emit-null', - code: 'Host.v1.emit({ a: 1 })', - requestExpr: '[{ a: 1 }]', - responseExpr: '({ ok: null, units: 0 })', - units: 0, - gas: { base: 5, kArg: 1, kRet: 0, kUnits: 1 }, - }, -]; - -function dvLength(expr) { - const result = spawnSync(binPath, ['--dv-encode', '--eval', expr], { - encoding: 'utf8', - }); - if (result.error) { - throw new Error(`dv encode spawn error: ${result.error.message}`); - } - const stdout = (result.stdout || '').trim(); - const match = stdout.match(/^DV\s+([0-9a-fA-F]+)$/); - if (!match) { - throw new Error(`Unexpected dv encode output: ${stdout}`); - } - const hex = match[1].replace(/\s+/g, ''); - return hex.length / 2; -} - -function runHarness(code) { - const args = [ - ...manifestArgs, - '--gas-limit', - '10000', - '--report-gas', - '--gas-trace', - '--eval', - code, - ]; - const result = spawnSync(binPath, args, { encoding: 'utf8' }); - if (result.error) { - throw new Error(`harness spawn error: ${result.error.message}`); - } - const stdout = (result.stdout || '').trim(); - if (!stdout) { - throw new Error('Harness produced no stdout'); - } - const usedMatch = stdout.match(/used=(\d+)/); - const traceMatch = stdout.match(/TRACE (\{.*\})/); - if (!usedMatch || !traceMatch) { - throw new Error(`Missing gas or trace in output: ${stdout}`); - } - - const used = Number(usedMatch[1]); - const trace = JSON.parse(traceMatch[1]); - return { used, trace, raw: stdout, status: result.status }; -} - -function computeNonHostGas(trace) { - const opcode = Number(trace.opcodeGas || 0); - const arrayBase = Number(trace.arrayCbBase?.gas || 0); - const arrayPerEl = Number(trace.arrayCbPerEl?.gas || 0); - const alloc = Number(trace.alloc?.gas || 0); - const jsonParse = Number(trace.jsonParse?.gas || 0); - const jsonStringify = Number(trace.jsonStringify?.gas || 0); - return opcode + arrayBase + arrayPerEl + alloc + jsonParse + jsonStringify; -} - -const failures = []; - -for (const test of cases) { - const reqLen = dvLength(test.requestExpr); - const respLen = dvLength(test.responseExpr); - const expectedHostGas = - test.gas.base + - test.gas.kArg * reqLen + - test.gas.kRet * respLen + - test.gas.kUnits * test.units; - - const run = runHarness(test.code); - const nonHost = computeNonHostGas(run.trace); - const hostGas = run.used - nonHost; - - if (hostGas !== expectedHostGas) { - failures.push({ - name: test.name, - expected: expectedHostGas, - actual: hostGas, - raw: run.raw, - }); - } -} - -if (failures.length > 0) { - console.error('Host gas mismatches:'); - for (const failure of failures) { - console.error( - `- ${failure.name}: expected ${failure.expected}, actual ${failure.actual}`, - ); - console.error(` output: ${failure.raw}`); - } - process.exit(1); -} - -console.log(`Host gas suite passed (${cases.length} cases)`); diff --git a/tools/quickjs-native-harness/scripts/parity-gas-delta-baseline.json b/tools/quickjs-native-harness/scripts/parity-gas-delta-baseline.json new file mode 100644 index 0000000..7e233cb --- /dev/null +++ b/tools/quickjs-native-harness/scripts/parity-gas-delta-baseline.json @@ -0,0 +1,143 @@ +{ + "version": 1, + "entries": [ + { + "suite": "binary-library", + "fixtureName": "base64-js-roundtrip", + "gasDeltaUsed": "0", + "gasDeltaRemaining": "0" + }, + { + "suite": "binary-library", + "fixtureName": "noble-sha256-hex", + "gasDeltaUsed": "0", + "gasDeltaRemaining": "0" + }, + { + "suite": "determinism", + "fixtureName": "async-promise-chain", + "gasDeltaUsed": "0", + "gasDeltaRemaining": "0" + }, + { + "suite": "determinism", + "fixtureName": "async-promise-rejection", + "gasDeltaUsed": "0", + "gasDeltaRemaining": "0" + }, + { + "suite": "determinism", + "fixtureName": "async-queue-microtask-host", + "gasDeltaUsed": "0", + "gasDeltaRemaining": "0" + }, + { + "suite": "determinism", + "fixtureName": "canon-ops", + "gasDeltaUsed": "0", + "gasDeltaRemaining": "0" + }, + { + "suite": "determinism", + "fixtureName": "compat-binary-host-v2-bytes-roundtrip", + "gasDeltaUsed": "0", + "gasDeltaRemaining": "0" + }, + { + "suite": "determinism", + "fixtureName": "compat-console-shim", + "gasDeltaUsed": "0", + "gasDeltaRemaining": "0" + }, + { + "suite": "determinism", + "fixtureName": "compat-stable-sort", + "gasDeltaUsed": "0", + "gasDeltaRemaining": "0" + }, + { + "suite": "determinism", + "fixtureName": "doc-canonical", + "gasDeltaUsed": "0", + "gasDeltaRemaining": "0" + }, + { + "suite": "determinism", + "fixtureName": "doc-read", + "gasDeltaUsed": "0", + "gasDeltaRemaining": "0" + }, + { + "suite": "determinism", + "fixtureName": "host-error", + "gasDeltaUsed": "0", + "gasDeltaRemaining": "0" + }, + { + "suite": "determinism", + "fixtureName": "host-error-invalid", + "gasDeltaUsed": "0", + "gasDeltaRemaining": "0" + }, + { + "suite": "determinism", + "fixtureName": "host-error-limit", + "gasDeltaUsed": "0", + "gasDeltaRemaining": "0" + }, + { + "suite": "determinism", + "fixtureName": "host-gas-paths", + "gasDeltaUsed": "0", + "gasDeltaRemaining": "0" + }, + { + "suite": "determinism", + "fixtureName": "json-builtins", + "gasDeltaUsed": "0", + "gasDeltaRemaining": "0" + }, + { + "suite": "determinism", + "fixtureName": "multi-host", + "gasDeltaUsed": "0", + "gasDeltaRemaining": "0" + }, + { + "suite": "module-pack", + "fixtureName": "module-pack-cyclic-imports", + "gasDeltaUsed": "0", + "gasDeltaRemaining": "0" + }, + { + "suite": "module-pack", + "fixtureName": "module-pack-default-export", + "gasDeltaUsed": "0", + "gasDeltaRemaining": "0" + }, + { + "suite": "module-pack", + "fixtureName": "module-pack-host-call-tape", + "gasDeltaUsed": "0", + "gasDeltaRemaining": "0" + }, + { + "suite": "module-pack", + "fixtureName": "module-pack-missing-entry-specifier", + "gasDeltaUsed": "0", + "gasDeltaRemaining": "0" + }, + { + "suite": "module-pack", + "fixtureName": "module-pack-missing-export", + "gasDeltaUsed": "0", + "gasDeltaRemaining": "0" + }, + { + "suite": "module-pack", + "fixtureName": "module-pack-named-export", + "gasDeltaUsed": "0", + "gasDeltaRemaining": "0" + } + ] +} diff --git a/tools/quickjs-native-harness/scripts/parity-report.mjs b/tools/quickjs-native-harness/scripts/parity-report.mjs new file mode 100644 index 0000000..a410bd0 --- /dev/null +++ b/tools/quickjs-native-harness/scripts/parity-report.mjs @@ -0,0 +1,1519 @@ +#!/usr/bin/env node +import assert from 'node:assert/strict'; +import { spawnSync } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { existsSync, readFileSync } from 'node:fs'; +import { mkdir, readFile, writeFile } from 'node:fs/promises'; +import os from 'node:os'; +import path from 'node:path'; +import process from 'node:process'; +import { fileURLToPath } from 'node:url'; +import jiti from 'jiti'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const repoRoot = path.resolve(__dirname, '../../..'); +const require = jiti(import.meta.url, { interopDefault: true }); + +const harnessPath = path.join( + repoRoot, + 'tools', + 'quickjs-native-harness', + 'dist', + 'quickjs-native-harness', +); + +if (!existsSync(harnessPath)) { + throw new Error( + `Native harness not found at ${harnessPath}. Build quickjs-native-harness first.`, + ); +} + +const GAS_SPEC_PATH = path.join( + repoRoot, + 'tools', + 'gas-spec', + 'gas-spec.v3.json', +); +const QUICKJS_RUNTIME_INDEX_PATH = path.join( + repoRoot, + 'libs', + 'quickjs-runtime', + 'src', + 'index.ts', +); +const QUICKJS_RUNTIME_EVALUATE_ERRORS_PATH = path.join( + repoRoot, + 'libs', + 'quickjs-runtime', + 'src', + 'lib', + 'evaluate-errors.ts', +); +const GAS_VERSION = readGasVersion(); + +const { encodeDv, encodeDv2 } = require('../../../libs/dv/src/index.ts'); +const { + evaluate, + validateProgramArtifact, + validateProgramArtifactV2, + validateInputEnvelope, +} = require(QUICKJS_RUNTIME_INDEX_PATH); +const { mapVmError } = require(QUICKJS_RUNTIME_EVALUATE_ERRORS_PATH); +const { + hashAbiManifest, + validateAbiManifest, +} = require('../../../libs/abi-manifest/src/index.ts'); +const { + bundleDeterministicProgram, +} = require('../../../libs/deterministic-bundler/src/index.ts'); +const { + BINARY_LIBRARY_FIXTURES, + BINARY_LIBRARY_GAS_LIMIT, + BINARY_LIBRARY_INPUT, + BINARY_LIBRARY_MANIFEST, + BINARY_LIBRARY_PROGRAM_BASE, + DETERMINISM_FIXTURES, + MODULE_PACK_FIXTURES, + serializeHostTape, +} = require('../../../libs/test-harness/src/index.ts'); + +const TAPE_CAPACITY = 64; + +const argv = parseArgs(process.argv.slice(2)); + +/** @typedef {{resultHash: string | null, errorCode: string | null, errorTag: string | null, gasUsed: string, gasRemaining: string, tapeHash: string | null, tapeLength: number}} Snapshot */ + +async function main() { + const gasDeltaBaselineMap = + !argv.includeGasTrace && argv.gasDeltaBaselinePath + ? await loadGasDeltaBaselineMap(argv.gasDeltaBaselinePath) + : new Map(); + const comparison = { + ignoreGas: argv.ignoreGas || argv.includeGasTrace, + gasDeltaBaselineMap, + includeGasTrace: argv.includeGasTrace, + includeGasChargeTape: argv.includeGasChargeTape, + gasChargeTapeCapacity: argv.gasChargeTapeCapacity, + }; + const suites = []; + const fixtureReports = []; + + const determinism = await runFixtureSuite( + 'determinism', + DETERMINISM_FIXTURES, + (fixture) => fixture.program, + (fixture) => fixture.input, + (fixture) => fixture.manifest, + (fixture) => fixture.gasLimit, + comparison, + ); + suites.push(determinism.summary); + fixtureReports.push(...determinism.reports); + + const modulePack = await runFixtureSuite( + 'module-pack', + MODULE_PACK_FIXTURES, + (fixture) => fixture.program, + (fixture) => fixture.input, + (fixture) => fixture.manifest, + (fixture) => fixture.gasLimit, + comparison, + ); + suites.push(modulePack.summary); + fixtureReports.push(...modulePack.reports); + + const binaryFixtureReports = []; + for (const fixture of BINARY_LIBRARY_FIXTURES) { + const bundled = await bundleDeterministicProgram({ + absWorkingDir: repoRoot, + entryPath: fixture.entryPath, + profile: 'compat-binary-v1', + }); + const program = { + ...BINARY_LIBRARY_PROGRAM_BASE, + code: bundled.code, + }; + const host = createNativeCompatibleHost(); + const nodeSnapshot = await runNodeEvaluation({ + program, + input: BINARY_LIBRARY_INPUT, + manifest: BINARY_LIBRARY_MANIFEST, + gasLimit: BINARY_LIBRARY_GAS_LIMIT, + handlers: host.handlers, + includeGasTrace: comparison.includeGasTrace, + includeGasChargeTape: comparison.includeGasChargeTape, + gasChargeTapeCapacity: comparison.gasChargeTapeCapacity, + }); + assert.deepStrictEqual( + normalizeJsonValue(nodeSnapshot.okValue), + fixture.expectedValue, + `binary fixture "${fixture.name}" produced unexpected node value`, + ); + const nativeSnapshot = runNativeEvaluation({ + program, + manifest: BINARY_LIBRARY_MANIFEST, + input: BINARY_LIBRARY_INPUT, + gasLimit: BINARY_LIBRARY_GAS_LIMIT, + includeGasTrace: comparison.includeGasTrace, + includeGasChargeTape: comparison.includeGasChargeTape, + gasChargeTapeCapacity: comparison.gasChargeTapeCapacity, + }); + const report = compareSnapshots( + 'binary-library', + fixture.name, + { + node: nodeSnapshot.snapshot, + native: nativeSnapshot, + }, + comparison, + extractProgramMetadata(program), + ); + binaryFixtureReports.push(report); + } + + fixtureReports.push(...binaryFixtureReports); + suites.push(createSuiteSummary('binary-library', binaryFixtureReports)); + + const mismatchCount = fixtureReports.filter((report) => !report.match).length; + const report = buildReport({ + fixtureReports, + suites, + mismatchCount, + }); + + if (argv.outPath) { + const outPath = path.resolve(argv.outPath); + await mkdir(path.dirname(outPath), { recursive: true }); + await writeFile(outPath, `${JSON.stringify(report, null, 2)}\n`, 'utf8'); + } + + if (argv.writeGasDeltaBaselinePath) { + const baselinePath = path.resolve(argv.writeGasDeltaBaselinePath); + await mkdir(path.dirname(baselinePath), { recursive: true }); + await writeFile( + baselinePath, + `${JSON.stringify(buildGasDeltaBaseline(report), null, 2)}\n`, + 'utf8', + ); + } + + console.log(JSON.stringify(report, null, 2)); + + if (argv.comparePath) { + const compareResult = await compareWithReport(report, argv.comparePath); + console.error( + `comparison summary: differing fixtures=${compareResult.differenceCount}`, + ); + if (compareResult.differenceCount > 0) { + console.error(JSON.stringify(compareResult.differences, null, 2)); + process.exitCode = 1; + } + } + + if (argv.assertMatch && mismatchCount > 0) { + process.exitCode = 1; + } + + if (argv.gasDeltaBaselinePath && !argv.includeGasTrace) { + const gasDeltaResult = await compareGasDeltaBaseline( + report, + argv.gasDeltaBaselinePath, + ); + console.error( + `gas delta baseline summary: differing fixtures=${gasDeltaResult.differenceCount}`, + ); + if (gasDeltaResult.differenceCount > 0) { + console.error(JSON.stringify(gasDeltaResult.differences, null, 2)); + process.exitCode = 1; + } + } else if (argv.gasDeltaBaselinePath && argv.includeGasTrace) { + console.error( + 'gas delta baseline check skipped because --include-gas-trace perturbs gas counters', + ); + } +} + +/** + * @param {string} suiteName + * @param {Array} fixtures + * @param {(fixture: any) => any} getProgram + * @param {(fixture: any) => any} getInput + * @param {(fixture: any) => any} getManifest + * @param {(fixture: any) => bigint} getGasLimit + */ +async function runFixtureSuite( + suiteName, + fixtures, + getProgram, + getInput, + getManifest, + getGasLimit, + comparison, +) { + const reports = []; + for (const fixture of fixtures) { + const program = getProgram(fixture); + const manifest = getManifest(fixture); + const input = getInput(fixture); + const gasLimit = getGasLimit(fixture); + const host = createNativeCompatibleHost(); + const node = await runNodeEvaluation({ + program, + input, + manifest, + gasLimit, + handlers: host.handlers, + includeGasTrace: comparison.includeGasTrace, + includeGasChargeTape: comparison.includeGasChargeTape, + gasChargeTapeCapacity: comparison.gasChargeTapeCapacity, + }); + const native = runNativeEvaluation({ + program, + manifest, + input, + gasLimit, + includeGasTrace: comparison.includeGasTrace, + includeGasChargeTape: comparison.includeGasChargeTape, + gasChargeTapeCapacity: comparison.gasChargeTapeCapacity, + }); + reports.push( + compareSnapshots( + suiteName, + fixture.name, + { + node: node.snapshot, + native, + }, + comparison, + extractProgramMetadata(program), + ), + ); + } + + return { + summary: createSuiteSummary(suiteName, reports), + reports, + }; +} + +function createNativeCompatibleHost() { + return { + handlers: { + document: { + get: (docPath) => { + if (docPath === 'missing') { + return { + err: { code: 'NOT_FOUND', tag: 'host/not_found' }, + units: 2, + }; + } + if (docPath === 'limit') { + return { + err: { code: 'LIMIT_EXCEEDED', tag: 'host/limit' }, + units: 3, + }; + } + if (docPath === 'bytes/payload') { + return { ok: Uint8Array.from([222, 173, 190, 239]), units: 4 }; + } + return { ok: docPath, units: 1 }; + }, + getCanonical: (docPath) => { + if (docPath === 'missing') { + return { + err: { code: 'NOT_FOUND', tag: 'host/not_found' }, + units: 2, + }; + } + if (docPath === 'limit') { + return { + err: { code: 'LIMIT_EXCEEDED', tag: 'host/limit' }, + units: 3, + }; + } + if (docPath === 'bytes/payload') { + return { ok: Uint8Array.from([222, 173, 190, 239]), units: 4 }; + } + return { ok: docPath, units: 1 }; + }, + }, + emit: () => ({ ok: null, units: 0 }), + }, + }; +} + +/** + * @param {{program: any, input: any, manifest: any, gasLimit: bigint, handlers: any, includeGasTrace?: boolean, includeGasChargeTape?: boolean, gasChargeTapeCapacity?: number}} options + */ +async function runNodeEvaluation(options) { + const manifest = validateAbiManifest(options.manifest); + const program = normalizeProgram(options.program); + const input = validateInputEnvelope(options.input); + const result = await evaluate({ + program, + input, + gasLimit: options.gasLimit, + manifest, + handlers: options.handlers, + tape: { capacity: TAPE_CAPACITY }, + gasTrace: options.includeGasTrace ?? false, + ...(options.includeGasChargeTape + ? { + gasChargeTape: { + capacity: options.gasChargeTapeCapacity ?? 256, + }, + } + : {}), + }); + + if (result.ok) { + return { + okValue: result.value, + snapshot: { + resultHash: hashDv(result.value), + errorCode: null, + errorTag: null, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + tapeHash: hashTape(result.tape ?? []), + tapeLength: (result.tape ?? []).length, + ...(options.includeGasTrace && result.gasTrace + ? { gasTrace: normalizeNodeGasTrace(result.gasTrace) } + : {}), + ...(options.includeGasChargeTape && result.gasChargeTape + ? { + gasChargeTape: normalizeNodeGasChargeTape(result.gasChargeTape), + } + : {}), + }, + }; + } + + return { + okValue: null, + snapshot: { + resultHash: null, + errorCode: result.error.code, + errorTag: 'tag' in result.error ? result.error.tag : null, + gasUsed: result.gasUsed.toString(), + gasRemaining: result.gasRemaining.toString(), + tapeHash: hashTape(result.tape ?? []), + tapeLength: (result.tape ?? []).length, + ...(options.includeGasTrace && result.gasTrace + ? { gasTrace: normalizeNodeGasTrace(result.gasTrace) } + : {}), + ...(options.includeGasChargeTape && result.gasChargeTape + ? { gasChargeTape: normalizeNodeGasChargeTape(result.gasChargeTape) } + : {}), + }, + }; +} + +/** + * @param {{program: any, manifest: any, input: any, gasLimit: bigint, includeGasTrace?: boolean, includeGasChargeTape?: boolean, gasChargeTapeCapacity?: number}} options + * @returns {Snapshot} + */ +function runNativeEvaluation(options) { + const manifest = validateAbiManifest(options.manifest); + const manifestCanonical = hashAbiManifest(manifest); + const contextBlobHex = bytesToHex(encodeDv(options.input)); + const profile = inferExecutionProfile(options.program); + const args = [ + '--abi-manifest-hex', + bytesToHex(manifestCanonical.bytes), + '--abi-manifest-hash', + manifestCanonical.hash, + '--execution-profile', + profile, + '--context-blob-hex', + contextBlobHex, + '--gas-limit', + options.gasLimit.toString(), + '--report-gas', + '--report-tape', + ...(options.includeGasChargeTape + ? [ + '--gas-charge-tape', + '--gas-charge-tape-capacity', + String(options.gasChargeTapeCapacity ?? 256), + ] + : []), + ...(options.includeGasTrace ? ['--gas-trace'] : []), + ...buildProgramArgs(options.program), + ]; + const result = spawnSync(harnessPath, args, { encoding: 'utf8' }); + if (result.error) { + throw result.error; + } + const stdout = (result.stdout ?? '').trim(); + if (!stdout) { + throw new Error( + `native harness emitted empty output: ${result.stderr ?? ''}`, + ); + } + return parseNativeSnapshot(stdout, manifest, { + includeGasTrace: options.includeGasTrace ?? false, + includeGasChargeTape: options.includeGasChargeTape ?? false, + }); +} + +function inferExecutionProfile(program) { + return program.executionProfile ?? 'baseline-v1'; +} + +function buildProgramArgs(program) { + if (program.version === 2 && program.sourceKind === 'module-pack') { + const modulePack = program.source.modulePack; + return [ + '--module-entry-specifier', + modulePack.entrySpecifier, + '--module-entry-export', + modulePack.entryExport ?? 'default', + '--module-pack-json', + JSON.stringify(modulePack.modules), + ]; + } + + if (program.version === 2 && program.sourceKind === 'script') { + return ['--parity-eval', '--eval', program.source.code]; + } + + return ['--parity-eval', '--eval', program.code]; +} + +function parseNativeSnapshot(stdout, manifest, options) { + const gasMatch = stdout.match(/ GAS remaining=(\d+)(?: used=(\d+))?/); + if (!gasMatch || gasMatch.index == null) { + throw new Error(`missing gas trailer in native output: ${stdout}`); + } + const tapeMarker = ' TAPE '; + const tapeIndex = stdout.lastIndexOf(tapeMarker); + if (tapeIndex < 0) { + throw new Error(`missing tape trailer in native output: ${stdout}`); + } + const chargeTapeMarker = ' CHARGE_TAPE '; + const chargeTapeIndex = stdout.lastIndexOf(chargeTapeMarker); + + const gasStart = gasMatch.index; + const gasRemaining = gasMatch[1]; + const gasUsed = gasMatch[2] ?? '0'; + const trace = parseNativeTrace(stdout, tapeIndex, options); + const tapeEnd = chargeTapeIndex > tapeIndex ? chargeTapeIndex : stdout.length; + const tapeJson = stdout.slice(tapeIndex + tapeMarker.length, tapeEnd).trim(); + const tape = parseNativeTape(tapeJson); + const gasChargeTape = + options.includeGasChargeTape && chargeTapeIndex > tapeIndex + ? parseNativeGasChargeTape( + stdout.slice(chargeTapeIndex + chargeTapeMarker.length).trim(), + ) + : null; + + if (stdout.startsWith('RESULT ')) { + const valueJson = stdout.slice('RESULT '.length, gasStart); + const value = JSON.parse(valueJson); + return { + resultHash: hashDv(value), + errorCode: null, + errorTag: null, + gasUsed, + gasRemaining, + tapeHash: hashTape(tape), + tapeLength: tape.length, + ...(trace ? { gasTrace: trace } : {}), + ...(gasChargeTape ? { gasChargeTape } : {}), + }; + } + + if (stdout.startsWith('ERROR ')) { + const message = stdout.slice('ERROR '.length, gasStart); + const mapped = mapVmError(message, validateAbiManifest(manifest)); + return { + resultHash: null, + errorCode: mapped.code, + errorTag: mapped.tag, + gasUsed, + gasRemaining, + tapeHash: hashTape(tape), + tapeLength: tape.length, + ...(trace ? { gasTrace: trace } : {}), + ...(gasChargeTape ? { gasChargeTape } : {}), + }; + } + + throw new Error(`unexpected native output prefix: ${stdout}`); +} + +function parseNativeTrace(stdout, tapeIndex, options) { + if (!options.includeGasTrace) { + return null; + } + const marker = ' TRACE '; + const traceIndex = stdout.lastIndexOf(marker); + if (traceIndex < 0 || traceIndex > tapeIndex) { + return null; + } + const traceJson = stdout.slice(traceIndex + marker.length, tapeIndex).trim(); + if (!traceJson) { + return null; + } + const parsed = JSON.parse(traceJson); + return normalizeNativeGasTrace(parsed); +} + +function parseNativeTape(tapeJson) { + const parsed = JSON.parse(tapeJson); + if (!Array.isArray(parsed)) { + throw new Error(`native tape must be array JSON: ${tapeJson}`); + } + return parsed.map((record) => ({ + fnId: Number(record.fnId), + reqLen: Number(record.reqLen), + respLen: Number(record.respLen), + units: Number(record.units), + gasPre: BigInt(record.gasPre), + gasPost: BigInt(record.gasPost), + isError: Boolean(record.isError), + chargeFailed: Boolean(record.chargeFailed), + reqHash: String(record.reqHash), + respHash: String(record.respHash), + })); +} + +function parseNativeGasChargeTape(chargeTapeJson) { + const parsed = JSON.parse(chargeTapeJson); + if (!Array.isArray(parsed)) { + throw new Error(`native charge tape must be array JSON: ${chargeTapeJson}`); + } + return parsed.map((record) => ({ + siteId: Number(record.siteId), + kind: Number(record.kind), + flags: Number(record.flags), + amount: String(record.amount), + logicalUnits: String(record.logicalUnits), + gasBefore: String(record.gasBefore), + gasAfter: String(record.gasAfter), + })); +} + +function compareSnapshots( + suite, + fixtureName, + snapshots, + comparison = { ignoreGas: false }, + metadata = { + executionProfile: 'unknown', + sourceKind: 'script', + gasVersion: null, + }, +) { + const baselineEntry = comparison.gasDeltaBaselineMap?.get( + `${suite}:${fixtureName}`, + ); + const match = isSnapshotEqual( + snapshots.node, + snapshots.native, + comparison, + baselineEntry, + ); + const gasDeltaUsed = + BigInt(snapshots.native.gasUsed) - BigInt(snapshots.node.gasUsed); + const gasDeltaRemaining = + BigInt(snapshots.native.gasRemaining) - BigInt(snapshots.node.gasRemaining); + const gasTraceDelta = + comparison.includeGasTrace && + snapshots.node.gasTrace && + snapshots.native.gasTrace + ? computeGasTraceDelta(snapshots.node.gasTrace, snapshots.native.gasTrace) + : null; + const tracedGasDeltaUsed = gasTraceDelta + ? sumTracedGasDelta(gasTraceDelta) + : null; + const residualGasDeltaUsed = + tracedGasDeltaUsed !== null ? gasDeltaUsed - tracedGasDeltaUsed : null; + const allocationGasDeltaUsed = gasTraceDelta + ? BigInt(String(gasTraceDelta.allocationGas ?? '0')) + : null; + const nonAllocationTracedGasDeltaUsed = + tracedGasDeltaUsed !== null && allocationGasDeltaUsed !== null + ? tracedGasDeltaUsed - allocationGasDeltaUsed + : null; + const chargeTapeComparison = + comparison.includeGasChargeTape && + snapshots.node.gasChargeTape && + snapshots.native.gasChargeTape + ? compareGasChargeTape( + snapshots.node.gasChargeTape, + snapshots.native.gasChargeTape, + ) + : null; + return { + suite, + fixtureName, + match, + metadata, + gasDeltaUsed: gasDeltaUsed.toString(), + gasDeltaRemaining: gasDeltaRemaining.toString(), + ...(baselineEntry + ? { + expectedGasDeltaUsed: baselineEntry.gasDeltaUsed, + expectedGasDeltaRemaining: baselineEntry.gasDeltaRemaining, + } + : {}), + ...(gasTraceDelta + ? { + gasTraceDelta, + tracedGasDeltaUsed: tracedGasDeltaUsed.toString(), + residualGasDeltaUsed: residualGasDeltaUsed.toString(), + allocationGasDeltaUsed: allocationGasDeltaUsed.toString(), + nonAllocationTracedGasDeltaUsed: + nonAllocationTracedGasDeltaUsed.toString(), + } + : {}), + ...(chargeTapeComparison + ? { + nodeChargeTapeHash: chargeTapeComparison.nodeHash, + nativeChargeTapeHash: chargeTapeComparison.nativeHash, + nodeChargeTapeLength: chargeTapeComparison.nodeLength, + nativeChargeTapeLength: chargeTapeComparison.nativeLength, + ...(chargeTapeComparison.siteDeltaSummaryTop + ? { + chargeTapeSiteDeltaSummaryTop: + chargeTapeComparison.siteDeltaSummaryTop, + } + : {}), + ...(chargeTapeComparison.firstDivergence + ? { + firstDivergentChargeIndex: + chargeTapeComparison.firstDivergence.index, + firstDivergentChargeSiteId: + chargeTapeComparison.firstDivergence.siteId, + firstDivergentChargeNodeGasBefore: + chargeTapeComparison.firstDivergence.nodeGasBefore, + firstDivergentChargeNativeGasBefore: + chargeTapeComparison.firstDivergence.nativeGasBefore, + firstDivergentChargeNodeGasAfter: + chargeTapeComparison.firstDivergence.nodeGasAfter, + firstDivergentChargeNativeGasAfter: + chargeTapeComparison.firstDivergence.nativeGasAfter, + } + : {}), + } + : {}), + node: snapshots.node, + native: snapshots.native, + ...(match + ? {} + : { + differences: listSnapshotDifferences( + snapshots.node, + snapshots.native, + ), + }), + }; +} + +function isSnapshotEqual(left, right, comparison, baselineEntry) { + const baseMatch = + left.resultHash === right.resultHash && + left.errorCode === right.errorCode && + left.errorTag === right.errorTag && + left.tapeHash === right.tapeHash && + left.tapeLength === right.tapeLength; + if (!baseMatch) { + return false; + } + if ( + comparison?.includeGasChargeTape && + !areGasChargeTapesEqual(left.gasChargeTape, right.gasChargeTape) + ) { + return false; + } + if (comparison?.ignoreGas) { + return true; + } + if (baselineEntry) { + const normalizedNativeUsed = + BigInt(right.gasUsed) - BigInt(baselineEntry.gasDeltaUsed); + const normalizedNativeRemaining = + BigInt(right.gasRemaining) - BigInt(baselineEntry.gasDeltaRemaining); + return ( + normalizedNativeUsed === BigInt(left.gasUsed) && + normalizedNativeRemaining === BigInt(left.gasRemaining) + ); + } + return ( + left.gasUsed === right.gasUsed && left.gasRemaining === right.gasRemaining + ); +} + +function areGasChargeTapesEqual(left, right) { + if (!left && !right) { + return true; + } + if (!left || !right) { + return false; + } + return JSON.stringify(left) === JSON.stringify(right); +} + +function compareGasChargeTape(nodeRecords, nativeRecords) { + const nodeHash = hashGasChargeTape(nodeRecords); + const nativeHash = hashGasChargeTape(nativeRecords); + const maxLength = Math.max(nodeRecords.length, nativeRecords.length); + const siteDeltaSummary = summarizeChargeSiteDeltas( + nodeRecords, + nativeRecords, + ); + let firstDivergence = null; + for (let index = 0; index < maxLength; index += 1) { + const left = nodeRecords[index]; + const right = nativeRecords[index]; + if (JSON.stringify(left) !== JSON.stringify(right)) { + firstDivergence = { + index, + siteId: Number((right && right.siteId) ?? (left && left.siteId) ?? -1), + nodeGasBefore: left?.gasBefore ?? null, + nativeGasBefore: right?.gasBefore ?? null, + nodeGasAfter: left?.gasAfter ?? null, + nativeGasAfter: right?.gasAfter ?? null, + }; + break; + } + } + return { + nodeHash, + nativeHash, + nodeLength: nodeRecords.length, + nativeLength: nativeRecords.length, + ...(siteDeltaSummary.length > 0 + ? { siteDeltaSummaryTop: siteDeltaSummary } + : {}), + firstDivergence, + }; +} + +function hashGasChargeTape(records) { + return sha256Hex(JSON.stringify(records)); +} + +function summarizeChargeSiteDeltas(nodeRecords, nativeRecords, limit = 8) { + const nodeBySite = new Map(); + const nativeBySite = new Map(); + for (const record of nodeRecords) { + const siteId = Number(record.siteId); + const entry = nodeBySite.get(siteId) ?? { gas: 0n, count: 0n }; + entry.gas += BigInt(record.amount); + entry.count += 1n; + nodeBySite.set(siteId, entry); + } + for (const record of nativeRecords) { + const siteId = Number(record.siteId); + const entry = nativeBySite.get(siteId) ?? { gas: 0n, count: 0n }; + entry.gas += BigInt(record.amount); + entry.count += 1n; + nativeBySite.set(siteId, entry); + } + const allSiteIds = new Set([...nodeBySite.keys(), ...nativeBySite.keys()]); + const rows = []; + for (const siteId of allSiteIds) { + const nodeEntry = nodeBySite.get(siteId) ?? { gas: 0n, count: 0n }; + const nativeEntry = nativeBySite.get(siteId) ?? { gas: 0n, count: 0n }; + const deltaGas = nodeEntry.gas - nativeEntry.gas; + const deltaCount = nodeEntry.count - nativeEntry.count; + if (deltaGas === 0n && deltaCount === 0n) { + continue; + } + rows.push({ + siteId, + deltaGas: deltaGas.toString(), + deltaCount: deltaCount.toString(), + nodeGas: nodeEntry.gas.toString(), + nativeGas: nativeEntry.gas.toString(), + nodeCount: nodeEntry.count.toString(), + nativeCount: nativeEntry.count.toString(), + }); + } + rows.sort((left, right) => { + const leftGasAbs = bigIntAbs(BigInt(left.deltaGas)); + const rightGasAbs = bigIntAbs(BigInt(right.deltaGas)); + if (leftGasAbs === rightGasAbs) { + const leftCountAbs = bigIntAbs(BigInt(left.deltaCount)); + const rightCountAbs = bigIntAbs(BigInt(right.deltaCount)); + if (leftCountAbs === rightCountAbs) { + return Number(left.siteId) - Number(right.siteId); + } + return rightCountAbs > leftCountAbs ? 1 : -1; + } + return rightGasAbs > leftGasAbs ? 1 : -1; + }); + return rows.slice(0, limit); +} + +function listSnapshotDifferences(nodeSnapshot, nativeSnapshot) { + const differences = []; + for (const key of [ + 'resultHash', + 'errorCode', + 'errorTag', + 'gasUsed', + 'gasRemaining', + 'tapeHash', + 'tapeLength', + ]) { + if (nodeSnapshot[key] !== nativeSnapshot[key]) { + differences.push({ + field: key, + node: nodeSnapshot[key], + native: nativeSnapshot[key], + }); + } + } + return differences; +} + +function createSuiteSummary(suite, reports) { + const mismatches = reports.filter((report) => !report.match).length; + const absGasUsed = reports.map((report) => + bigIntAbs(BigInt(report.gasDeltaUsed)), + ); + const absGasRemaining = reports.map((report) => + bigIntAbs(BigInt(report.gasDeltaRemaining)), + ); + const maxAbsGasUsed = + absGasUsed.length > 0 + ? absGasUsed.reduce((max, value) => (value > max ? value : max), 0n) + : 0n; + const maxAbsGasRemaining = + absGasRemaining.length > 0 + ? absGasRemaining.reduce((max, value) => (value > max ? value : max), 0n) + : 0n; + return { + suite, + totalFixtures: reports.length, + mismatches, + matched: reports.length - mismatches, + maxAbsGasDeltaUsed: maxAbsGasUsed.toString(), + maxAbsGasDeltaRemaining: maxAbsGasRemaining.toString(), + }; +} + +function buildReport({ fixtureReports, suites, mismatchCount }) { + const gasTraceSummary = summarizeGasTraceDeltas(fixtureReports); + const gasVersions = [ + ...new Set( + fixtureReports + .map((report) => report.metadata?.gasVersion) + .filter((value) => value !== null && value !== undefined), + ), + ].sort((left, right) => Number(left) - Number(right)); + const payload = { + generatedAt: new Date().toISOString(), + gitCommit: readGitCommit(), + environment: { + platform: process.platform, + arch: process.arch, + release: os.release(), + hostname: os.hostname(), + nodeVersion: process.version, + }, + ...(GAS_VERSION !== null ? { gasVersion: GAS_VERSION } : {}), + suites, + fixtureReports, + mismatchCount, + ...(gasVersions.length > 0 ? { gasVersions } : {}), + ...(gasTraceSummary ? { gasTraceSummary } : {}), + }; + const digest = sha256Hex(JSON.stringify(payload)); + return { + ...payload, + signature: { + algorithm: 'sha256', + digest, + }, + }; +} + +function readGasVersion() { + if (!existsSync(GAS_SPEC_PATH)) { + return null; + } + try { + const parsed = JSON.parse(readFileSync(GAS_SPEC_PATH, 'utf8')); + if (Number.isInteger(parsed?.gasVersion) && parsed.gasVersion >= 0) { + return parsed.gasVersion; + } + return null; + } catch { + return null; + } +} + +function hashDv(value) { + return sha256Hex(Buffer.from(encodeDv2(value))); +} + +function hashTape(tape) { + if (tape.length === 0) { + return null; + } + return sha256Hex(Buffer.from(serializeHostTape(tape))); +} + +function bytesToHex(bytes) { + return Buffer.from(bytes).toString('hex'); +} + +function sha256Hex(input) { + return createHash('sha256').update(input).digest('hex'); +} + +function normalizeProgram(program) { + if (program.version === 2) { + return validateProgramArtifactV2(program); + } + return validateProgramArtifact(program); +} + +function extractProgramMetadata(program) { + const executionProfile = program.executionProfile ?? 'baseline-v1'; + const sourceKind = + program.version === 2 ? String(program.sourceKind) : 'script'; + const gasVersion = program.gasVersion ?? null; + return { + executionProfile, + sourceKind, + gasVersion, + }; +} + +function normalizeJsonValue(value) { + if (Array.isArray(value)) { + return value.map((entry) => normalizeJsonValue(entry)); + } + if (value && typeof value === 'object') { + const normalized = {}; + for (const [key, entry] of Object.entries(value)) { + normalized[key] = normalizeJsonValue(entry); + } + return normalized; + } + return value; +} + +function normalizeNodeGasTrace(trace) { + const normalizeBigIntString = (value) => value.toString(); + return { + opcodeCount: normalizeBigIntString(trace.opcodeCount), + opcodeGas: normalizeBigIntString(trace.opcodeGas), + arrayCbBaseCount: normalizeBigIntString(trace.arrayCbBaseCount), + arrayCbBaseGas: normalizeBigIntString(trace.arrayCbBaseGas), + arrayCbPerElCount: normalizeBigIntString(trace.arrayCbPerElCount), + arrayCbPerElGas: normalizeBigIntString(trace.arrayCbPerElGas), + allocationCount: normalizeBigIntString(trace.allocationCount), + allocationRequestedBytes: normalizeBigIntString( + trace.allocationRequestedBytes ?? trace.allocationBytes, + ), + allocationBytes: normalizeBigIntString(trace.allocationBytes), + allocationGas: normalizeBigIntString(trace.allocationGas), + jsonParseCount: normalizeBigIntString(trace.jsonParseCount), + jsonParseGas: normalizeBigIntString(trace.jsonParseGas), + jsonParseInputBytes: normalizeBigIntString(trace.jsonParseInputBytes), + jsonParseValues: normalizeBigIntString(trace.jsonParseValues), + jsonParseObjectEntries: normalizeBigIntString(trace.jsonParseObjectEntries), + jsonParseArrayElements: normalizeBigIntString(trace.jsonParseArrayElements), + jsonStringifyCount: normalizeBigIntString(trace.jsonStringifyCount), + jsonStringifyGas: normalizeBigIntString(trace.jsonStringifyGas), + jsonStringifyOutputBytes: normalizeBigIntString( + trace.jsonStringifyOutputBytes, + ), + jsonStringifyValues: normalizeBigIntString(trace.jsonStringifyValues), + jsonStringifyObjectEntries: normalizeBigIntString( + trace.jsonStringifyObjectEntries, + ), + jsonStringifyArrayElements: normalizeBigIntString( + trace.jsonStringifyArrayElements, + ), + jsonStringifySortComparisons: normalizeBigIntString( + trace.jsonStringifySortComparisons, + ), + hostCallPreCount: normalizeBigIntString(trace.hostCallPreCount), + hostCallPreGas: normalizeBigIntString(trace.hostCallPreGas), + hostCallPostCount: normalizeBigIntString(trace.hostCallPostCount), + hostCallPostGas: normalizeBigIntString(trace.hostCallPostGas), + }; +} + +function normalizeNodeGasChargeTape(records) { + return records.map((record) => ({ + siteId: Number(record.siteId), + kind: Number(record.kind), + flags: Number(record.flags), + amount: record.amount.toString(), + logicalUnits: record.logicalUnits.toString(), + gasBefore: record.gasBefore.toString(), + gasAfter: record.gasAfter.toString(), + })); +} + +function normalizeNativeGasTrace(trace) { + const from = (value) => String(value ?? '0'); + return { + opcodeCount: from(trace.opcodeCount), + opcodeGas: from(trace.opcodeGas), + arrayCbBaseCount: from(trace.arrayCbBase?.count), + arrayCbBaseGas: from(trace.arrayCbBase?.gas), + arrayCbPerElCount: from(trace.arrayCbPerEl?.count), + arrayCbPerElGas: from(trace.arrayCbPerEl?.gas), + allocationCount: from(trace.alloc?.count), + allocationRequestedBytes: from( + trace.alloc?.requestedBytes ?? trace.alloc?.bytes, + ), + allocationBytes: from(trace.alloc?.bytes), + allocationGas: from(trace.alloc?.gas), + jsonParseCount: from(trace.jsonParse?.count), + jsonParseGas: from(trace.jsonParse?.gas), + jsonParseInputBytes: from(trace.jsonParse?.inputBytes), + jsonParseValues: from(trace.jsonParse?.values), + jsonParseObjectEntries: from(trace.jsonParse?.objectEntries), + jsonParseArrayElements: from(trace.jsonParse?.arrayElements), + jsonStringifyCount: from(trace.jsonStringify?.count), + jsonStringifyGas: from(trace.jsonStringify?.gas), + jsonStringifyOutputBytes: from(trace.jsonStringify?.outputBytes), + jsonStringifyValues: from(trace.jsonStringify?.values), + jsonStringifyObjectEntries: from(trace.jsonStringify?.objectEntries), + jsonStringifyArrayElements: from(trace.jsonStringify?.arrayElements), + jsonStringifySortComparisons: from(trace.jsonStringify?.sortComparisons), + hostCallPreCount: from(trace.hostCallPre?.count), + hostCallPreGas: from(trace.hostCallPre?.gas), + hostCallPostCount: from(trace.hostCallPost?.count), + hostCallPostGas: from(trace.hostCallPost?.gas), + }; +} + +function computeGasTraceDelta(nodeTrace, nativeTrace) { + const delta = {}; + const keys = Object.keys(nodeTrace); + for (const key of keys) { + const left = BigInt(nodeTrace[key] ?? '0'); + const right = BigInt(nativeTrace[key] ?? '0'); + delta[key] = (right - left).toString(); + } + return delta; +} + +function sumTracedGasDelta(gasTraceDelta) { + const gasKeys = [ + 'opcodeGas', + 'arrayCbBaseGas', + 'arrayCbPerElGas', + 'allocationGas', + 'jsonParseGas', + 'jsonStringifyGas', + 'hostCallPreGas', + 'hostCallPostGas', + ]; + let sum = 0n; + for (const key of gasKeys) { + sum += BigInt(String(gasTraceDelta[key] ?? '0')); + } + return sum; +} + +function readGitCommit() { + const result = spawnSync('git', ['rev-parse', 'HEAD'], { + cwd: repoRoot, + encoding: 'utf8', + }); + if (result.status !== 0) { + return 'unknown'; + } + return (result.stdout ?? '').trim() || 'unknown'; +} + +function parseArgs(args) { + let outPath = null; + let comparePath = null; + let assertMatch = false; + let ignoreGas = false; + let includeGasTrace = false; + let includeGasChargeTape = false; + let gasChargeTapeCapacity = null; + let gasDeltaBaselinePath = null; + let writeGasDeltaBaselinePath = null; + for (let i = 0; i < args.length; i += 1) { + const arg = args[i]; + if (arg === '--out') { + outPath = args[i + 1] ? args[i + 1] : null; + i += 1; + continue; + } + if (arg === '--compare') { + comparePath = args[i + 1] ? args[i + 1] : null; + i += 1; + continue; + } + if (arg === '--assert-match') { + assertMatch = true; + continue; + } + if (arg === '--ignore-gas') { + ignoreGas = true; + continue; + } + if (arg === '--include-gas-trace') { + includeGasTrace = true; + continue; + } + if (arg === '--include-gas-charge-tape') { + includeGasChargeTape = true; + continue; + } + if (arg === '--gas-charge-tape-capacity') { + const value = args[i + 1] ? Number.parseInt(args[i + 1], 10) : NaN; + if (!Number.isInteger(value) || value < 0) { + throw new Error( + '--gas-charge-tape-capacity must be a non-negative integer', + ); + } + gasChargeTapeCapacity = value; + i += 1; + continue; + } + if (arg === '--gas-delta-baseline') { + gasDeltaBaselinePath = args[i + 1] ? args[i + 1] : null; + i += 1; + continue; + } + if (arg === '--write-gas-delta-baseline') { + writeGasDeltaBaselinePath = args[i + 1] ? args[i + 1] : null; + i += 1; + } + } + return { + outPath, + comparePath, + assertMatch, + ignoreGas, + includeGasTrace, + includeGasChargeTape, + gasChargeTapeCapacity, + gasDeltaBaselinePath, + writeGasDeltaBaselinePath, + }; +} + +async function compareWithReport(currentReport, comparePath) { + const baselineText = await readFile(path.resolve(comparePath), 'utf8'); + const baseline = JSON.parse(baselineText); + + const baselineByFixture = new Map(); + for (const report of baseline.fixtureReports ?? []) { + baselineByFixture.set(`${report.suite}:${report.fixtureName}`, report); + } + + const differences = []; + for (const current of currentReport.fixtureReports) { + const key = `${current.suite}:${current.fixtureName}`; + const previous = baselineByFixture.get(key); + if (!previous) { + differences.push({ + suite: current.suite, + fixtureName: current.fixtureName, + reason: 'missing in comparison report', + }); + continue; + } + + const currentSnapshot = stableFixtureSnapshot(current); + const previousSnapshot = stableFixtureSnapshot(previous); + if (currentSnapshot !== previousSnapshot) { + differences.push({ + suite: current.suite, + fixtureName: current.fixtureName, + reason: 'snapshot differs', + }); + } + } + + return { + differenceCount: differences.length, + differences, + }; +} + +function stableFixtureSnapshot(report) { + return JSON.stringify({ + match: report.match, + node: report.node, + native: report.native, + }); +} + +function bigIntAbs(value) { + return value < 0n ? -value : value; +} + +function summarizeGasTraceDeltas(fixtureReports) { + const byCounter = new Map(); + const residualByFixture = []; + const allocationByFixture = []; + const residualHistogram = new Map(); + const residualByProfile = new Map(); + let fixturesWithTrace = 0; + + for (const report of fixtureReports) { + if (!report.gasTraceDelta || typeof report.gasTraceDelta !== 'object') { + continue; + } + fixturesWithTrace += 1; + const fixtureKey = `${report.suite}:${report.fixtureName}`; + if (report.residualGasDeltaUsed !== undefined) { + const residualValue = String(report.residualGasDeltaUsed); + residualByFixture.push({ + fixture: fixtureKey, + residualGasDeltaUsed: residualValue, + }); + + const histogramEntry = residualHistogram.get(residualValue) ?? { + residualGasDeltaUsed: residualValue, + count: 0, + fixtures: [], + }; + histogramEntry.count += 1; + if (histogramEntry.fixtures.length < 6) { + histogramEntry.fixtures.push(fixtureKey); + } + residualHistogram.set(residualValue, histogramEntry); + + const profile = String(report.metadata?.executionProfile ?? 'unknown'); + const profileEntry = residualByProfile.get(profile) ?? { + executionProfile: profile, + count: 0, + signedResidual: 0n, + totalAbsResidual: 0n, + maxAbsResidual: 0n, + maxAbsFixture: null, + }; + const residualBigInt = BigInt(residualValue); + profileEntry.count += 1; + profileEntry.signedResidual += residualBigInt; + profileEntry.totalAbsResidual += bigIntAbs(residualBigInt); + if (bigIntAbs(residualBigInt) > profileEntry.maxAbsResidual) { + profileEntry.maxAbsResidual = bigIntAbs(residualBigInt); + profileEntry.maxAbsFixture = fixtureKey; + } + residualByProfile.set(profile, profileEntry); + } + if (report.allocationGasDeltaUsed !== undefined) { + allocationByFixture.push({ + fixture: fixtureKey, + allocationGasDeltaUsed: String(report.allocationGasDeltaUsed), + }); + } + for (const [counter, rawDelta] of Object.entries(report.gasTraceDelta)) { + const delta = BigInt(String(rawDelta)); + const current = byCounter.get(counter) ?? { + counter, + signedDelta: 0n, + totalAbsDelta: 0n, + maxAbsDelta: 0n, + maxAbsFixture: null, + }; + current.signedDelta += delta; + current.totalAbsDelta += bigIntAbs(delta); + if (bigIntAbs(delta) > current.maxAbsDelta) { + current.maxAbsDelta = bigIntAbs(delta); + current.maxAbsFixture = fixtureKey; + } + byCounter.set(counter, current); + } + } + + if (fixturesWithTrace === 0) { + return null; + } + + const counters = [...byCounter.values()] + .sort((left, right) => { + if (left.totalAbsDelta === right.totalAbsDelta) { + return left.counter.localeCompare(right.counter); + } + return left.totalAbsDelta > right.totalAbsDelta ? -1 : 1; + }) + .map((entry) => ({ + counter: entry.counter, + signedDelta: entry.signedDelta.toString(), + totalAbsDelta: entry.totalAbsDelta.toString(), + maxAbsDelta: entry.maxAbsDelta.toString(), + maxAbsFixture: entry.maxAbsFixture, + })); + + const topResiduals = residualByFixture + .map((entry) => ({ + fixture: entry.fixture, + residualGasDeltaUsed: entry.residualGasDeltaUsed, + absResidualGasDeltaUsed: bigIntAbs( + BigInt(entry.residualGasDeltaUsed), + ).toString(), + })) + .sort((left, right) => { + const leftAbs = BigInt(left.absResidualGasDeltaUsed); + const rightAbs = BigInt(right.absResidualGasDeltaUsed); + if (leftAbs === rightAbs) { + return left.fixture.localeCompare(right.fixture); + } + return leftAbs > rightAbs ? -1 : 1; + }) + .slice(0, 10); + + const topAllocationGasDeltas = allocationByFixture + .map((entry) => ({ + fixture: entry.fixture, + allocationGasDeltaUsed: entry.allocationGasDeltaUsed, + absAllocationGasDeltaUsed: bigIntAbs( + BigInt(entry.allocationGasDeltaUsed), + ).toString(), + })) + .sort((left, right) => { + const leftAbs = BigInt(left.absAllocationGasDeltaUsed); + const rightAbs = BigInt(right.absAllocationGasDeltaUsed); + if (leftAbs === rightAbs) { + return left.fixture.localeCompare(right.fixture); + } + return leftAbs > rightAbs ? -1 : 1; + }) + .slice(0, 10); + + const residualSignatures = [...residualHistogram.values()] + .sort((left, right) => { + if (left.count === right.count) { + const leftResidual = BigInt(left.residualGasDeltaUsed); + const rightResidual = BigInt(right.residualGasDeltaUsed); + if (leftResidual === rightResidual) { + return 0; + } + return rightResidual > leftResidual ? 1 : -1; + } + return right.count - left.count; + }) + .map((entry) => ({ + residualGasDeltaUsed: entry.residualGasDeltaUsed, + count: entry.count, + fixtures: entry.fixtures, + })); + + const residualProfiles = [...residualByProfile.values()] + .sort((left, right) => { + if (left.totalAbsResidual === right.totalAbsResidual) { + return left.executionProfile.localeCompare(right.executionProfile); + } + return left.totalAbsResidual > right.totalAbsResidual ? -1 : 1; + }) + .map((entry) => ({ + executionProfile: entry.executionProfile, + count: entry.count, + signedResidual: entry.signedResidual.toString(), + totalAbsResidual: entry.totalAbsResidual.toString(), + maxAbsResidual: entry.maxAbsResidual.toString(), + maxAbsFixture: entry.maxAbsFixture, + })); + + return { + fixturesWithTrace, + counterCount: counters.length, + counters, + topAllocationGasDeltas, + topResiduals, + residualSignatures, + residualProfiles, + }; +} + +function buildGasDeltaBaseline(report) { + const entries = report.fixtureReports + .map((fixtureReport) => ({ + suite: fixtureReport.suite, + fixtureName: fixtureReport.fixtureName, + gasDeltaUsed: fixtureReport.gasDeltaUsed, + gasDeltaRemaining: fixtureReport.gasDeltaRemaining, + })) + .sort((left, right) => { + const leftKey = `${left.suite}:${left.fixtureName}`; + const rightKey = `${right.suite}:${right.fixtureName}`; + return leftKey.localeCompare(rightKey); + }); + + return { + version: 1, + entries, + }; +} + +async function loadGasDeltaBaselineMap(baselinePath) { + const baselineText = await readFile(path.resolve(baselinePath), 'utf8'); + const baseline = JSON.parse(baselineText); + const baselineEntries = Array.isArray(baseline.entries) + ? baseline.entries + : []; + const lookup = new Map(); + for (const entry of baselineEntries) { + lookup.set(`${entry.suite}:${entry.fixtureName}`, { + gasDeltaUsed: String(entry.gasDeltaUsed), + gasDeltaRemaining: String(entry.gasDeltaRemaining), + }); + } + return lookup; +} + +async function compareGasDeltaBaseline(currentReport, baselinePath) { + const baselineText = await readFile(path.resolve(baselinePath), 'utf8'); + const baseline = JSON.parse(baselineText); + const baselineEntries = Array.isArray(baseline.entries) + ? baseline.entries + : []; + + const baselineByFixture = new Map(); + for (const entry of baselineEntries) { + baselineByFixture.set(`${entry.suite}:${entry.fixtureName}`, entry); + } + + const differences = []; + for (const fixtureReport of currentReport.fixtureReports) { + const key = `${fixtureReport.suite}:${fixtureReport.fixtureName}`; + const expected = baselineByFixture.get(key); + if (!expected) { + differences.push({ + suite: fixtureReport.suite, + fixtureName: fixtureReport.fixtureName, + reason: 'missing fixture in gas delta baseline', + }); + continue; + } + if ( + String(expected.gasDeltaUsed) !== String(fixtureReport.gasDeltaUsed) || + String(expected.gasDeltaRemaining) !== + String(fixtureReport.gasDeltaRemaining) + ) { + differences.push({ + suite: fixtureReport.suite, + fixtureName: fixtureReport.fixtureName, + reason: 'gas delta mismatch', + expected: { + gasDeltaUsed: String(expected.gasDeltaUsed), + gasDeltaRemaining: String(expected.gasDeltaRemaining), + }, + actual: { + gasDeltaUsed: String(fixtureReport.gasDeltaUsed), + gasDeltaRemaining: String(fixtureReport.gasDeltaRemaining), + }, + }); + } + } + + return { + differenceCount: differences.length, + differences, + }; +} + +await main(); diff --git a/tools/quickjs-native-harness/scripts/test.sh b/tools/quickjs-native-harness/scripts/test.sh index 0b61b1f..0226023 100755 --- a/tools/quickjs-native-harness/scripts/test.sh +++ b/tools/quickjs-native-harness/scripts/test.sh @@ -14,7 +14,6 @@ fi HOST_MANIFEST_HEX="$(tr -d '\r\n' < "${REPO_ROOT}/libs/test-harness/fixtures/abi-manifest/host-v1.bytes.hex")" HOST_MANIFEST_HASH="$(tr -d '\r\n' < "${REPO_ROOT}/libs/test-harness/fixtures/abi-manifest/host-v1.hash")" COMMON_ARGS=(--abi-manifest-hex "${HOST_MANIFEST_HEX}" --abi-manifest-hash "${HOST_MANIFEST_HASH}") -BAD_MANIFEST_HASH="0000000000000000000000000000000000000000000000000000000000000000" SHA_EMPTY="e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" SHA_ABC="ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" SHA_LONG="248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1" @@ -26,35 +25,33 @@ HOST_UNITS_FLOAT_HEX="a2626f6b0165756e697473fb3ff8000000000000" HOST_ERR_CODE_NUMBER_HEX="a263657272a164636f6465187b65756e69747300" HOST_UNITS_ZERO_HEX="a2626f6b0065756e69747300" HOST_UNITS_ONE_HEX="a2626f6b0065756e69747301" -CONTEXT_BLOB_HEX="a5656576656e74a163666f6f01657374657073826273316273326e6576656e7443616e6f6e6963616ca163626172f56f63757272656e74436f6e7472616374a16269646a636f6e74726163742d31781863757272656e74436f6e747261637443616e6f6e6963616ca1626964a16576616c75656a636f6e74726163742d31" -assert_output() { +assert_host_call() { local name="$1" - local code="$2" - local expected="$3" - shift 3 + local expected="$2" + shift 2 local output - output="$("${BIN}" "${COMMON_ARGS[@]}" "$@" --eval "${code}" || true)" + output="$("${BIN}" "${COMMON_ARGS[@]}" "$@" || true)" if [[ "${output}" != "${expected}" ]]; then - echo "Harness output mismatch for '${name}'" >&2 + echo "Harness host_call mismatch for '${name}'" >&2 echo " expected: ${expected}" >&2 echo " actual: ${output}" >&2 exit 1 fi } -assert_host_call() { +assert_cli() { local name="$1" local expected="$2" shift 2 local output - output="$("${BIN}" "${COMMON_ARGS[@]}" "$@" || true)" + output="$("${BIN}" "$@" || true)" if [[ "${output}" != "${expected}" ]]; then - echo "Harness host_call mismatch for '${name}'" >&2 + echo "Harness CLI mismatch for '${name}'" >&2 echo " expected: ${expected}" >&2 echo " actual: ${output}" >&2 exit 1 @@ -86,327 +83,11 @@ assert_reject() { fi } -host_descriptor_js="$(cat <<'EOF' -(() => { - const desc = Object.getOwnPropertyDescriptor(globalThis, 'Host'); - const v1 = Host && Host.v1; - return { - configurable: desc ? desc.configurable : null, - enumerable: desc ? desc.enumerable : null, - writable: desc ? desc.writable : null, - hostType: typeof Host, - v1Type: typeof v1, - v1NullProto: v1 ? Object.getPrototypeOf(v1) === null : null - }; -})() -EOF -)" - -capability_snapshot_js="$(cat <<'EOF' -(() => { - const capture = (fn) => { - try { - return { ok: true, value: fn() }; - } catch (e) { - return { ok: false, error: String(e) }; - } - }; - - return { - eval: capture(() => eval('1 + 1')), - Function: capture(() => Function('return 1')()), - RegExp: capture(() => new RegExp('a')), - Proxy: capture(() => new Proxy({}, {})), - Promise: capture(() => Promise.resolve(1)), - MathRandom: capture(() => Math.random()), - Date: capture(() => typeof Date), - setTimeout: capture(() => typeof setTimeout), - ArrayBuffer: capture(() => new ArrayBuffer(4)), - SharedArrayBuffer: capture(() => new SharedArrayBuffer(4)), - DataView: capture(() => new DataView()), - Uint8Array: capture(() => new Uint8Array(4)), - Atomics: capture(() => Atomics()), - WebAssembly: capture(() => WebAssembly()), - consoleLog: capture(() => console.log('x')), - print: capture(() => print('x')), - globalOrder: capture(() => - Object.getOwnPropertyNames(globalThis).filter( - (n) => n === 'Host' || n === 'console' || n === 'print' - ) - ), - hostImmutable: capture(() => { - const before = Host; - Host = 123; - const after = Host; - const original = Host.v1.document.get; - let added = false; - try { - Host.v1.added = 1; - added = Object.prototype.hasOwnProperty.call(Host.v1, 'added'); - } catch (_) { - added = false; - } - let overwrite = null; - try { - let threw = false; - (() => { - 'use strict'; - try { - Host.v1.document.get = () => 'pwn'; - } catch (_) { - threw = true; - } - })(); - const desc = Object.getOwnPropertyDescriptor(Host.v1.document, 'get'); - overwrite = { - same: Host.v1.document.get === original, - threw, - writable: desc ? desc.writable : null, - configurable: desc ? desc.configurable : null - }; - } catch (_) { - overwrite = null; - } - return { - sameRef: before === after, - hasV1: !!after.v1, - added, - desc: Object.getOwnPropertyDescriptor(globalThis, 'Host'), - protoNull: Object.getPrototypeOf(Host) === null, - v1ProtoNull: Object.getPrototypeOf(Host.v1) === null, - hostIsExtensible: Object.isExtensible(Host), - hostV1Extensible: Object.isExtensible(Host.v1), - overwrite - }; - }) - }; -})() -EOF -)" - -ergonomic_globals_js="$(cat <<'EOF' -(() => { - const docDesc = Object.getOwnPropertyDescriptor(globalThis, 'document'); - const canonicalDesc = Object.getOwnPropertyDescriptor(document, 'canonical'); - return { - document: { - value: document('foo'), - canonical: document.canonical('bar'), - desc: docDesc - ? { - writable: docDesc.writable, - enumerable: docDesc.enumerable, - configurable: docDesc.configurable - } - : null, - canonicalDesc: canonicalDesc - ? { - writable: canonicalDesc.writable, - enumerable: canonicalDesc.enumerable, - configurable: canonicalDesc.configurable - } - : null, - extensible: Object.isExtensible(document) - }, - context: { - event, - eventCanonical, - steps, - currentContract, - currentContractCanonical, - frozen: { - event: Object.isFrozen(event), - eventCanonical: Object.isFrozen(eventCanonical), - steps: Object.isFrozen(steps), - currentContract: Object.isFrozen(currentContract), - currentContractCanonical: Object.isFrozen(currentContractCanonical) - } - } - }; -})() -EOF -)" - -canon_helpers_js="$(cat <<'EOF' -(() => { - const value = canon.unwrap({ - b: 2, - a: { z: 9 }, - list: [{ name: 'zero' }, { name: 'one' }], - 'a/b': 7, - 'til~de': 5 - }); - return { - keys: Object.keys(value), - rootNested: canon.at(value, "").a.z, - nested: canon.at(value, "/a/z"), - listName: canon.at(value, "/list/1/name"), - escapedSlash: canon.at(value, "/a~1b"), - escapedTilde: canon.at(value, "/til~0de"), - missing: canon.at(value, "/missing") ?? null, - badPointer: (() => { - try { - canon.at(value, "oops"); - return "no error"; - } catch (e) { - return String(e); - } - })(), - badFragment: (() => { - try { - canon.at(value, "#/a"); - return "no error"; - } catch (e) { - return String(e); - } - })(), - badEscape: (() => { - try { - canon.at(value, "/~2"); - return "no error"; - } catch (e) { - return String(e); - } - })(), - badArrayPath: (() => { - try { - canon.at(value, ["a"]); - return "no error"; - } catch (e) { - return String(e); - } - })(), - badArrayIndex: (() => { - try { - canon.at(value, "/list/65535"); - return "no error"; - } catch (e) { - return String(e); - } - })(), - badDash: (() => { - try { - canon.at(value, "/list/-"); - return "no error"; - } catch (e) { - return String(e); - } - })(), - frozen: Object.isFrozen(value) - }; -})() -EOF -)" - -canon_unwrap_depth_js="$(cat <<'EOF' -(() => { - const wrappedValue = { value: { foo: { value: 1 } }, extra: 9 }; - const wrappedItems = { items: [{ value: 2 }, { items: [3] }], extra: 8 }; - const root = { wrappedValue, wrappedItems, plain: { a: { value: 4 } } }; - const shallowRoot = canon.unwrap(root, false); - const deepRoot = canon.unwrap(root, true); - const deepDefault = canon.unwrap(root); - const shallowValue = canon.unwrap(wrappedValue, false); - const deepValue = canon.unwrap(wrappedValue, true); - const shallowItems = canon.unwrap(wrappedItems, false); - const badType = (() => { - try { - canon.unwrap(root, "nope"); - return "no error"; - } catch (e) { - return String(e); - } - })(); - const badNumber = (() => { - try { - canon.unwrap(root, 0); - return "no error"; - } catch (e) { - return String(e); - } - })(); - return { - shallowRootFrozen: Object.isFrozen(shallowRoot), - shallowRootValueWrapper: Object.prototype.hasOwnProperty.call(shallowRoot.wrappedValue, "value"), - shallowRootItemsWrapper: Object.prototype.hasOwnProperty.call(shallowRoot.wrappedItems, "items"), - shallowRootValueNested: shallowRoot.wrappedValue.value.foo.value, - shallowRootItemsNested: shallowRoot.wrappedItems.items[0].value, - shallowValueFooIsWrapper: Object.prototype.hasOwnProperty.call(shallowValue.foo, "value"), - shallowItemsSecondHasItems: Object.prototype.hasOwnProperty.call(shallowItems[1], "items"), - deepRootValueFoo: deepRoot.wrappedValue.foo, - deepRootValueHasValueProp: Object.prototype.hasOwnProperty.call(deepRoot.wrappedValue, "value"), - deepRootItemsFirst: deepRoot.wrappedItems[0], - deepRootItemsSecond: deepRoot.wrappedItems[1][0], - deepRootPlainA: deepRoot.plain.a, - deepRootFrozen: Object.isFrozen(deepRoot), - deepRootItemsFrozen: Object.isFrozen(deepRoot.wrappedItems), - deepRootItemsNestedFrozen: Object.isFrozen(deepRoot.wrappedItems[1]), - deepDefaultValueFoo: deepDefault.wrappedValue.foo, - deepDefaultItemsSecond: deepDefault.wrappedItems[1][0], - deepDefaultPlainA: deepDefault.plain.a, - deepValueFoo: deepValue.foo, - badType, - badNumber - }; -})() -EOF -)" - -assert_output "basic addition" "1 + 2" "RESULT 3" -assert_output "manifest hash mismatch" "1 + 1" "ERROR ManifestError: abi manifest hash mismatch" --abi-manifest-hash "${BAD_MANIFEST_HASH}" +assert_cli "eval smoke" "RESULT 3" "${COMMON_ARGS[@]}" --eval "1 + 2" assert_sha "sha256 empty" "" "SHA256 ${SHA_EMPTY}" assert_sha "sha256 abc" "616263" "SHA256 ${SHA_ABC}" assert_sha "sha256 long" "6162636462636465636465666465666765666768666768696768696a68696a6b696a6b6c6a6b6c6d6b6c6d6e6c6d6e6f6d6e6f706e6f7071" "SHA256 ${SHA_LONG}" assert_reject "dv-decode with sha256" --dv-decode "a0" --sha256-hex "${SHA_EMPTY}" -assert_output "eval disabled" "eval('1 + 1')" "ERROR TypeError: eval is disabled in deterministic mode" -assert_output "Function disabled" "(new Function('return 7'))()" "ERROR TypeError: Function is disabled in deterministic mode" -assert_output "Function ctor via Function.prototype.constructor" "(() => { const RealFunction = (function () {}).constructor; return RealFunction('return 3')(); })()" "ERROR TypeError: Function constructor is disabled in deterministic mode" -assert_output "Function ctor via arrow constructor" "(() => { const RealFunction = (() => {}).constructor; return RealFunction('return 4')(); })()" "ERROR TypeError: Function constructor is disabled in deterministic mode" -assert_output "Function ctor via generator constructor" "(() => { const GenFunction = (function* () {}).constructor; return GenFunction('return 5')(); })()" "ERROR TypeError: Function constructor is disabled in deterministic mode" -assert_output "RegExp constructor disabled" "new RegExp('a')" "ERROR TypeError: RegExp is disabled in deterministic mode" -assert_output "RegExp literal disabled" "'abc'.match(/a/)" "ERROR TypeError: RegExp is disabled in deterministic mode" -assert_output "Proxy disabled" "new Proxy({}, {})" "ERROR TypeError: Proxy is disabled in deterministic mode" -assert_output "Math.random disabled" "Math.random()" "ERROR TypeError: Math.random is disabled in deterministic mode" -assert_output "ArrayBuffer disabled" "new ArrayBuffer(4)" "ERROR TypeError: ArrayBuffer is disabled in deterministic mode" -assert_output "SharedArrayBuffer disabled" "new SharedArrayBuffer(4)" "ERROR TypeError: SharedArrayBuffer is disabled in deterministic mode" -assert_output "DataView disabled" "new DataView()" "ERROR TypeError: DataView is disabled in deterministic mode" -assert_output "Typed arrays disabled" "new Uint8Array(4)" "ERROR TypeError: Typed arrays are disabled in deterministic mode" -assert_output "Atomics disabled" "Atomics()" "ERROR TypeError: Atomics is disabled in deterministic mode" -assert_output "WebAssembly disabled" "WebAssembly()" "ERROR TypeError: WebAssembly is disabled in deterministic mode" -assert_output "console disabled" "console.log('x')" "ERROR TypeError: console is disabled in deterministic mode" -assert_output "print disabled" "print('x')" "ERROR TypeError: print is disabled in deterministic mode" -assert_output "JSON.parse success" "JSON.parse('{\"aa\":1,\"b\":2}')" "RESULT {\"aa\":1,\"b\":2}" -assert_output "JSON.parse syntax error" "JSON.parse('[')" "ERROR SyntaxError: Unexpected end of JSON input" -assert_output "JSON.parse reviver unsupported" "JSON.parse('[]', () => 1)" "ERROR TypeError: JSON.parse reviver is not supported in deterministic mode" -assert_output "JSON.parse invalid string" "JSON.parse('\"\\ud800\"')" "ERROR TypeError: JSON.parse string contains lone surrogate code points" -assert_output "JSON.parse invalid key" "JSON.parse('{\"\\ud800\":1}')" "ERROR TypeError: JSON.parse key contains lone surrogate code points" -assert_output "JSON.parse deep nesting limit" "JSON.parse('['.repeat(10000) + '0' + ']'.repeat(10000))" "ERROR TypeError: JSON.parse maxDepth 64 exceeded" -assert_output "JSON.stringify canonical key order" "JSON.stringify({ aa: 1, b: 2 })" "RESULT \"{\\\"b\\\":2,\\\"aa\\\":1}\"" -assert_output "JSON.stringify replacer unsupported" "JSON.stringify({ aa: 1, b: 2 }, [])" "ERROR TypeError: JSON.stringify replacer is not supported in deterministic mode" -assert_output "JSON.stringify space unsupported" "JSON.stringify({ aa: 1, b: 2 }, null, 2)" "ERROR TypeError: JSON.stringify space is not supported in deterministic mode" -assert_output "JSON.stringify cycle error" "(() => { const x = {}; x.self = x; return JSON.stringify(x); })()" "ERROR TypeError: JSON.stringify does not support circular references" -assert_output "JSON.stringify accessor unsupported" "JSON.stringify({ get a() { return 1; } })" "ERROR TypeError: JSON.stringify does not support accessor properties" -assert_output "JSON.stringify array accessor unsupported" "(() => { const arr = [1]; Object.defineProperty(arr, 0, { get() { return 1; }, enumerable: true }); return JSON.stringify(arr); })()" "ERROR TypeError: JSON.stringify does not support accessor properties" -assert_output "JSON.stringify invalid string" "JSON.stringify('\\ud800')" "ERROR TypeError: JSON.stringify string contains lone surrogate code points" -assert_output "JSON.stringify invalid key" "(() => { const key = '\\ud800'; return JSON.stringify({ [key]: 1 }); })()" "ERROR TypeError: JSON.stringify key contains lone surrogate code points" -assert_output "JSON.stringify unsupported type" "JSON.stringify({ x: undefined })" "ERROR TypeError: JSON.stringify only supports null, booleans, strings, finite numbers, arrays, and plain objects" -assert_output "JSON.stringify sparse array ignores prototype getters" "(() => { let getterCalls = 0; Object.defineProperty(Array.prototype, 0, { get() { getterCalls += 1; return 1; }, configurable: true }); try { return [JSON.stringify([,]), getterCalls]; } finally { delete Array.prototype[0]; } })()" "RESULT [\"[null]\",0]" -assert_output "Array.sort disabled" "[3, 1, 2].sort()" "ERROR TypeError: Array.prototype.sort is disabled in deterministic mode" -assert_output "Date missing" "typeof Date" "RESULT \"undefined\"" -assert_output "Timers missing" "typeof setTimeout" "RESULT \"undefined\"" -assert_output "Promise disabled" "Promise.resolve(1)" "ERROR TypeError: Promise is disabled in deterministic mode" -assert_output "queueMicrotask missing" "typeof queueMicrotask" "RESULT \"undefined\"" -assert_output "Host descriptor" "${host_descriptor_js}" "RESULT {\"configurable\":false,\"enumerable\":false,\"writable\":false,\"hostType\":\"object\",\"v1Type\":\"object\",\"v1NullProto\":true}" -assert_output "capability snapshot" "${capability_snapshot_js}" "RESULT {\"eval\":{\"ok\":false,\"error\":\"TypeError: eval is disabled in deterministic mode\"},\"Function\":{\"ok\":false,\"error\":\"TypeError: Function is disabled in deterministic mode\"},\"RegExp\":{\"ok\":false,\"error\":\"TypeError: RegExp is disabled in deterministic mode\"},\"Proxy\":{\"ok\":false,\"error\":\"TypeError: Proxy is disabled in deterministic mode\"},\"Promise\":{\"ok\":false,\"error\":\"TypeError: Promise is disabled in deterministic mode\"},\"MathRandom\":{\"ok\":false,\"error\":\"TypeError: Math.random is disabled in deterministic mode\"},\"Date\":{\"ok\":true,\"value\":\"undefined\"},\"setTimeout\":{\"ok\":true,\"value\":\"undefined\"},\"ArrayBuffer\":{\"ok\":false,\"error\":\"TypeError: ArrayBuffer is disabled in deterministic mode\"},\"SharedArrayBuffer\":{\"ok\":false,\"error\":\"TypeError: SharedArrayBuffer is disabled in deterministic mode\"},\"DataView\":{\"ok\":false,\"error\":\"TypeError: DataView is disabled in deterministic mode\"},\"Uint8Array\":{\"ok\":false,\"error\":\"TypeError: Typed arrays are disabled in deterministic mode\"},\"Atomics\":{\"ok\":false,\"error\":\"TypeError: Atomics is disabled in deterministic mode\"},\"WebAssembly\":{\"ok\":false,\"error\":\"TypeError: WebAssembly is disabled in deterministic mode\"},\"consoleLog\":{\"ok\":false,\"error\":\"TypeError: console is disabled in deterministic mode\"},\"print\":{\"ok\":false,\"error\":\"TypeError: print is disabled in deterministic mode\"},\"globalOrder\":{\"ok\":true,\"value\":[\"console\",\"print\",\"Host\"]},\"hostImmutable\":{\"ok\":true,\"value\":{\"sameRef\":true,\"hasV1\":true,\"added\":false,\"desc\":{\"value\":{},\"writable\":false,\"enumerable\":false,\"configurable\":false},\"protoNull\":true,\"v1ProtoNull\":true,\"hostIsExtensible\":false,\"hostV1Extensible\":false,\"overwrite\":{\"same\":true,\"threw\":true,\"writable\":false,\"configurable\":false}}}}" -assert_output "ergonomic globals" "${ergonomic_globals_js}" "RESULT {\"document\":{\"value\":\"foo\",\"canonical\":\"bar\",\"desc\":{\"writable\":false,\"enumerable\":false,\"configurable\":false},\"canonicalDesc\":{\"writable\":false,\"enumerable\":false,\"configurable\":false},\"extensible\":false},\"context\":{\"event\":{\"foo\":1},\"eventCanonical\":{\"bar\":true},\"steps\":[\"s1\",\"s2\"],\"currentContract\":{\"id\":\"contract-1\"},\"currentContractCanonical\":{\"id\":{\"value\":\"contract-1\"}},\"frozen\":{\"event\":true,\"eventCanonical\":true,\"steps\":true,\"currentContract\":true,\"currentContractCanonical\":true}}}" --context-blob-hex "${CONTEXT_BLOB_HEX}" -assert_output "Host.v1 document.get ok" "Host.v1.document.get('foo')" "RESULT \"foo\"" -assert_output "Host.v1 document.getCanonical ok" "Host.v1.document.getCanonical('bar')" "RESULT \"bar\"" -assert_output "Host.v1 emit" "Host.v1.emit({ a: 1 })" "RESULT null" -assert_output "Host.v1 document missing" "Host.v1.document.get('missing')" "ERROR HostError: host/not_found" -assert_output "Host.v1 document arg type" "Host.v1.document.get(123)" "ERROR TypeError: Host.v1.document.get argument 1 must be a string" -assert_output "Host.v1 document arg utf8 limit" "Host.v1.document.get('x'.repeat(2050))" "ERROR TypeError: Host.v1.document.get argument 1 exceeds utf8 limit (2050 > 2048)" -assert_output "canon helpers" "${canon_helpers_js}" "RESULT {\"keys\":[\"a\",\"b\",\"a/b\",\"list\",\"til~de\"],\"rootNested\":9,\"nested\":9,\"listName\":\"one\",\"escapedSlash\":7,\"escapedTilde\":5,\"missing\":null,\"badPointer\":\"TypeError: canon.at path must be a JSON Pointer string\",\"badFragment\":\"TypeError: canon.at JSON Pointer fragment form is not supported\",\"badEscape\":\"TypeError: canon.at JSON Pointer contains invalid escape sequence\",\"badArrayPath\":\"TypeError: canon.at path must be a JSON Pointer string (array paths are no longer supported)\",\"badArrayIndex\":\"TypeError: canon.at path index is out of range\",\"badDash\":\"TypeError: canon.at path index '-' is not allowed\",\"frozen\":true}" --context-blob-hex "${CONTEXT_BLOB_HEX}" -assert_output "canon unwrap depth" "${canon_unwrap_depth_js}" "RESULT {\"shallowRootFrozen\":true,\"shallowRootValueWrapper\":true,\"shallowRootItemsWrapper\":true,\"shallowRootValueNested\":1,\"shallowRootItemsNested\":2,\"shallowValueFooIsWrapper\":true,\"shallowItemsSecondHasItems\":true,\"deepRootValueFoo\":1,\"deepRootValueHasValueProp\":false,\"deepRootItemsFirst\":2,\"deepRootItemsSecond\":3,\"deepRootPlainA\":4,\"deepRootFrozen\":true,\"deepRootItemsFrozen\":true,\"deepRootItemsNestedFrozen\":true,\"deepDefaultValueFoo\":1,\"deepDefaultItemsSecond\":3,\"deepDefaultPlainA\":4,\"deepValueFoo\":1,\"badType\":\"TypeError: canon.unwrap deep must be a boolean\",\"badNumber\":\"TypeError: canon.unwrap deep must be a boolean\"}" --context-blob-hex "${CONTEXT_BLOB_HEX}" assert_host_call "host_call echo" "HOSTCALL 0a0b0c GAS remaining=100 used=0" --host-call "0a0b0c" --gas-limit 100 --report-gas assert_host_call "host_call request limit" "ERROR TypeError: host_call request exceeds max_request_bytes" --host-call "010203" --host-max-request 2 assert_host_call "host_call response limit" "ERROR HostError: host/transport" --host-call "0a0b0c" --host-max-request 3 --host-max-response 2 @@ -421,11 +102,12 @@ assert_host_call "host_call max_units zero allowed" "HOSTRESP 0 UNITS 0" --host- assert_host_call "host_call units above max_units zero" "ERROR HostError: host/envelope_invalid" --host-call "${HOST_UNITS_ONE_HEX}" --host-parse-envelope --host-max-units 0 assert_host_call "host_call ok envelope" "HOSTRESP {\"value\":\"hello\"} UNITS 5" --host-call "${HOST_OK_ENVELOPE_HEX}" --host-parse-envelope --host-max-units 10 -echo "Running gas golden suite" -node "${SCRIPT_DIR}/gas-goldens.mjs" -echo "Running host gas suite" -node "${SCRIPT_DIR}/host-gas.mjs" -echo "Running DV parity suite" -node "${SCRIPT_DIR}/dv-parity.mjs" +if [[ "${NATIVE_PARITY_STRICT:-0}" == "1" ]]; then + echo "Running cross-runtime strict parity report suite" + node "${SCRIPT_DIR}/parity-report.mjs" --assert-match +else + echo "Running cross-runtime diagnostic parity report suite" + node "${SCRIPT_DIR}/parity-report.mjs" +fi echo "quickjs-native-harness test passed" diff --git a/tools/quickjs-native-harness/src/harness.c b/tools/quickjs-native-harness/src/harness.c index 053cefa..2cb895c 100644 --- a/tools/quickjs-native-harness/src/harness.c +++ b/tools/quickjs-native-harness/src/harness.c @@ -3,6 +3,7 @@ #include "quickjs-internal.h" #include #include +#include #include #include #include @@ -16,6 +17,7 @@ typedef struct { HostStubMode mode; int trigger_reentrancy; int trigger_exception; + int use_dv2_codec; } HostStubConfig; typedef struct { @@ -27,11 +29,19 @@ typedef struct { typedef struct { const char *code; + const char *module_pack_json; + const char *module_pack_file; + const char *module_entry_specifier; + const char *module_entry_export; uint64_t gas_limit; int report_gas; int report_trace; + int report_tape; + int report_charge_tape; + uint32_t charge_tape_capacity; const char *dump_global; int dv_encode; + int parity_eval; const char *dv_decode_hex; const char *abi_manifest_hex; const char *abi_manifest_file; @@ -47,6 +57,7 @@ typedef struct { int host_call_parse_envelope; uint32_t host_call_max_units; int host_call_max_units_provided; + const char *execution_profile; } HarnessOptions; typedef struct { @@ -60,9 +71,41 @@ typedef struct { size_t count; } HostErrorTable; +typedef struct { + char *specifier; + char *source; + size_t source_len; +} ModulePackEntry; + +typedef struct { + ModulePackEntry *entries; + uint32_t entry_count; +} ModulePack; + static int print_exception(JSContext *ctx, const HarnessOptions *options); static void free_runtime(HarnessRuntime *runtime); static int run_sha256(const HarnessOptions *options); +static int eval_module_pack(HarnessRuntime *runtime, const HarnessOptions *options); + +static uint32_t deterministic_feature_flags_for_profile(const char *profile) { + if (!profile || strcmp(profile, "baseline-v1") == 0) { + return 0; + } + if (strcmp(profile, "compat-general-v1") == 0) { + return JS_DETERMINISTIC_FEATURE_REGEXP | + JS_DETERMINISTIC_FEATURE_PROMISE_JOBS | + JS_DETERMINISTIC_FEATURE_CONSOLE_SHIM | + JS_DETERMINISTIC_FEATURE_STABLE_SORT; + } + if (strcmp(profile, "compat-binary-v1") == 0) { + return JS_DETERMINISTIC_FEATURE_REGEXP | + JS_DETERMINISTIC_FEATURE_PROMISE_JOBS | + JS_DETERMINISTIC_FEATURE_CONSOLE_SHIM | + JS_DETERMINISTIC_FEATURE_STABLE_SORT | + JS_DETERMINISTIC_FEATURE_TYPED_ARRAYS; + } + return UINT32_MAX; +} static int hex_value(char c) { if (c >= '0' && c <= '9') { @@ -137,6 +180,282 @@ static int parse_hex_string(const char *hex, uint8_t **out, size_t *out_len) { return 0; } +static int manifest_uses_host_v2(const uint8_t *bytes, size_t len) { + static const uint8_t needle[] = {'H', 'o', 's', 't', '.', 'v', '2'}; + if (!bytes || len < sizeof(needle)) { + return 0; + } + for (size_t i = 0; i + sizeof(needle) <= len; i++) { + if (memcmp(bytes + i, needle, sizeof(needle)) == 0) { + return 1; + } + } + return 0; +} + +static char *copy_cstring_len(const char *value, size_t length) { + char *out = malloc(length + 1); + if (!out) { + return NULL; + } + memcpy(out, value, length); + out[length] = '\0'; + return out; +} + +static char *hex_bytes(const uint8_t *bytes, size_t length) { + static const char *HEX = "0123456789abcdef"; + char *out; + + if (length > 0 && !bytes) { + return NULL; + } + + out = malloc((length * 2) + 1); + if (!out) { + return NULL; + } + + for (size_t i = 0; i < length; i++) { + out[i * 2] = HEX[(bytes[i] >> 4) & 0x0f]; + out[i * 2 + 1] = HEX[bytes[i] & 0x0f]; + } + out[length * 2] = '\0'; + return out; +} + +static int js_set_prop(JSContext *ctx, JSValue obj, const char *name, JSValue val) { + if (JS_IsException(val)) { + return -1; + } + if (JS_DefinePropertyValueStr(ctx, obj, name, val, JS_PROP_C_W_E) < 0) { + JS_FreeValue(ctx, val); + return -1; + } + return 0; +} + +static void free_module_pack(ModulePack *pack) { + if (!pack) { + return; + } + + if (pack->entries) { + for (uint32_t i = 0; i < pack->entry_count; i++) { + free(pack->entries[i].specifier); + free(pack->entries[i].source); + } + free(pack->entries); + } + pack->entries = NULL; + pack->entry_count = 0; +} + +static ModulePackEntry *find_module_pack_entry(ModulePack *pack, const char *specifier) { + if (!pack || !specifier) { + return NULL; + } + + for (uint32_t i = 0; i < pack->entry_count; i++) { + if (strcmp(pack->entries[i].specifier, specifier) == 0) { + return &pack->entries[i]; + } + } + return NULL; +} + +static int parse_module_pack_json(JSContext *ctx, const char *module_pack_json, ModulePack *out_pack) { + JSValue parsed = JS_UNDEFINED; + JSValue length_value = JS_UNDEFINED; + uint32_t module_count = 0; + + memset(out_pack, 0, sizeof(*out_pack)); + + parsed = JS_ParseJSON(ctx, module_pack_json, strlen(module_pack_json), ""); + if (JS_IsException(parsed)) { + goto fail; + } + + if (!JS_IsArray(ctx, parsed)) { + JS_ThrowTypeError(ctx, "module pack json must be an array"); + goto fail; + } + + length_value = JS_GetPropertyStr(ctx, parsed, "length"); + if (JS_IsException(length_value)) { + goto fail; + } + + if (JS_ToUint32(ctx, &module_count, length_value) != 0) { + goto fail; + } + JS_FreeValue(ctx, length_value); + length_value = JS_UNDEFINED; + + if (module_count == 0) { + JS_ThrowTypeError(ctx, "module pack must contain at least one module"); + goto fail; + } + + out_pack->entries = calloc(module_count, sizeof(*out_pack->entries)); + if (!out_pack->entries) { + JS_ThrowOutOfMemory(ctx); + goto fail; + } + out_pack->entry_count = module_count; + + for (uint32_t i = 0; i < module_count; i++) { + JSValue item = JS_GetPropertyUint32(ctx, parsed, i); + JSValue specifier_value = JS_UNDEFINED; + JSValue source_value = JS_UNDEFINED; + const char *specifier_cstr = NULL; + const char *source_cstr = NULL; + size_t source_len = 0; + + if (JS_IsException(item)) { + goto fail; + } + if (!JS_IsObject(item)) { + JS_FreeValue(ctx, item); + JS_ThrowTypeError(ctx, "module pack entry must be an object"); + goto fail; + } + + specifier_value = JS_GetPropertyStr(ctx, item, "specifier"); + source_value = JS_GetPropertyStr(ctx, item, "source"); + if (JS_IsException(specifier_value) || JS_IsException(source_value)) { + JS_FreeValue(ctx, specifier_value); + JS_FreeValue(ctx, source_value); + JS_FreeValue(ctx, item); + goto fail; + } + + specifier_cstr = JS_ToCString(ctx, specifier_value); + source_cstr = JS_ToCStringLen(ctx, &source_len, source_value); + if (!specifier_cstr || !source_cstr) { + JS_FreeCString(ctx, specifier_cstr); + JS_FreeCString(ctx, source_cstr); + JS_FreeValue(ctx, specifier_value); + JS_FreeValue(ctx, source_value); + JS_FreeValue(ctx, item); + goto fail; + } + + out_pack->entries[i].specifier = copy_cstring_len(specifier_cstr, strlen(specifier_cstr)); + out_pack->entries[i].source = copy_cstring_len(source_cstr, source_len); + out_pack->entries[i].source_len = source_len; + + JS_FreeCString(ctx, specifier_cstr); + JS_FreeCString(ctx, source_cstr); + JS_FreeValue(ctx, specifier_value); + JS_FreeValue(ctx, source_value); + JS_FreeValue(ctx, item); + + if (!out_pack->entries[i].specifier || !out_pack->entries[i].source) { + JS_ThrowOutOfMemory(ctx); + goto fail; + } + } + + JS_FreeValue(ctx, parsed); + return 0; + +fail: + if (!JS_IsUndefined(length_value)) { + JS_FreeValue(ctx, length_value); + } + if (!JS_IsUndefined(parsed)) { + JS_FreeValue(ctx, parsed); + } + free_module_pack(out_pack); + return -1; +} + +static JSModuleDef *module_pack_loader(JSContext *ctx, + const char *module_name, + void *opaque, + JSValueConst attributes) { + ModulePack *pack = (ModulePack *)opaque; + ModulePackEntry *entry = find_module_pack_entry(pack, module_name); + JSValue module_obj = JS_UNDEFINED; + + (void)attributes; + + if (!entry) { + JS_ThrowReferenceError(ctx, "ModuleResolutionError: module specifier not found: %s", module_name); + return NULL; + } + + module_obj = JS_Eval(ctx, + entry->source, + entry->source_len, + entry->specifier, + JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY); + if (JS_IsException(module_obj)) { + return NULL; + } + + JSModuleDef *module_def = (JSModuleDef *)JS_VALUE_GET_PTR(module_obj); + JS_FreeValue(ctx, module_obj); + return module_def; +} + +static char *escape_js_string(const char *input) { + size_t needed = 2; + for (const unsigned char *p = (const unsigned char *)input; *p; p++) { + switch (*p) { + case '\\': + case '"': + case '\n': + case '\r': + case '\t': + needed += 2; + break; + default: + needed += 1; + break; + } + } + + char *out = malloc(needed + 1); + if (!out) { + return NULL; + } + + char *cursor = out; + *cursor++ = '"'; + for (const unsigned char *p = (const unsigned char *)input; *p; p++) { + switch (*p) { + case '\\': + *cursor++ = '\\'; + *cursor++ = '\\'; + break; + case '"': + *cursor++ = '\\'; + *cursor++ = '"'; + break; + case '\n': + *cursor++ = '\\'; + *cursor++ = 'n'; + break; + case '\r': + *cursor++ = '\\'; + *cursor++ = 'r'; + break; + case '\t': + *cursor++ = '\\'; + *cursor++ = 't'; + break; + default: + *cursor++ = (char)*p; + break; + } + } + *cursor++ = '"'; + *cursor = '\0'; + return out; +} + static void free_default_host_errors(JSContext *ctx, HostErrorTable *table) { if (!table) { return; @@ -192,7 +511,8 @@ static uint32_t harness_manifest_host_call(JSContext *ctx, const uint8_t *req_ptr, uint32_t req_len, uint8_t *resp_ptr, - uint32_t resp_capacity) { + uint32_t resp_capacity, + int use_dv2_codec) { JSValue req = JS_UNDEFINED; JSValue arg0 = JS_UNDEFINED; JSValue envelope = JS_UNDEFINED; @@ -203,7 +523,9 @@ static uint32_t harness_manifest_host_call(JSContext *ctx, const char *error_code = NULL; uint32_t resp_len = JS_HOST_CALL_TRANSPORT_ERROR; - req = JS_DecodeDV(ctx, req_ptr, req_len, &JS_DV_LIMIT_DEFAULTS); + req = use_dv2_codec + ? JS_DecodeDV2(ctx, req_ptr, req_len, &JS_DV_LIMIT_DEFAULTS) + : JS_DecodeDV(ctx, req_ptr, req_len, &JS_DV_LIMIT_DEFAULTS); if (JS_IsException(req)) { goto done; } @@ -237,19 +559,29 @@ static uint32_t harness_manifest_host_call(JSContext *ctx, error_code = "LIMIT_EXCEEDED"; units = 3; } - JS_FreeCString(ctx, path); - if (error_code) { + if (!error_code && strcmp(path, "bytes/payload") == 0) { + const uint8_t payload_dv2[] = {0x44, 0xde, 0xad, 0xbe, 0xef}; + ok_val = JS_DecodeDV2(ctx, payload_dv2, sizeof(payload_dv2), &JS_DV_LIMIT_DEFAULTS); + if (JS_IsException(ok_val)) { + JS_FreeCString(ctx, path); + goto done; + } + units = 4; + } else if (error_code) { err_obj = JS_NewObjectProto(ctx, JS_NULL); if (JS_IsException(err_obj)) { + JS_FreeCString(ctx, path); goto done; } if (JS_SetPropertyStr(ctx, err_obj, "code", JS_NewString(ctx, error_code)) < 0) { + JS_FreeCString(ctx, path); goto done; } } else { ok_val = JS_DupValue(ctx, arg0); } + JS_FreeCString(ctx, path); } else if (fn_id == 3) { ok_val = JS_NULL; units = 0; @@ -273,7 +605,8 @@ static uint32_t harness_manifest_host_call(JSContext *ctx, goto done; } - if (JS_EncodeDV(ctx, envelope, &JS_DV_LIMIT_DEFAULTS, &resp) != 0) { + if ((use_dv2_codec ? JS_EncodeDV2(ctx, envelope, &JS_DV_LIMIT_DEFAULTS, &resp) + : JS_EncodeDV(ctx, envelope, &JS_DV_LIMIT_DEFAULTS, &resp)) != 0) { goto done; } @@ -337,7 +670,13 @@ static uint32_t harness_host_call(JSContext *ctx, } if (config && config->mode == HOST_STUB_MODE_MANIFEST) { - return harness_manifest_host_call(ctx, fn_id, req_ptr, req_len, resp_ptr, resp_capacity); + return harness_manifest_host_call(ctx, + fn_id, + req_ptr, + req_len, + resp_ptr, + resp_capacity, + config->use_dv2_codec); } if (req_len > resp_capacity) { @@ -384,6 +723,31 @@ static char *read_file_to_string(const char *path) { return buffer; } +static char *dup_printf(const char *fmt, ...) { + va_list args; + va_start(args, fmt); + int needed = vsnprintf(NULL, 0, fmt, args); + va_end(args); + if (needed < 0) { + return NULL; + } + + char *out = malloc((size_t)needed + 1); + if (!out) { + return NULL; + } + + va_start(args, fmt); + int written = vsnprintf(out, (size_t)needed + 1, fmt, args); + va_end(args); + if (written < 0) { + free(out); + return NULL; + } + + return out; +} + static void print_hex_buffer(const uint8_t *data, size_t len) { for (size_t i = 0; i < len; i++) { fprintf(stdout, "%02x", data[i]); @@ -414,10 +778,16 @@ static int init_runtime(HarnessRuntime *runtime, const HarnessOptions *options) uint8_t *context_blob = NULL; size_t context_blob_len = 0; char *manifest_hex_from_file = NULL; + uint32_t feature_flags = deterministic_feature_flags_for_profile(options->execution_profile); int rc = 0; - if (JS_NewDeterministicRuntime(&runtime->rt, &runtime->ctx) != 0) { - fprintf(stderr, "init: JS_NewDeterministicRuntime failed\n"); + if (feature_flags == UINT32_MAX) { + fprintf(stderr, "Unsupported --execution-profile: %s\n", options->execution_profile); + return 2; + } + + if (JS_NewDeterministicRuntimeWithFeatures(&runtime->rt, &runtime->ctx, feature_flags) != 0) { + fprintf(stderr, "init: JS_NewDeterministicRuntimeWithFeatures failed\n"); return 1; } @@ -475,6 +845,7 @@ static int init_runtime(HarnessRuntime *runtime, const HarnessOptions *options) .context_blob = context_blob, .context_blob_size = context_blob_len, .gas_limit = options->gas_limit, + .feature_flags = feature_flags, }; if (JS_InitDeterministicContext(runtime->ctx, &init_opts) != 0) { @@ -491,6 +862,11 @@ static int init_runtime(HarnessRuntime *runtime, const HarnessOptions *options) options->host_call_hex != NULL ? HOST_STUB_MODE_ECHO : HOST_STUB_MODE_MANIFEST; runtime->host_stub.trigger_reentrancy = options->host_call_reentrant; runtime->host_stub.trigger_exception = options->host_call_exception; + runtime->host_stub.use_dv2_codec = + runtime->host_stub.mode == HOST_STUB_MODE_MANIFEST && + manifest_uses_host_v2(manifest_bytes, manifest_len) + ? 1 + : 0; runtime->host_stub_enabled = 1; if (JS_SetHostCallDispatcher(runtime->rt, harness_host_call, &runtime->host_stub) != 0) { rc = 1; @@ -619,7 +995,9 @@ static void print_trace_suffix(const HarnessOptions *options, const HarnessSnaps "},\"jsonStringify\":{\"count\":%" PRIu64 ",\"gas\":%" PRIu64 ",\"outputBytes\":%" PRIu64 ",\"values\":%" PRIu64 ",\"objectEntries\":%" PRIu64 ",\"arrayElements\":%" PRIu64 - ",\"sortComparisons\":%" PRIu64 "}", + ",\"sortComparisons\":%" PRIu64 + "},\"hostCallPre\":{\"count\":%" PRIu64 ",\"gas\":%" PRIu64 + "},\"hostCallPost\":{\"count\":%" PRIu64 ",\"gas\":%" PRIu64 "}", snapshot->trace.opcode_count, snapshot->trace.opcode_gas, snapshot->trace.builtin_array_cb_base_count, snapshot->trace.builtin_array_cb_base_gas, snapshot->trace.builtin_array_cb_per_element_count, @@ -634,11 +1012,233 @@ static void print_trace_suffix(const HarnessOptions *options, const HarnessSnaps snapshot->trace.json_stringify_value_count, snapshot->trace.json_stringify_object_entry_count, snapshot->trace.json_stringify_array_element_count, - snapshot->trace.json_stringify_sort_comparison_count); + snapshot->trace.json_stringify_sort_comparison_count, + snapshot->trace.host_call_pre_count, + snapshot->trace.host_call_pre_gas, + snapshot->trace.host_call_post_count, + snapshot->trace.host_call_post_gas); fputc('}', stdout); } +static void print_tape_suffix(JSContext *ctx, const HarnessOptions *options) { + if (!options->report_tape) { + return; + } + + JSHostTapeRecord *records = NULL; + size_t count = JS_GetHostTapeLength(ctx); + size_t to_read = 0; + JSValue arr = JS_UNDEFINED; + JSValue json = JS_UNDEFINED; + const char *json_str = NULL; + int wrote = 0; + + if (count == 0) { + fprintf(stdout, " TAPE []"); + return; + } + + to_read = count > JS_HOST_TAPE_MAX_CAPACITY ? JS_HOST_TAPE_MAX_CAPACITY : count; + records = js_mallocz(ctx, sizeof(JSHostTapeRecord) * to_read); + if (!records) { + goto done; + } + + if (JS_ReadHostTape(ctx, records, to_read, &count) != 0) { + goto done; + } + + arr = JS_NewArray(ctx); + if (JS_IsException(arr)) { + goto done; + } + + for (size_t i = 0; i < count; i++) { + JSValue obj = JS_NewObjectProto(ctx, JS_NULL); + char *req_hex = NULL; + char *resp_hex = NULL; + char gas_pre_buf[32]; + char gas_post_buf[32]; + + if (JS_IsException(obj)) { + JS_FreeValue(ctx, obj); + goto done; + } + + if (js_set_prop(ctx, obj, "fnId", JS_NewUint32(ctx, records[i].fn_id)) < 0 || + js_set_prop(ctx, obj, "reqLen", JS_NewUint32(ctx, records[i].req_len)) < 0 || + js_set_prop(ctx, obj, "respLen", JS_NewUint32(ctx, records[i].resp_len)) < 0 || + js_set_prop(ctx, obj, "units", JS_NewUint32(ctx, records[i].units)) < 0) { + JS_FreeValue(ctx, obj); + goto done; + } + + snprintf(gas_pre_buf, sizeof(gas_pre_buf), "%" PRIu64, records[i].gas_pre); + snprintf(gas_post_buf, sizeof(gas_post_buf), "%" PRIu64, records[i].gas_post); + if (js_set_prop(ctx, obj, "gasPre", JS_NewString(ctx, gas_pre_buf)) < 0 || + js_set_prop(ctx, obj, "gasPost", JS_NewString(ctx, gas_post_buf)) < 0 || + js_set_prop(ctx, obj, "isError", JS_NewBool(ctx, records[i].is_error)) < 0 || + js_set_prop(ctx, obj, "chargeFailed", JS_NewBool(ctx, records[i].charge_failed)) < 0) { + JS_FreeValue(ctx, obj); + goto done; + } + + req_hex = hex_bytes(records[i].req_hash, sizeof(records[i].req_hash)); + resp_hex = hex_bytes(records[i].resp_hash, sizeof(records[i].resp_hash)); + if (!req_hex || !resp_hex) { + free(req_hex); + free(resp_hex); + JS_FreeValue(ctx, obj); + goto done; + } + + if (js_set_prop(ctx, obj, "reqHash", JS_NewString(ctx, req_hex)) < 0 || + js_set_prop(ctx, obj, "respHash", JS_NewString(ctx, resp_hex)) < 0) { + free(req_hex); + free(resp_hex); + JS_FreeValue(ctx, obj); + goto done; + } + free(req_hex); + free(resp_hex); + + if (JS_SetPropertyUint32(ctx, arr, (uint32_t)i, obj) < 0) { + JS_FreeValue(ctx, obj); + goto done; + } + } + + json = JS_JSONStringify(ctx, arr, JS_UNDEFINED, JS_UNDEFINED); + if (JS_IsException(json)) { + goto done; + } + + json_str = JS_ToCString(ctx, json); + if (!json_str) { + goto done; + } + + fprintf(stdout, " TAPE %s", json_str); + wrote = 1; + JS_FreeCString(ctx, json_str); + +done: + if (records) { + js_free(ctx, records); + } + if (!JS_IsUndefined(arr)) { + JS_FreeValue(ctx, arr); + } + if (!JS_IsUndefined(json)) { + JS_FreeValue(ctx, json); + } + if (!wrote) { + fprintf(stdout, " TAPE []"); + } +} + +static void print_charge_tape_suffix(JSContext *ctx, const HarnessOptions *options) { + if (!options->report_charge_tape) { + return; + } + + JSGasChargeRecord *records = NULL; + size_t count = JS_GetGasChargeTapeLength(ctx); + size_t to_read = 0; + JSValue arr = JS_UNDEFINED; + JSValue json = JS_UNDEFINED; + const char *json_str = NULL; + int wrote = 0; + + if (count == 0) { + fprintf(stdout, " CHARGE_TAPE []"); + return; + } + + to_read = + count > JS_GAS_CHARGE_TAPE_MAX_CAPACITY ? JS_GAS_CHARGE_TAPE_MAX_CAPACITY : count; + records = js_mallocz(ctx, sizeof(JSGasChargeRecord) * to_read); + if (!records) { + goto done; + } + + if (JS_ReadGasChargeTape(ctx, records, to_read, &count) != 0) { + goto done; + } + + arr = JS_NewArray(ctx); + if (JS_IsException(arr)) { + goto done; + } + + for (size_t i = 0; i < count; i++) { + JSValue obj = JS_NewObjectProto(ctx, JS_NULL); + char amount_buf[32]; + char logical_units_buf[32]; + char gas_before_buf[32]; + char gas_after_buf[32]; + + if (JS_IsException(obj)) { + JS_FreeValue(ctx, obj); + goto done; + } + + if (js_set_prop(ctx, obj, "siteId", JS_NewUint32(ctx, records[i].site_id)) < 0 || + js_set_prop(ctx, obj, "kind", JS_NewUint32(ctx, records[i].kind)) < 0 || + js_set_prop(ctx, obj, "flags", JS_NewUint32(ctx, records[i].flags)) < 0) { + JS_FreeValue(ctx, obj); + goto done; + } + + snprintf(amount_buf, sizeof(amount_buf), "%" PRIu64, records[i].amount); + snprintf(logical_units_buf, sizeof(logical_units_buf), "%" PRIu64, + records[i].logical_units); + snprintf(gas_before_buf, sizeof(gas_before_buf), "%" PRIu64, records[i].gas_before); + snprintf(gas_after_buf, sizeof(gas_after_buf), "%" PRIu64, records[i].gas_after); + if (js_set_prop(ctx, obj, "amount", JS_NewString(ctx, amount_buf)) < 0 || + js_set_prop(ctx, obj, "logicalUnits", JS_NewString(ctx, logical_units_buf)) < 0 || + js_set_prop(ctx, obj, "gasBefore", JS_NewString(ctx, gas_before_buf)) < 0 || + js_set_prop(ctx, obj, "gasAfter", JS_NewString(ctx, gas_after_buf)) < 0) { + JS_FreeValue(ctx, obj); + goto done; + } + + if (JS_SetPropertyUint32(ctx, arr, (uint32_t)i, obj) < 0) { + JS_FreeValue(ctx, obj); + goto done; + } + } + + json = JS_JSONStringify(ctx, arr, JS_UNDEFINED, JS_UNDEFINED); + if (JS_IsException(json)) { + goto done; + } + + json_str = JS_ToCString(ctx, json); + if (!json_str) { + goto done; + } + + fprintf(stdout, " CHARGE_TAPE %s", json_str); + wrote = 1; + JS_FreeCString(ctx, json_str); + +done: + if (records) { + js_free(ctx, records); + } + if (!JS_IsUndefined(arr)) { + JS_FreeValue(ctx, arr); + } + if (!JS_IsUndefined(json)) { + JS_FreeValue(ctx, json); + } + if (!wrote) { + fprintf(stdout, " CHARGE_TAPE []"); + } +} + static int print_exception(JSContext *ctx, const HarnessOptions *options) { HarnessSnapshot snapshot = {0}; JSValue exception = JS_GetException(ctx); @@ -650,6 +1250,8 @@ static int print_exception(JSContext *ctx, const HarnessOptions *options) { print_gas_suffix(options, &snapshot); print_state_suffix(ctx, options); print_trace_suffix(options, &snapshot); + print_tape_suffix(ctx, options); + print_charge_tape_suffix(ctx, options); fprintf(stdout, "\n"); JS_FreeCString(ctx, msg); } else { @@ -657,6 +1259,8 @@ static int print_exception(JSContext *ctx, const HarnessOptions *options) { print_gas_suffix(options, &snapshot); print_state_suffix(ctx, options); print_trace_suffix(options, &snapshot); + print_tape_suffix(ctx, options); + print_charge_tape_suffix(ctx, options); fprintf(stdout, "\n"); } JS_FreeValue(ctx, exception); @@ -671,6 +1275,47 @@ static int run_gc_checkpoint(JSContext *ctx, const HarnessOptions *options) { return print_exception(ctx, options); } +static int drain_pending_jobs(JSRuntime *rt, JSContext *ctx, JSContext **out_error_ctx) { + while (JS_IsJobPending(rt)) { + JSContext *job_ctx = NULL; + int rc = JS_ExecutePendingJob(rt, &job_ctx); + if (rc < 0) { + if (out_error_ctx) { + *out_error_ctx = job_ctx ? job_ctx : ctx; + } + return -1; + } + } + if (out_error_ctx) { + *out_error_ctx = ctx; + } + return 0; +} + +static int resolve_promise_result(JSContext *ctx, JSValue *value) { + int state = (int)JS_PromiseState(ctx, *value); + if (state < 0) { + return 0; + } + + if (state == JS_PROMISE_PENDING) { + JS_ThrowTypeError(ctx, "promise did not settle during deterministic job drain"); + return -1; + } + + JSValue settled = JS_PromiseResult(ctx, *value); + if (state == JS_PROMISE_REJECTED) { + JS_FreeValue(ctx, *value); + *value = JS_UNDEFINED; + JS_Throw(ctx, settled); + return -1; + } + + JS_FreeValue(ctx, *value); + *value = settled; + return 0; +} + static int encode_dv_source(JSContext *ctx, const HarnessOptions *options) { if (run_gc_checkpoint(ctx, options) != 0) { return 1; @@ -876,6 +1521,8 @@ static int run_host_call(HarnessRuntime *runtime, const HarnessOptions *options) print_gas_suffix(options, &snapshot); print_state_suffix(runtime->ctx, options); print_trace_suffix(options, &snapshot); + print_tape_suffix(runtime->ctx, options); + print_charge_tape_suffix(runtime->ctx, options); fprintf(stdout, "\n"); return 1; } @@ -888,6 +1535,8 @@ static int run_host_call(HarnessRuntime *runtime, const HarnessOptions *options) print_gas_suffix(options, &snapshot); print_state_suffix(runtime->ctx, options); print_trace_suffix(options, &snapshot); + print_tape_suffix(runtime->ctx, options); + print_charge_tape_suffix(runtime->ctx, options); fprintf(stdout, "\n"); free(req_bytes); return 0; @@ -902,6 +1551,8 @@ static int run_host_call(HarnessRuntime *runtime, const HarnessOptions *options) print_gas_suffix(options, &snapshot); print_state_suffix(runtime->ctx, options); print_trace_suffix(options, &snapshot); + print_tape_suffix(runtime->ctx, options); + print_charge_tape_suffix(runtime->ctx, options); fprintf(stdout, "\n"); free(req_bytes); @@ -909,6 +1560,11 @@ static int run_host_call(HarnessRuntime *runtime, const HarnessOptions *options) } static int eval_source(JSContext *ctx, const char *code, const HarnessOptions *options) { + JSRuntime *rt = JS_GetRuntime(ctx); + JSContext *job_error_ctx = NULL; + JSDvBuffer parity_dv = {0}; + JSValue parity_decoded = JS_UNDEFINED; + if (run_gc_checkpoint(ctx, options) != 0) { return 1; } @@ -916,14 +1572,36 @@ static int eval_source(JSContext *ctx, const char *code, const HarnessOptions *o JSValue result = JS_Eval(ctx, code, strlen(code), "", JS_EVAL_TYPE_GLOBAL); if (JS_IsException(result)) { JS_FreeValue(ctx, result); - if (run_gc_checkpoint(ctx, options) != 0) { + if (!options->parity_eval && run_gc_checkpoint(ctx, options) != 0) { return 1; } return print_exception(ctx, options); } + if (drain_pending_jobs(rt, ctx, &job_error_ctx) != 0) { + JS_FreeValue(ctx, result); + return print_exception(job_error_ctx ? job_error_ctx : ctx, options); + } + + if (resolve_promise_result(ctx, &result) != 0) { + JS_FreeValue(ctx, result); + return print_exception(ctx, options); + } + + if (options->parity_eval) { + if (JS_EncodeDV(ctx, result, NULL, &parity_dv) != 0) { + JS_FreeValue(ctx, result); + return print_exception(ctx, options); + } + JS_FreeValue(ctx, result); + result = JS_UNDEFINED; + } + if (run_gc_checkpoint(ctx, options) != 0) { JS_FreeValue(ctx, result); + if (parity_dv.data) { + JS_FreeDVBuffer(ctx, &parity_dv); + } return 1; } @@ -931,8 +1609,26 @@ static int eval_source(JSContext *ctx, const char *code, const HarnessOptions *o capture_snapshot(ctx, options, &snapshot); disable_gas_metering(ctx); - JSValue json = JS_JSONStringify(ctx, result, JS_UNDEFINED, JS_UNDEFINED); - JS_FreeValue(ctx, result); + if (options->parity_eval) { + parity_decoded = JS_DecodeDV(ctx, parity_dv.data, parity_dv.length, NULL); + JS_FreeDVBuffer(ctx, &parity_dv); + parity_dv.data = NULL; + if (JS_IsException(parity_decoded)) { + return print_exception(ctx, options); + } + } + + JSValue json = JS_JSONStringify( + ctx, + options->parity_eval ? parity_decoded : result, + JS_UNDEFINED, + JS_UNDEFINED); + if (options->parity_eval) { + JS_FreeValue(ctx, parity_decoded); + parity_decoded = JS_UNDEFINED; + } else { + JS_FreeValue(ctx, result); + } if (JS_IsException(json)) { if (run_gc_checkpoint(ctx, options) != 0) { @@ -952,6 +1648,8 @@ static int eval_source(JSContext *ctx, const char *code, const HarnessOptions *o print_gas_suffix(options, &snapshot); print_state_suffix(ctx, options); print_trace_suffix(options, &snapshot); + print_tape_suffix(ctx, options); + print_charge_tape_suffix(ctx, options); fprintf(stdout, "\n"); JS_FreeCString(ctx, json_str); @@ -959,28 +1657,265 @@ static int eval_source(JSContext *ctx, const char *code, const HarnessOptions *o return 0; } +static int eval_module_pack(HarnessRuntime *runtime, const HarnessOptions *options) { + JSContext *ctx = runtime->ctx; + JSRuntime *rt = runtime->rt; + JSContext *job_error_ctx = NULL; + JSContext *error_ctx = NULL; + ModulePack pack = {0}; + JSValue module_eval = JS_UNDEFINED; + JSValue global_obj = JS_UNDEFINED; + JSValue export_value = JS_UNDEFINED; + JSValue decoded_result = JS_UNDEFINED; + JSValue json = JS_UNDEFINED; + JSDvBuffer dv = {0}; + char *module_pack_from_file = NULL; + const char *module_pack_json = options->module_pack_json; + const char *entry_specifier = options->module_entry_specifier; + const char *target_export = NULL; + const char *json_str = NULL; + char *entry_specifier_escaped = NULL; + char *entry_export_escaped = NULL; + char *wrapper_source = NULL; + JSAtom result_atom = JS_ATOM_NULL; + const char *result_global_name = "__blue_module_pack_result"; + int rc = 1; + + if (options->module_pack_file) { + module_pack_from_file = read_file_to_string(options->module_pack_file); + if (!module_pack_from_file) { + return 1; + } + module_pack_json = module_pack_from_file; + } + + target_export = (options->module_entry_export && options->module_entry_export[0] != '\0') + ? options->module_entry_export + : "default"; + + if (run_gc_checkpoint(ctx, options) != 0) { + rc = 1; + goto cleanup; + } + + if (!module_pack_json || module_pack_json[0] == '\0') { + JS_ThrowReferenceError(ctx, "ModuleEvaluationError: empty module pack json"); + goto cleanup; + } + + if (!entry_specifier || entry_specifier[0] == '\0') { + JS_ThrowReferenceError(ctx, "ModuleSpecifierNotFound: empty entry specifier"); + goto cleanup; + } + + if (parse_module_pack_json(ctx, module_pack_json, &pack) != 0) { + goto cleanup; + } + + if (!find_module_pack_entry(&pack, entry_specifier)) { + JS_ThrowReferenceError(ctx, "ModuleSpecifierNotFound: entry module not found"); + goto cleanup; + } + + if (JS_AddIntrinsicPromise(ctx) != 0) { + goto cleanup; + } + + JS_SetModuleLoaderFunc2(rt, NULL, module_pack_loader, NULL, &pack); + + entry_specifier_escaped = escape_js_string(entry_specifier); + entry_export_escaped = escape_js_string(target_export); + if (!entry_specifier_escaped || !entry_export_escaped) { + JS_ThrowOutOfMemory(ctx); + goto cleanup; + } + + wrapper_source = dup_printf( + "import * as __blue_entry_ns from %s;\n" + "if (typeof __blue_entry_ns[%s] === 'undefined') {\n" + " throw new Error('ModuleExportMissing: export not found');\n" + "}\n" + "globalThis.%s = __blue_entry_ns[%s];\n", + entry_specifier_escaped, + entry_export_escaped, + result_global_name, + entry_export_escaped); + if (!wrapper_source) { + JS_ThrowOutOfMemory(ctx); + goto cleanup; + } + + module_eval = JS_Eval(ctx, + wrapper_source, + strlen(wrapper_source), + "./__module_pack_entry__.js", + JS_EVAL_TYPE_MODULE); + if (JS_IsException(module_eval)) { + goto cleanup; + } + + if (drain_pending_jobs(rt, ctx, &job_error_ctx) != 0) { + error_ctx = job_error_ctx ? job_error_ctx : ctx; + rc = 1; + goto cleanup; + } + + global_obj = JS_GetGlobalObject(ctx); + if (JS_IsException(global_obj)) { + goto cleanup; + } + + export_value = JS_GetPropertyStr(ctx, global_obj, result_global_name); + if (JS_IsException(export_value)) { + goto cleanup; + } + if (JS_IsUndefined(export_value)) { + JS_ThrowReferenceError(ctx, "ModuleExportMissing: export not found"); + goto cleanup; + } + + if (resolve_promise_result(ctx, &export_value) != 0) { + rc = 1; + goto cleanup; + } + + result_atom = JS_NewAtom(ctx, result_global_name); + if (result_atom != JS_ATOM_NULL) { + JS_DeleteProperty(ctx, global_obj, result_atom, 0); + } + + if (JS_EncodeDV(ctx, export_value, NULL, &dv) != 0) { + goto cleanup; + } + + if (run_gc_checkpoint(ctx, options) != 0) { + rc = 1; + goto cleanup; + } + + HarnessSnapshot snapshot = {0}; + capture_snapshot(ctx, options, &snapshot); + disable_gas_metering(ctx); + + decoded_result = JS_DecodeDV(ctx, dv.data, dv.length, NULL); + if (JS_IsException(decoded_result)) { + goto cleanup; + } + + json = JS_JSONStringify(ctx, decoded_result, JS_UNDEFINED, JS_UNDEFINED); + if (JS_IsException(json)) { + goto cleanup; + } + + json_str = JS_ToCString(ctx, json); + if (!json_str) { + fprintf(stdout, "ERROR "); + print_gas_suffix(options, &snapshot); + print_state_suffix(ctx, options); + print_trace_suffix(options, &snapshot); + print_tape_suffix(ctx, options); + print_charge_tape_suffix(ctx, options); + fprintf(stdout, "\n"); + rc = 1; + goto cleanup; + } + + fprintf(stdout, "RESULT %s", json_str); + print_gas_suffix(options, &snapshot); + print_state_suffix(ctx, options); + print_trace_suffix(options, &snapshot); + print_tape_suffix(ctx, options); + print_charge_tape_suffix(ctx, options); + fprintf(stdout, "\n"); + rc = 0; + +cleanup: + if (json_str) { + JS_FreeCString(ctx, json_str); + } + if (!JS_IsUndefined(json)) { + JS_FreeValue(ctx, json); + } + if (!JS_IsUndefined(decoded_result)) { + JS_FreeValue(ctx, decoded_result); + } + if (dv.data) { + JS_FreeDVBuffer(ctx, &dv); + } + + JS_SetModuleLoaderFunc2(rt, NULL, NULL, NULL, NULL); + if (result_atom != JS_ATOM_NULL) { + JS_FreeAtom(ctx, result_atom); + } + + if (!JS_IsUndefined(export_value)) { + JS_FreeValue(ctx, export_value); + } + if (!JS_IsUndefined(global_obj)) { + JS_FreeValue(ctx, global_obj); + } + if (!JS_IsUndefined(module_eval)) { + JS_FreeValue(ctx, module_eval); + } + + if (wrapper_source) { + free(wrapper_source); + } + if (entry_specifier_escaped) { + free(entry_specifier_escaped); + } + if (entry_export_escaped) { + free(entry_export_escaped); + } + + JS_FreeContextLoadedModules(ctx); + free_module_pack(&pack); + free(module_pack_from_file); + + if (rc != 0) { + JSContext *exception_ctx = error_ctx ? error_ctx : ctx; + if (!JS_HasException(exception_ctx)) { + JS_ThrowInternalError(ctx, "ModuleEvaluationError: module-pack execution failed"); + exception_ctx = ctx; + } + return print_exception(exception_ctx, options); + } + + return 0; +} + static void print_usage(const char *prog) { fprintf(stderr, "Usage:\n" - " %s [--gas-limit ] [--report-gas] [--gas-trace] [--dump-global ] [--abi-manifest-hex | --abi-manifest-hex-file ] [--abi-manifest-hash ] [--context-blob-hex ] --eval \"\"\n" + " %s [--gas-limit ] [--report-gas] [--report-tape] [--gas-charge-tape] [--gas-charge-tape-capacity ] [--gas-trace] [--dump-global ] [--execution-profile ] [--abi-manifest-hex | --abi-manifest-hex-file ] [--abi-manifest-hash ] [--context-blob-hex ] [--parity-eval] --eval \"\"\n" + " %s [--gas-limit ] [--report-gas] [--report-tape] [--gas-charge-tape] [--gas-charge-tape-capacity ] [--gas-trace] [--execution-profile ] [--abi-manifest-hex | --abi-manifest-hex-file ] [--abi-manifest-hash ] --module-entry-specifier [--module-entry-export ] (--module-pack-json \"\" | --module-pack-file )\n" " %s --dv-encode --eval \"\"\n" " %s --dv-decode \n" - " %s --host-call [--host-fn-id ] [--host-max-request ] [--host-max-response ] [--host-max-units ] [--host-parse-envelope] [--host-reentrant] [--host-exception] [--gas-limit ] [--report-gas] [--gas-trace] [--abi-manifest-hex | --abi-manifest-hex-file ] [--abi-manifest-hash ] [--context-blob-hex ]\n" + " %s --host-call [--host-fn-id ] [--host-max-request ] [--host-max-response ] [--host-max-units ] [--host-parse-envelope] [--host-reentrant] [--host-exception] [--gas-limit ] [--report-gas] [--report-tape] [--gas-charge-tape] [--gas-charge-tape-capacity ] [--gas-trace] [--execution-profile ] [--abi-manifest-hex | --abi-manifest-hex-file ] [--abi-manifest-hash ] [--context-blob-hex ]\n" " %s --sha256-hex \n", prog, prog, prog, prog, + prog, prog); } static int parse_args(int argc, char **argv, HarnessOptions *opts) { opts->code = NULL; + opts->module_pack_json = NULL; + opts->module_pack_file = NULL; + opts->module_entry_specifier = NULL; + opts->module_entry_export = NULL; opts->gas_limit = JS_GAS_UNLIMITED; opts->report_gas = 0; opts->report_trace = 0; + opts->report_tape = 0; + opts->report_charge_tape = 0; + opts->charge_tape_capacity = 256; opts->dump_global = NULL; opts->dv_encode = 0; + opts->parity_eval = 0; opts->dv_decode_hex = NULL; opts->abi_manifest_hex = NULL; opts->abi_manifest_file = NULL; @@ -996,6 +1931,7 @@ static int parse_args(int argc, char **argv, HarnessOptions *opts) { opts->host_call_parse_envelope = 0; opts->host_call_max_units = 0; opts->host_call_max_units_provided = 0; + opts->execution_profile = "baseline-v1"; for (int i = 1; i < argc; i++) { if (strcmp(argv[i], "--eval") == 0) { @@ -1029,6 +1965,33 @@ static int parse_args(int argc, char **argv, HarnessOptions *opts) { continue; } + if (strcmp(argv[i], "--report-tape") == 0) { + opts->report_tape = 1; + continue; + } + + if (strcmp(argv[i], "--gas-charge-tape") == 0) { + opts->report_charge_tape = 1; + continue; + } + + if (strcmp(argv[i], "--gas-charge-tape-capacity") == 0) { + if (i + 1 >= argc) { + print_usage(argv[0]); + return 2; + } + const char *value = argv[++i]; + char *endptr = NULL; + errno = 0; + unsigned long parsed = strtoul(value, &endptr, 10); + if (errno != 0 || endptr == value || *endptr != '\0' || parsed > UINT32_MAX) { + fprintf(stderr, "Invalid --gas-charge-tape-capacity: %s\n", value); + return 2; + } + opts->charge_tape_capacity = (uint32_t)parsed; + continue; + } + if (strcmp(argv[i], "--gas-trace") == 0) { opts->report_trace = 1; continue; @@ -1039,6 +2002,11 @@ static int parse_args(int argc, char **argv, HarnessOptions *opts) { continue; } + if (strcmp(argv[i], "--parity-eval") == 0) { + opts->parity_eval = 1; + continue; + } + if (strcmp(argv[i], "--dv-decode") == 0) { if (i + 1 >= argc) { print_usage(argv[0]); @@ -1084,6 +2052,15 @@ static int parse_args(int argc, char **argv, HarnessOptions *opts) { continue; } + if (strcmp(argv[i], "--execution-profile") == 0) { + if (i + 1 >= argc) { + print_usage(argv[0]); + return 2; + } + opts->execution_profile = argv[++i]; + continue; + } + if (strcmp(argv[i], "--sha256-hex") == 0) { if (i + 1 >= argc) { print_usage(argv[0]); @@ -1102,6 +2079,42 @@ static int parse_args(int argc, char **argv, HarnessOptions *opts) { continue; } + if (strcmp(argv[i], "--module-pack-json") == 0) { + if (i + 1 >= argc) { + print_usage(argv[0]); + return 2; + } + opts->module_pack_json = argv[++i]; + continue; + } + + if (strcmp(argv[i], "--module-pack-file") == 0) { + if (i + 1 >= argc) { + print_usage(argv[0]); + return 2; + } + opts->module_pack_file = argv[++i]; + continue; + } + + if (strcmp(argv[i], "--module-entry-specifier") == 0) { + if (i + 1 >= argc) { + print_usage(argv[0]); + return 2; + } + opts->module_entry_specifier = argv[++i]; + continue; + } + + if (strcmp(argv[i], "--module-entry-export") == 0) { + if (i + 1 >= argc) { + print_usage(argv[0]); + return 2; + } + opts->module_entry_export = argv[++i]; + continue; + } + if (strcmp(argv[i], "--host-call") == 0) { if (i + 1 >= argc) { print_usage(argv[0]); @@ -1203,9 +2216,13 @@ static int parse_args(int argc, char **argv, HarnessOptions *opts) { } const int host_call_mode = opts->host_call_hex != NULL || opts->host_call_parse_envelope; + const int module_pack_mode = opts->module_pack_json != NULL || opts->module_pack_file != NULL || + opts->module_entry_specifier != NULL || + opts->module_entry_export != NULL; if (opts->dv_decode_hex) { - if (opts->code != NULL || opts->dv_encode || host_call_mode || opts->sha256_hex) { + if (opts->code != NULL || opts->dv_encode || opts->parity_eval || host_call_mode || opts->sha256_hex || + module_pack_mode) { print_usage(argv[0]); return 2; } @@ -1213,8 +2230,8 @@ static int parse_args(int argc, char **argv, HarnessOptions *opts) { } if (opts->sha256_hex) { - if (opts->code != NULL || opts->dv_encode || opts->dv_decode_hex || - host_call_mode) { + if (opts->code != NULL || opts->dv_encode || opts->parity_eval || opts->dv_decode_hex || + host_call_mode || module_pack_mode) { print_usage(argv[0]); return 2; } @@ -1222,7 +2239,7 @@ static int parse_args(int argc, char **argv, HarnessOptions *opts) { } if (host_call_mode) { - if (opts->code != NULL || opts->dv_encode) { + if (opts->code != NULL || opts->dv_encode || opts->parity_eval || module_pack_mode) { print_usage(argv[0]); return 2; } @@ -1233,11 +2250,32 @@ static int parse_args(int argc, char **argv, HarnessOptions *opts) { return 0; } + if (module_pack_mode) { + if (opts->code != NULL || opts->dv_encode || opts->parity_eval) { + print_usage(argv[0]); + return 2; + } + if ((opts->module_pack_json != NULL) == (opts->module_pack_file != NULL)) { + print_usage(argv[0]); + return 2; + } + if (opts->module_entry_specifier == NULL) { + print_usage(argv[0]); + return 2; + } + return 0; + } + if (opts->code == NULL) { print_usage(argv[0]); return 2; } + if (opts->parity_eval && opts->dv_encode) { + print_usage(argv[0]); + return 2; + } + return 0; } @@ -1261,6 +2299,25 @@ int main(int argc, char **argv) { JS_SetGasLimit(runtime.ctx, options.gas_limit); + if (options.report_tape) { + if (JS_EnableHostTape(runtime.ctx, 64) != 0 || JS_ResetHostTape(runtime.ctx) != 0) { + fprintf(stderr, "init: failed to enable host tape\n"); + free_runtime(&runtime); + return 1; + } + } + + if (options.report_charge_tape) { + if (JS_EnableGasChargeTape(runtime.ctx, options.charge_tape_capacity) != 0 || + JS_ResetGasChargeTape(runtime.ctx) != 0) { + fprintf(stderr, "init: failed to enable gas charge tape\n"); + free_runtime(&runtime); + return 1; + } + } + + /* Keep trace counters aligned with wasm-node evaluate(): tape setup first, + then gas-trace enable/reset so setup charges are excluded from trace data. */ if (options.report_trace) { if (JS_EnableGasTrace(runtime.ctx, 1) != 0) { fprintf(stderr, "init: failed to enable gas trace\n"); @@ -1270,15 +2327,15 @@ int main(int argc, char **argv) { } int rc = 0; + const int module_pack_mode = options.module_pack_json != NULL || options.module_pack_file != NULL; if (options.dv_decode_hex) { rc = decode_dv_hex(runtime.ctx, &options); } else if (options.host_call_hex) { rc = run_host_call(&runtime, &options); + } else if (module_pack_mode) { + rc = eval_module_pack(&runtime, &options); } else { - if (run_gc_checkpoint(runtime.ctx, &options) != 0) { - free_runtime(&runtime); - return 1; - } + /* eval_source()/encode_dv_source() own their GC checkpoint sequencing. */ if (options.dv_encode) { rc = encode_dv_source(runtime.ctx, &options); } else { diff --git a/tools/quickjs-native-harness/tests/baseline-v1/console.spec.mjs b/tools/quickjs-native-harness/tests/baseline-v1/console.spec.mjs new file mode 100644 index 0000000..39b6e0d --- /dev/null +++ b/tools/quickjs-native-harness/tests/baseline-v1/console.spec.mjs @@ -0,0 +1,12 @@ +import { describe, it } from 'vitest'; +import { expectHarnessOutput } from '../helpers/harness.mjs'; + +describe('baseline-v1 console', () => { + it('disables console', () => { + expectHarnessOutput( + 'console disabled', + "console.log('x')", + 'ERROR TypeError: console is disabled in deterministic mode', + ); + }); +}); diff --git a/tools/quickjs-native-harness/tests/baseline-v1/promise.spec.mjs b/tools/quickjs-native-harness/tests/baseline-v1/promise.spec.mjs new file mode 100644 index 0000000..10cf6a0 --- /dev/null +++ b/tools/quickjs-native-harness/tests/baseline-v1/promise.spec.mjs @@ -0,0 +1,12 @@ +import { describe, it } from 'vitest'; +import { expectHarnessOutput } from '../helpers/harness.mjs'; + +describe('baseline-v1 Promise', () => { + it('disables Promise in baseline mode', () => { + expectHarnessOutput( + 'Promise disabled', + 'Promise.resolve(1)', + 'ERROR TypeError: Promise is disabled in deterministic mode', + ); + }); +}); diff --git a/tools/quickjs-native-harness/tests/baseline-v1/regexp.spec.mjs b/tools/quickjs-native-harness/tests/baseline-v1/regexp.spec.mjs new file mode 100644 index 0000000..11f5c88 --- /dev/null +++ b/tools/quickjs-native-harness/tests/baseline-v1/regexp.spec.mjs @@ -0,0 +1,17 @@ +import { describe, it } from 'vitest'; +import { expectHarnessOutput } from '../helpers/harness.mjs'; + +describe('baseline-v1 RegExp', () => { + it('disables RegExp construction and regex literals', () => { + expectHarnessOutput( + 'RegExp constructor disabled', + "new RegExp('a')", + 'ERROR TypeError: RegExp is disabled in deterministic mode', + ); + expectHarnessOutput( + 'RegExp literal disabled', + "'abc'.match(/a/)", + 'ERROR TypeError: RegExp is disabled in deterministic mode', + ); + }); +}); diff --git a/tools/quickjs-native-harness/tests/baseline-v1/typed-arrays.spec.mjs b/tools/quickjs-native-harness/tests/baseline-v1/typed-arrays.spec.mjs new file mode 100644 index 0000000..6df49d2 --- /dev/null +++ b/tools/quickjs-native-harness/tests/baseline-v1/typed-arrays.spec.mjs @@ -0,0 +1,27 @@ +import { describe, it } from 'vitest'; +import { expectHarnessOutput } from '../helpers/harness.mjs'; + +describe('baseline-v1 binary surface', () => { + it('disables typed arrays and related binary objects', () => { + expectHarnessOutput( + 'ArrayBuffer disabled', + 'new ArrayBuffer(4)', + 'ERROR TypeError: ArrayBuffer is disabled in deterministic mode', + ); + expectHarnessOutput( + 'SharedArrayBuffer disabled', + 'new SharedArrayBuffer(4)', + 'ERROR TypeError: SharedArrayBuffer is disabled in deterministic mode', + ); + expectHarnessOutput( + 'DataView disabled', + 'new DataView()', + 'ERROR TypeError: DataView is disabled in deterministic mode', + ); + expectHarnessOutput( + 'Typed arrays disabled', + 'new Uint8Array(4)', + 'ERROR TypeError: Typed arrays are disabled in deterministic mode', + ); + }); +}); diff --git a/tools/quickjs-native-harness/tests/common-v1/eval.spec.mjs b/tools/quickjs-native-harness/tests/common-v1/eval.spec.mjs new file mode 100644 index 0000000..94bc651 --- /dev/null +++ b/tools/quickjs-native-harness/tests/common-v1/eval.spec.mjs @@ -0,0 +1,16 @@ +import { describe, it } from 'vitest'; +import { expectHarnessOutput } from '../helpers/harness.mjs'; + +describe('deterministic runtime eval', () => { + it('keeps basic evaluation working', () => { + expectHarnessOutput('basic addition', '1 + 2', 'RESULT 3'); + }); + + it('disables eval', () => { + expectHarnessOutput( + 'eval disabled', + "eval('1 + 1')", + 'ERROR TypeError: eval is disabled in deterministic mode', + ); + }); +}); diff --git a/tools/quickjs-native-harness/tests/common-v1/function.spec.mjs b/tools/quickjs-native-harness/tests/common-v1/function.spec.mjs new file mode 100644 index 0000000..aa47c11 --- /dev/null +++ b/tools/quickjs-native-harness/tests/common-v1/function.spec.mjs @@ -0,0 +1,32 @@ +import { describe, it } from 'vitest'; +import { expectHarnessOutput } from '../helpers/harness.mjs'; + +describe('deterministic runtime Function', () => { + it('disables the Function global', () => { + expectHarnessOutput( + 'Function disabled', + "(new Function('return 7'))()", + 'ERROR TypeError: Function is disabled in deterministic mode', + ); + }); + + it('blocks Function constructor escape paths', () => { + expectHarnessOutput( + 'Function ctor via Function.prototype.constructor', + "(() => { const RealFunction = (function () {}).constructor; return RealFunction('return 3')(); })()", + 'ERROR TypeError: Function constructor is disabled in deterministic mode', + ); + + expectHarnessOutput( + 'Function ctor via arrow constructor', + "(() => { const RealFunction = (() => {}).constructor; return RealFunction('return 4')(); })()", + 'ERROR TypeError: Function constructor is disabled in deterministic mode', + ); + + expectHarnessOutput( + 'Function ctor via generator constructor', + "(() => { const GenFunction = (function* () {}).constructor; return GenFunction('return 5')(); })()", + 'ERROR TypeError: Function constructor is disabled in deterministic mode', + ); + }); +}); diff --git a/tools/quickjs-native-harness/tests/common-v1/gas.spec.mjs b/tools/quickjs-native-harness/tests/common-v1/gas.spec.mjs new file mode 100644 index 0000000..800c02e --- /dev/null +++ b/tools/quickjs-native-harness/tests/common-v1/gas.spec.mjs @@ -0,0 +1,46 @@ +import { describe, it } from 'vitest'; +import { expectHarnessFixture } from '../helpers/harness.mjs'; + +describe('deterministic runtime gas and GC', () => { + it('enforces zero gas and gc-checkpoint budget limits', () => { + expectHarnessFixture( + 'zero-precharge', + 'gas/zero-precharge.js', + 'ERROR OutOfGas: out of gas GAS remaining=0 used=0 STATE undefined', + ['--gas-limit', '0', '--report-gas', '--dump-global', '__touched'], + ); + expectHarnessFixture( + 'gc-checkpoint-budget', + 'gas/zero-precharge.js', + 'ERROR OutOfGas: out of gas GAS remaining=0 used=54 STATE undefined', + ['--gas-limit', '54', '--report-gas', '--dump-global', '__touched'], + ); + }); + + it('reports opcode gas usage', () => { + expectHarnessFixture( + 'addition-gas', + 'gas/addition.js', + 'RESULT 3 GAS remaining=66 used=39', + ['--gas-limit', '105', '--report-gas'], + ); + }); + + it('includes allocation gas in traces', () => { + expectHarnessFixture( + 'addition-trace', + 'gas/addition.js', + 'RESULT 3 GAS remaining=66 used=39 TRACE {"opcodeCount":5,"opcodeGas":5,"arrayCbBase":{"count":0,"gas":0},"arrayCbPerEl":{"count":0,"gas":0},"alloc":{"count":11,"bytes":1048,"gas":34},"jsonParse":{"count":0,"gas":0,"inputBytes":0,"values":0,"objectEntries":0,"arrayElements":0},"jsonStringify":{"count":0,"gas":0,"outputBytes":0,"values":0,"objectEntries":0,"arrayElements":0,"sortComparisons":0},"hostCallPre":{"count":0,"gas":0},"hostCallPost":{"count":0,"gas":0}}', + ['--gas-limit', '105', '--report-gas', '--gas-trace'], + ); + }); + + it('runs deterministic gc checkpoints without spurious extra gas drift', () => { + expectHarnessFixture( + 'gc-pending-trace', + 'gas/gc-pending.js', + 'RESULT 1200000 GAS remaining=39911 used=89 TRACE {"opcodeCount":18,"opcodeGas":18,"arrayCbBase":{"count":0,"gas":0},"arrayCbPerEl":{"count":0,"gas":0},"alloc":{"count":39,"bytes":2456,"gas":71},"jsonParse":{"count":0,"gas":0,"inputBytes":0,"values":0,"objectEntries":0,"arrayElements":0},"jsonStringify":{"count":0,"gas":0,"outputBytes":0,"values":0,"objectEntries":0,"arrayElements":0,"sortComparisons":0},"hostCallPre":{"count":0,"gas":0},"hostCallPost":{"count":0,"gas":0}}', + ['--gas-limit', '40000', '--report-gas', '--gas-trace'], + ); + }); +}); diff --git a/tools/quickjs-native-harness/tests/common-v1/host-hardening.spec.mjs b/tools/quickjs-native-harness/tests/common-v1/host-hardening.spec.mjs new file mode 100644 index 0000000..07e896f --- /dev/null +++ b/tools/quickjs-native-harness/tests/common-v1/host-hardening.spec.mjs @@ -0,0 +1,32 @@ +import { describe, it } from 'vitest'; +import { expectHarnessOutput } from '../helpers/harness.mjs'; + +describe('deterministic runtime Host hardening', () => { + it('prevents extensions on Host and Host.v1', () => { + expectHarnessOutput( + 'Host immutability', + `(() => { + const before = Host; + Host = 123; + const after = Host; + let added = false; + try { + Host.v1.added = 1; + added = Object.prototype.hasOwnProperty.call(Host.v1, 'added'); + } catch (_) { + added = false; + } + return { + sameRef: before === after, + hasV1: !!after.v1, + added, + protoNull: Object.getPrototypeOf(Host) === null, + v1ProtoNull: Object.getPrototypeOf(Host.v1) === null, + hostIsExtensible: Object.isExtensible(Host), + hostV1Extensible: Object.isExtensible(Host.v1), + }; + })()`, + 'RESULT {"sameRef":true,"hasV1":true,"added":false,"protoNull":true,"v1ProtoNull":true,"hostIsExtensible":false,"hostV1Extensible":false}', + ); + }); +}); diff --git a/tools/quickjs-native-harness/tests/common-v1/host.spec.mjs b/tools/quickjs-native-harness/tests/common-v1/host.spec.mjs new file mode 100644 index 0000000..d28356e --- /dev/null +++ b/tools/quickjs-native-harness/tests/common-v1/host.spec.mjs @@ -0,0 +1,24 @@ +import { describe, it } from 'vitest'; +import { expectHarnessOutput } from '../helpers/harness.mjs'; + +describe('deterministic runtime Host bootstrap', () => { + it('installs Host and Host.v1 as null-prototype globals', () => { + expectHarnessOutput( + 'Host descriptor', + `(() => { + const desc = Object.getOwnPropertyDescriptor(globalThis, 'Host'); + const v1 = Host && Host.v1; + return { + configurable: desc ? desc.configurable : null, + enumerable: desc ? desc.enumerable : null, + writable: desc ? desc.writable : null, + hostType: typeof Host, + hostNullProto: Host ? Object.getPrototypeOf(Host) === null : null, + v1Type: typeof v1, + v1NullProto: v1 ? Object.getPrototypeOf(v1) === null : null + }; + })()`, + 'RESULT {"configurable":false,"enumerable":false,"writable":false,"hostType":"object","hostNullProto":true,"v1Type":"object","v1NullProto":true}', + ); + }); +}); diff --git a/tools/quickjs-native-harness/tests/common-v1/print.spec.mjs b/tools/quickjs-native-harness/tests/common-v1/print.spec.mjs new file mode 100644 index 0000000..e4881aa --- /dev/null +++ b/tools/quickjs-native-harness/tests/common-v1/print.spec.mjs @@ -0,0 +1,12 @@ +import { describe, it } from 'vitest'; +import { expectHarnessOutput } from '../helpers/harness.mjs'; + +describe('deterministic runtime print', () => { + it('disables print', () => { + expectHarnessOutput( + 'print disabled', + "print('x')", + 'ERROR TypeError: print is disabled in deterministic mode', + ); + }); +}); diff --git a/tools/quickjs-native-harness/tests/common-v1/proxy.spec.mjs b/tools/quickjs-native-harness/tests/common-v1/proxy.spec.mjs new file mode 100644 index 0000000..a7bffcb --- /dev/null +++ b/tools/quickjs-native-harness/tests/common-v1/proxy.spec.mjs @@ -0,0 +1,12 @@ +import { describe, it } from 'vitest'; +import { expectHarnessOutput } from '../helpers/harness.mjs'; + +describe('deterministic runtime Proxy', () => { + it('disables Proxy', () => { + expectHarnessOutput( + 'Proxy disabled', + 'new Proxy({}, {})', + 'ERROR TypeError: Proxy is disabled in deterministic mode', + ); + }); +}); diff --git a/tools/quickjs-native-harness/tests/common-v1/random.spec.mjs b/tools/quickjs-native-harness/tests/common-v1/random.spec.mjs new file mode 100644 index 0000000..60dddd9 --- /dev/null +++ b/tools/quickjs-native-harness/tests/common-v1/random.spec.mjs @@ -0,0 +1,12 @@ +import { describe, it } from 'vitest'; +import { expectHarnessOutput } from '../helpers/harness.mjs'; + +describe('deterministic runtime Math.random', () => { + it('disables Math.random', () => { + expectHarnessOutput( + 'Math.random disabled', + 'Math.random()', + 'ERROR TypeError: Math.random is disabled in deterministic mode', + ); + }); +}); diff --git a/tools/quickjs-native-harness/tests/common-v1/webassembly-atomics.spec.mjs b/tools/quickjs-native-harness/tests/common-v1/webassembly-atomics.spec.mjs new file mode 100644 index 0000000..476fd00 --- /dev/null +++ b/tools/quickjs-native-harness/tests/common-v1/webassembly-atomics.spec.mjs @@ -0,0 +1,17 @@ +import { describe, it } from 'vitest'; +import { expectHarnessOutput } from '../helpers/harness.mjs'; + +describe('deterministic runtime WebAssembly and Atomics', () => { + it('disables Atomics and WebAssembly', () => { + expectHarnessOutput( + 'Atomics disabled', + 'Atomics()', + 'ERROR TypeError: Atomics is disabled in deterministic mode', + ); + expectHarnessOutput( + 'WebAssembly disabled', + 'WebAssembly()', + 'ERROR TypeError: WebAssembly is disabled in deterministic mode', + ); + }); +}); diff --git a/tools/quickjs-native-harness/tests/compat-binary-v1/.gitkeep b/tools/quickjs-native-harness/tests/compat-binary-v1/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tools/quickjs-native-harness/tests/compat-binary-v1/.gitkeep @@ -0,0 +1 @@ + diff --git a/tools/quickjs-native-harness/tests/compat-general-v1/.gitkeep b/tools/quickjs-native-harness/tests/compat-general-v1/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tools/quickjs-native-harness/tests/compat-general-v1/.gitkeep @@ -0,0 +1 @@ + diff --git a/tools/quickjs-native-harness/tests/helpers/harness.mjs b/tools/quickjs-native-harness/tests/helpers/harness.mjs new file mode 100644 index 0000000..9141e6a --- /dev/null +++ b/tools/quickjs-native-harness/tests/helpers/harness.mjs @@ -0,0 +1,72 @@ +import { readFileSync } from 'node:fs'; +import path from 'node:path'; +import { spawnSync } from 'node:child_process'; +import { expect } from 'vitest'; + +export const repoRoot = path.resolve( + import.meta.dirname, + '..', + '..', + '..', + '..', +); +const fixturesRoot = path.join( + repoRoot, + 'tools', + 'quickjs-native-harness', + 'fixtures', +); +const harnessBin = path.join( + repoRoot, + 'tools', + 'quickjs-native-harness', + 'dist', + 'quickjs-native-harness', +); + +const hostManifestHex = readFixture( + 'libs/test-harness/fixtures/abi-manifest/host-v1.bytes.hex', +); +const hostManifestHash = readFixture( + 'libs/test-harness/fixtures/abi-manifest/host-v1.hash', +); +const commonArgs = [ + '--abi-manifest-hex', + hostManifestHex, + '--abi-manifest-hash', + hostManifestHash, +]; + +function readFixture(relativePath) { + return readFileSync(path.join(repoRoot, relativePath), 'utf8').replace( + /\s+/g, + '', + ); +} + +export function runHarness(args) { + const result = spawnSync(harnessBin, [...commonArgs, ...args], { + cwd: repoRoot, + encoding: 'utf8', + }); + + return { + status: result.status, + stdout: result.stdout.trim(), + stderr: result.stderr.trim(), + error: result.error, + }; +} + +export function expectHarnessOutput(name, code, expected, extraArgs = []) { + const result = runHarness([...extraArgs, '--eval', code]); + + expect(result.error, `${name}: spawn error`).toBeUndefined(); + expect(result.stderr, `${name}: stderr`).toBe(''); + expect(result.stdout, `${name}: stdout`).toBe(expected); +} + +export function expectHarnessFixture(name, fixture, expected, extraArgs = []) { + const code = readFileSync(path.join(fixturesRoot, fixture), 'utf8'); + expectHarnessOutput(name, code, expected, extraArgs); +} diff --git a/tools/quickjs-native-harness/vitest.config.mjs b/tools/quickjs-native-harness/vitest.config.mjs new file mode 100644 index 0000000..8c5b4ae --- /dev/null +++ b/tools/quickjs-native-harness/vitest.config.mjs @@ -0,0 +1,18 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + root: import.meta.dirname, + cacheDir: '../../node_modules/.vite/tools/quickjs-native-harness', + test: { + name: 'quickjs-native-harness', + watch: false, + globals: true, + environment: 'node', + include: ['tests/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], + reporters: ['default'], + coverage: { + reportsDirectory: './test-output/vitest/coverage', + provider: 'v8', + }, + }, +}); diff --git a/tools/release-evidence/_lib.mjs b/tools/release-evidence/_lib.mjs new file mode 100644 index 0000000..2f17473 --- /dev/null +++ b/tools/release-evidence/_lib.mjs @@ -0,0 +1,181 @@ +import { createHash, createPrivateKey, createPublicKey, sign, verify } from 'node:crypto'; +import { copyFile, mkdir, readFile, stat, writeFile } from 'node:fs/promises'; +import path from 'node:path'; + +export async function ensureDir(targetDir) { + await mkdir(targetDir, { recursive: true }); +} + +export function sha256Hex(input) { + return createHash('sha256').update(input).digest('hex'); +} + +export async function sha256FileHex(filePath) { + const content = await readFile(filePath); + return sha256Hex(content); +} + +export async function copyIntoEvidenceDir(sourcePath, targetDir, targetName) { + await ensureDir(targetDir); + const destinationPath = path.join(targetDir, targetName ?? path.basename(sourcePath)); + await copyFile(sourcePath, destinationPath); + return destinationPath; +} + +export async function createManifestEntry(filePath, evidenceRoot, category) { + const digest = await sha256FileHex(filePath); + const fileStat = await stat(filePath); + return { + category, + file: path.relative(evidenceRoot, filePath), + sha256: digest, + sizeBytes: fileStat.size, + }; +} + +export function createDetachedSignature(payloadBytes, options = {}) { + if (options.privateKeyPem) { + const key = createPrivateKey(options.privateKeyPem); + const signatureBytes = sign(null, payloadBytes, key); + return { + mode: 'ed25519', + algorithm: 'ed25519', + keyId: options.keyId ?? 'release-evidence', + signatureBase64: signatureBytes.toString('base64'), + }; + } + + return { + mode: 'digest-fallback', + algorithm: 'sha256', + keyId: options.keyId ?? 'digest-fallback', + signatureHex: sha256Hex(payloadBytes), + }; +} + +export function verifyDetachedSignature(payloadBytes, signaturePayload, options = {}) { + if (signaturePayload.mode === 'ed25519') { + if (!options.publicKeyPem) { + return { + ok: false, + reason: 'missing public key for ed25519 signature verification', + }; + } + const key = createPublicKey(options.publicKeyPem); + const signatureBytes = Buffer.from(signaturePayload.signatureBase64, 'base64'); + const isValid = verify(null, payloadBytes, key, signatureBytes); + return { + ok: isValid, + reason: isValid ? null : 'ed25519 signature mismatch', + }; + } + + const expectedDigest = sha256Hex(payloadBytes); + const isValid = signaturePayload.signatureHex === expectedDigest; + return { + ok: isValid, + reason: isValid ? null : 'sha256 digest signature mismatch', + }; +} + +export async function writeChecksumFile(filePath) { + const digest = await sha256FileHex(filePath); + const checksumPath = `${filePath}.sha256`; + await writeFile( + checksumPath, + `${digest} ${path.basename(filePath)}\n`, + 'utf8', + ); + return checksumPath; +} + +export async function writeSignatureFile(filePath, signaturePayload) { + const signaturePath = `${filePath}.sig`; + await writeFile( + signaturePath, + `${JSON.stringify(signaturePayload, null, 2)}\n`, + 'utf8', + ); + return signaturePath; +} + +export async function loadOptionalText(valueOrPath) { + if (!valueOrPath) { + return null; + } + const normalized = valueOrPath.trim(); + if (!normalized) { + return null; + } + if (normalized.includes('BEGIN') || normalized.includes('\n')) { + return normalized; + } + return readFile(path.resolve(process.cwd(), normalized), 'utf8'); +} + +export async function verifyManifestBundle(manifest, evidenceRoot, options = {}) { + const errors = []; + let verifiedCount = 0; + + for (const artifact of manifest.artifacts) { + const artifactPath = path.resolve(evidenceRoot, artifact.file); + let digest; + try { + digest = await sha256FileHex(artifactPath); + } catch (error) { + errors.push({ + type: 'missing-artifact', + file: artifact.file, + message: error instanceof Error ? error.message : String(error), + }); + continue; + } + if (digest !== artifact.sha256) { + errors.push({ + type: 'checksum-mismatch', + file: artifact.file, + expected: artifact.sha256, + actual: digest, + }); + continue; + } + + if (artifact.signatureFile) { + const signaturePath = path.resolve(evidenceRoot, artifact.signatureFile); + try { + const signaturePayload = JSON.parse(await readFile(signaturePath, 'utf8')); + const verification = verifyDetachedSignature( + await readFile(artifactPath), + signaturePayload, + options, + ); + if (!verification.ok) { + errors.push({ + type: 'signature-mismatch', + file: artifact.file, + signatureFile: artifact.signatureFile, + reason: verification.reason, + }); + continue; + } + } catch (error) { + errors.push({ + type: 'signature-read-failure', + file: artifact.file, + signatureFile: artifact.signatureFile, + message: error instanceof Error ? error.message : String(error), + }); + continue; + } + } + + verifiedCount += 1; + } + + return { + ok: errors.length === 0, + verifiedCount, + errorCount: errors.length, + errors, + }; +} diff --git a/tools/release-evidence/check-release-doc-freshness.mjs b/tools/release-evidence/check-release-doc-freshness.mjs new file mode 100644 index 0000000..826e2a5 --- /dev/null +++ b/tools/release-evidence/check-release-doc-freshness.mjs @@ -0,0 +1,117 @@ +#!/usr/bin/env node + +import { readFile } from 'node:fs/promises'; +import path from 'node:path'; +import process from 'node:process'; +import { spawnSync } from 'node:child_process'; +import { pathToFileURL } from 'node:url'; + +if (isMain()) { + const args = parseArgs(process.argv.slice(2)); + const repoRoot = process.cwd(); + const reportPath = path.resolve( + repoRoot, + args.reportPath ?? 'docs/release-readiness-report.md', + ); + const reportText = await readFile(reportPath, 'utf8'); + + const expectedBranch = args.expectedBranch ?? resolveCurrentBranch(repoRoot); + const expectedDate = + args.expectedDate ?? new Date().toISOString().slice(0, 10); + const output = checkReleaseDocFreshness({ + reportText, + expectedBranch, + expectedDate, + reportPath: path.relative(repoRoot, reportPath), + }); + + process.stdout.write(`${JSON.stringify(output, null, 2)}\n`); + if (!output.checks.branchMatches || !output.checks.dateMatches) { + process.exitCode = 1; + } +} + +export function checkReleaseDocFreshness({ + reportText, + expectedBranch, + expectedDate, + reportPath = 'docs/release-readiness-report.md', +}) { + const branchMatch = reportText.match(/^Branch:\s*`([^`]+)`/m); + const dateMatch = reportText.match(/^Date:\s*(\d{4}-\d{2}-\d{2})/m); + + if (!branchMatch) { + throw new Error(`missing Branch line in ${reportPath}`); + } + if (!dateMatch) { + throw new Error(`missing Date line in ${reportPath}`); + } + + const actualBranch = branchMatch[1]; + const actualDate = dateMatch[1]; + const checks = { + branchMatches: actualBranch === expectedBranch, + dateMatches: actualDate === expectedDate, + }; + + return { + reportPath, + expected: { + branch: expectedBranch, + date: expectedDate, + }, + actual: { + branch: actualBranch, + date: actualDate, + }, + checks, + }; +} + +function resolveCurrentBranch(cwd) { + const result = spawnSync('git', ['rev-parse', '--abbrev-ref', 'HEAD'], { + cwd, + encoding: 'utf8', + }); + if (result.status !== 0) { + const stderr = result.stderr?.trim() ?? ''; + throw new Error(`unable to resolve current git branch: ${stderr}`); + } + return result.stdout.trim(); +} + +function parseArgs(argv) { + let expectedBranch; + let expectedDate; + let reportPath; + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--') { + continue; + } + if (arg === '--expected-branch') { + expectedBranch = argv[index + 1]; + index += 1; + continue; + } + if (arg === '--expected-date') { + expectedDate = argv[index + 1]; + index += 1; + continue; + } + if (arg === '--report-path') { + reportPath = argv[index + 1]; + index += 1; + continue; + } + throw new Error(`unknown argument: ${arg}`); + } + return { expectedBranch, expectedDate, reportPath }; +} + +function isMain() { + if (!process.argv[1]) { + return false; + } + return import.meta.url === pathToFileURL(process.argv[1]).href; +} diff --git a/tools/release-evidence/check-release-doc-freshness.test.mjs b/tools/release-evidence/check-release-doc-freshness.test.mjs new file mode 100644 index 0000000..881ad48 --- /dev/null +++ b/tools/release-evidence/check-release-doc-freshness.test.mjs @@ -0,0 +1,63 @@ +import assert from 'node:assert/strict'; +import test from 'node:test'; +import { checkReleaseDocFreshness } from './check-release-doc-freshness.mjs'; + +const report = ({ branch = 'feature/readiness', date = '2026-04-30' } = {}) => + [ + '# Release Readiness Report', + '', + `Date: ${date}`, + `Branch: \`${branch}\``, + '', + ].join('\n'); + +test('release readiness freshness passes for the expected branch and date', () => { + const result = checkReleaseDocFreshness({ + reportText: report(), + expectedBranch: 'feature/readiness', + expectedDate: '2026-04-30', + }); + + assert.deepEqual(result.checks, { + branchMatches: true, + dateMatches: true, + }); +}); + +test('release readiness freshness reports stale dates', () => { + const result = checkReleaseDocFreshness({ + reportText: report({ date: '2026-04-29' }), + expectedBranch: 'feature/readiness', + expectedDate: '2026-04-30', + }); + + assert.deepEqual(result.checks, { + branchMatches: true, + dateMatches: false, + }); +}); + +test('release readiness freshness reports branch mismatches', () => { + const result = checkReleaseDocFreshness({ + reportText: report({ branch: 'main' }), + expectedBranch: 'feature/readiness', + expectedDate: '2026-04-30', + }); + + assert.deepEqual(result.checks, { + branchMatches: false, + dateMatches: true, + }); +}); + +test('release readiness freshness rejects missing report dates', () => { + assert.throws( + () => + checkReleaseDocFreshness({ + reportText: 'Branch: `feature/readiness`\n', + expectedBranch: 'feature/readiness', + expectedDate: '2026-04-30', + }), + /missing Date line/, + ); +}); diff --git a/tools/release-evidence/generate-license-report.mjs b/tools/release-evidence/generate-license-report.mjs new file mode 100644 index 0000000..e8c9d6f --- /dev/null +++ b/tools/release-evidence/generate-license-report.mjs @@ -0,0 +1,104 @@ +#!/usr/bin/env node + +import { mkdir, writeFile } from 'node:fs/promises'; +import path from 'node:path'; +import process from 'node:process'; +import { spawnSync } from 'node:child_process'; + +const args = parseArgs(process.argv.slice(2)); +const repoRoot = process.cwd(); +const outDir = path.resolve(repoRoot, args.outDir); +await mkdir(outDir, { recursive: true }); + +const run = spawnSync('pnpm', ['licenses', 'list', '--json'], { + cwd: repoRoot, + encoding: 'utf8', + env: process.env, + stdio: 'pipe', +}); +if (run.status !== 0) { + throw new Error(`license report generation failed: ${run.stderr ?? run.stdout}`); +} + +const parsed = JSON.parse(run.stdout); +const dependencies = []; +if (Array.isArray(parsed)) { + dependencies.push(...parsed); +} else if (parsed && typeof parsed === 'object') { + for (const [license, entries] of Object.entries(parsed)) { + if (!Array.isArray(entries)) { + continue; + } + for (const entry of entries) { + dependencies.push({ + ...entry, + license: entry.license ?? license, + }); + } + } +} + +const counts = new Map(); +for (const entry of dependencies) { + const license = entry.license ?? 'UNKNOWN'; + counts.set(license, (counts.get(license) ?? 0) + 1); +} +const summary = [...counts.entries()] + .map(([license, count]) => ({ license, count })) + .sort((left, right) => right.count - left.count); + +const report = { + generatedAt: new Date().toISOString(), + dependencyCount: dependencies.length, + licenseSummary: summary, + dependencies, +}; + +const jsonPath = path.join(outDir, 'license-report.json'); +const mdPath = path.join(outDir, 'license-report.md'); +await writeFile(jsonPath, `${JSON.stringify(report, null, 2)}\n`, 'utf8'); +await writeFile(mdPath, renderMarkdown(report), 'utf8'); + +process.stdout.write( + `${JSON.stringify( + { + jsonPath: path.relative(repoRoot, jsonPath), + mdPath: path.relative(repoRoot, mdPath), + dependencyCount: dependencies.length, + }, + null, + 2, + )}\n`, +); + +function renderMarkdown(report) { + const lines = [ + '# Dependency license report', + '', + `Generated: ${report.generatedAt}`, + `Dependencies: ${report.dependencyCount}`, + '', + '| License | Count |', + '| --- | ---: |', + ...report.licenseSummary.map((entry) => `| ${entry.license} | ${entry.count} |`), + '', + ]; + return `${lines.join('\n')}\n`; +} + +function parseArgs(argv) { + let outDir = 'artifacts/security'; + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--') { + continue; + } + if (arg === '--out-dir') { + outDir = argv[index + 1] ?? outDir; + index += 1; + continue; + } + throw new Error(`unknown argument: ${arg}`); + } + return { outDir }; +} diff --git a/tools/release-evidence/generate-sbom.mjs b/tools/release-evidence/generate-sbom.mjs new file mode 100644 index 0000000..2df16c0 --- /dev/null +++ b/tools/release-evidence/generate-sbom.mjs @@ -0,0 +1,127 @@ +#!/usr/bin/env node + +import { mkdir } from 'node:fs/promises'; +import path from 'node:path'; +import process from 'node:process'; +import { spawnSync } from 'node:child_process'; +import { writeFile } from 'node:fs/promises'; + +const args = parseArgs(process.argv.slice(2)); +const repoRoot = process.cwd(); +const outDir = path.resolve(repoRoot, args.outDir); +const outputPath = path.join(outDir, 'sbom.cdx.json'); + +await mkdir(outDir, { recursive: true }); + +const run = spawnSync( + 'pnpm', + ['ls', '--json', '--depth', 'Infinity'], + { + cwd: repoRoot, + encoding: 'utf8', + env: process.env, + stdio: 'pipe', + }, +); + +if (run.status !== 0) { + throw new Error(`SBOM generation failed: ${run.stderr || run.stdout}`); +} + +const parsed = JSON.parse(run.stdout); +const roots = Array.isArray(parsed) ? parsed : [parsed]; +const componentMap = new Map(); + +for (const root of roots) { + walkDependencies(root); +} + +const components = [...componentMap.values()].sort((left, right) => + `${left.name}@${left.version}`.localeCompare(`${right.name}@${right.version}`), +); +const sbom = { + bomFormat: 'CycloneDX', + specVersion: '1.5', + version: 1, + metadata: { + timestamp: new Date().toISOString(), + component: { + type: 'application', + name: '@blue-quickjs/source', + version: '0.0.0', + }, + tools: [ + { + vendor: 'blue-quickjs', + name: 'custom-pnpm-sbom-generator', + }, + ], + }, + components, +}; +await writeFile(outputPath, `${JSON.stringify(sbom, null, 2)}\n`, 'utf8'); + +process.stdout.write( + `${JSON.stringify( + { + outputPath: path.relative(repoRoot, outputPath), + componentCount: components.length, + }, + null, + 2, + )}\n`, +); + +function walkDependencies(node) { + if (!node || typeof node !== 'object') { + return; + } + for (const field of [ + 'dependencies', + 'devDependencies', + 'optionalDependencies', + 'peerDependencies', + ]) { + const dependencies = node[field]; + if (!dependencies || typeof dependencies !== 'object') { + continue; + } + for (const [name, dependency] of Object.entries(dependencies)) { + if (!dependency || typeof dependency !== 'object') { + continue; + } + const version = dependency.version ?? '0.0.0'; + const key = `${name}@${version}`; + if (!componentMap.has(key)) { + componentMap.set(key, { + type: 'library', + name, + version, + purl: `pkg:npm/${encodeComponent(name)}@${version}`, + }); + } + walkDependencies(dependency); + } + } +} + +function encodeComponent(name) { + return encodeURIComponent(name).replace('%2F', '/'); +} + +function parseArgs(argv) { + let outDir = 'artifacts/security'; + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--') { + continue; + } + if (arg === '--out-dir') { + outDir = argv[index + 1] ?? outDir; + index += 1; + continue; + } + throw new Error(`unknown argument: ${arg}`); + } + return { outDir }; +} diff --git a/tools/release-evidence/release-evidence.test.mjs b/tools/release-evidence/release-evidence.test.mjs new file mode 100644 index 0000000..30977aa --- /dev/null +++ b/tools/release-evidence/release-evidence.test.mjs @@ -0,0 +1,74 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import { generateKeyPairSync } from 'node:crypto'; +import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'; +import os from 'node:os'; +import path from 'node:path'; +import { + createDetachedSignature, + createManifestEntry, + verifyDetachedSignature, + verifyManifestBundle, + writeSignatureFile, +} from './_lib.mjs'; + +test('digest fallback signatures verify deterministically', async () => { + const payload = Buffer.from('release-evidence'); + const signature = createDetachedSignature(payload); + const verification = verifyDetachedSignature(payload, signature); + assert.equal(verification.ok, true); +}); + +test('ed25519 signatures verify with public key', async () => { + const { privateKey, publicKey } = generateKeyPairSync('ed25519'); + const payload = Buffer.from('consensus-evidence'); + const signature = createDetachedSignature(payload, { + privateKeyPem: privateKey.export({ format: 'pem', type: 'pkcs8' }), + keyId: 'test-key', + }); + const verification = verifyDetachedSignature(payload, signature, { + publicKeyPem: publicKey.export({ format: 'pem', type: 'spki' }), + }); + assert.equal(verification.ok, true); +}); + +test('manifest verification fails when artifact content is tampered', async () => { + const tempDir = await mkdtemp(path.join(os.tmpdir(), 'release-evidence-test-')); + try { + const artifactPath = path.join(tempDir, 'sample.json'); + await writeFile(artifactPath, '{"ok":true}\n', 'utf8'); + + const artifactEntry = await createManifestEntry( + artifactPath, + tempDir, + 'release-evidence', + ); + const signaturePayload = createDetachedSignature( + await readFile(artifactPath), + {}, + ); + const signaturePath = await writeSignatureFile(artifactPath, signaturePayload); + artifactEntry.signatureFile = path.relative(tempDir, signaturePath); + + const manifest = { + version: 1, + generatedAt: new Date().toISOString(), + branch: 'cursor/test', + date: '2026-03-18', + artifacts: [artifactEntry], + }; + + const valid = await verifyManifestBundle(manifest, tempDir, {}); + assert.equal(valid.ok, true); + + await writeFile(artifactPath, '{"ok":false}\n', 'utf8'); + const tampered = await verifyManifestBundle(manifest, tempDir, {}); + assert.equal(tampered.ok, false); + assert.equal( + tampered.errors.some((error) => error.type === 'checksum-mismatch'), + true, + ); + } finally { + await rm(tempDir, { recursive: true, force: true }); + } +}); diff --git a/tools/release-evidence/synthesize-release-evidence.mjs b/tools/release-evidence/synthesize-release-evidence.mjs new file mode 100644 index 0000000..c75db5c --- /dev/null +++ b/tools/release-evidence/synthesize-release-evidence.mjs @@ -0,0 +1,580 @@ +#!/usr/bin/env node + +import { readFile, readdir, stat, writeFile } from 'node:fs/promises'; +import path from 'node:path'; +import process from 'node:process'; +import { spawnSync } from 'node:child_process'; +import { + copyIntoEvidenceDir, + createDetachedSignature, + createManifestEntry, + ensureDir, + loadOptionalText, + writeChecksumFile, + writeSignatureFile, +} from './_lib.mjs'; + +const args = parseArgs(process.argv.slice(2)); +const repoRoot = process.cwd(); +const artifactsRoot = path.resolve(repoRoot, args.artifactsDir); +const outDir = path.resolve(repoRoot, args.outDir); +const inputsDir = path.join(outDir, 'inputs'); + +await ensureDir(outDir); +await ensureDir(inputsDir); + +const branch = args.branch ?? resolveCurrentBranch(repoRoot); +const date = args.date ?? new Date().toISOString().slice(0, 10); +const existingSummaryPath = path.join(outDir, 'release-evidence-summary.json'); +const existingSummary = + args.check && (await pathExists(existingSummaryPath)) + ? JSON.parse(await readFile(existingSummaryPath, 'utf8')) + : null; +const generatedAt = existingSummary?.generatedAt ?? new Date().toISOString(); + +const consensusSource = path.resolve( + repoRoot, + args.consensusReport ?? + (await findNewestFile(artifactsRoot, (entry) => + /^consensus-parity-report-.*\.json$/.test(entry.name), + )), +); +const workloadSource = path.resolve( + repoRoot, + args.workloadReport ?? + (await findNewestFile( + path.join(artifactsRoot, 'workload-certification'), + (entry) => /^workload-certification-.*\.json$/.test(entry.name), + )), +); +const workloadOogSource = path.resolve( + repoRoot, + args.workloadOogReport ?? path.join(artifactsRoot, 'workload-certification', 'oog-boundaries.json'), +); +const consumerSource = path.resolve( + repoRoot, + args.consumerReport ?? 'e2e/consumer-proof-app/reports/reproducibility-report.json', +); +const repeatabilitySource = path.resolve( + repoRoot, + args.repeatabilityReport ?? + path.join(artifactsRoot, 'workload-certification', 'repeatability-report.json'), +); +const seededSource = path.resolve( + repoRoot, + args.seededReport ?? + path.join(artifactsRoot, 'workload-certification', 'seeded-property-corpus-report.json'), +); +const workloadDeltaSource = path.resolve( + repoRoot, + args.workloadDeltaReport ?? + path.join(artifactsRoot, 'workload-certification', 'compatibility-delta-report.json'), +); +const workloadMatrixSource = path.resolve( + repoRoot, + args.workloadMatrixReport ?? + (await findNewestFile( + path.join(artifactsRoot, 'workload-certification'), + (entry) => /^compatibility-matrix-.*\.json$/.test(entry.name), + )), +); +const nativeSource = args.nativeReport + ? path.resolve(repoRoot, args.nativeReport) + : await findNewestFileOptional( + path.join(artifactsRoot, 'reproducibility'), + (entry) => /^parity-report-.*\.json$/.test(entry.name), + ); + +const metadataSource = path.resolve( + repoRoot, + args.metadataPath ?? 'libs/quickjs-wasm-build/dist/quickjs-wasm-build.metadata.json', +); +const metadata = await readOptionalJson(metadataSource); +const signingKeyPem = + (await loadOptionalText(args.signingKeyPath ?? '')) ?? + process.env.RELEASE_EVIDENCE_SIGNING_KEY ?? + null; + +const copiedArtifacts = []; +copiedArtifacts.push( + await copyArtifact(consensusSource, 'consensus-report.json', 'consensus'), +); +copiedArtifacts.push( + await copyArtifact(workloadSource, 'workload-certification.json', 'workload'), +); +copiedArtifacts.push( + await copyArtifact(workloadOogSource, 'workload-oog-boundaries.json', 'workload'), +); +copiedArtifacts.push( + await copyArtifact(workloadMatrixSource, 'workload-compatibility-matrix.json', 'workload'), +); +copiedArtifacts.push( + await copyArtifact(consumerSource, 'consumer-reproducibility.json', 'consumer'), +); + +if (await pathExists(repeatabilitySource)) { + copiedArtifacts.push( + await copyArtifact(repeatabilitySource, 'workload-repeatability.json', 'workload'), + ); +} +if (await pathExists(seededSource)) { + copiedArtifacts.push( + await copyArtifact(seededSource, 'workload-seeded-corpus.json', 'workload'), + ); +} +if (await pathExists(workloadDeltaSource)) { + copiedArtifacts.push( + await copyArtifact(workloadDeltaSource, 'workload-compatibility-delta.json', 'workload'), + ); +} +if (nativeSource && (await pathExists(nativeSource))) { + copiedArtifacts.push( + await copyArtifact(nativeSource, 'native-diagnostic-report.json', 'native'), + ); +} + +const consensus = JSON.parse( + await readFile(path.join(inputsDir, 'consensus-report.json'), 'utf8'), +); +const workload = JSON.parse( + await readFile(path.join(inputsDir, 'workload-certification.json'), 'utf8'), +); +const workloadOog = JSON.parse( + await readFile(path.join(inputsDir, 'workload-oog-boundaries.json'), 'utf8'), +); +const consumer = JSON.parse( + await readFile(path.join(inputsDir, 'consumer-reproducibility.json'), 'utf8'), +); +const workloadDelta = (await pathExists(path.join(inputsDir, 'workload-compatibility-delta.json'))) + ? JSON.parse( + await readFile(path.join(inputsDir, 'workload-compatibility-delta.json'), 'utf8'), + ) + : null; + +const executionProfiles = [ + ...new Set( + (workload.records ?? []) + .map((record) => record.profile) + .filter((value) => typeof value === 'string' && value.length > 0), + ), +].sort(); + +const consensusBoundarySuite = (consensus.suites ?? []).find( + (suite) => suite.name === 'gas-boundary-fixtures', +); +const exactOogParity = + (consensusBoundarySuite?.mismatchCount ?? 0) === 0 && + (workloadOog.mismatchCount ?? 1) === 0 && + Boolean(consumer.parity?.oogEqual); + +const summary = { + generatedAt, + branch, + date, + engineBuildHash: + metadata?.engineBuildHash ?? + metadata?.variants?.wasm32?.release?.engineBuildHash ?? + null, + gasVersion: metadata?.gasVersion ?? null, + executionProfileCoverage: executionProfiles, + fixtureCounts: { + consensus: consensus.fixtureCount ?? 0, + workloadTotal: workload.summary?.total ?? 0, + workloadGreen: workload.summary?.greenCount ?? 0, + workloadRed: workload.summary?.redCount ?? 0, + workloadFlagship: workload.summary?.flagshipCount ?? 0, + }, + mismatchCounts: { + consensus: consensus.mismatchCount ?? 0, + workload: workload.summary?.mismatches ?? 0, + workloadOog: workloadOog.mismatchCount ?? 0, + consumerParity: + consumer.parity?.snapshotEqual && consumer.parity?.oogEqual ? 0 : 1, + }, + compatibilityDelta: workloadDelta + ? { + greenDelta: workloadDelta.deltas?.greenDelta ?? 0, + addedCount: workloadDelta.added?.length ?? 0, + removedCount: workloadDelta.removed?.length ?? 0, + } + : null, + exactOogParity, + consumerParity: { + snapshotEqual: Boolean(consumer.parity?.snapshotEqual), + oogEqual: Boolean(consumer.parity?.oogEqual), + }, +}; + +const summaryJsonPath = path.join(outDir, 'release-evidence-summary.json'); +await writeFile(`${summaryJsonPath}`, `${JSON.stringify(summary, null, 2)}\n`, 'utf8'); +const summaryMarkdown = renderSummaryMarkdown(summary, copiedArtifacts); +const summaryMdPath = path.join(outDir, 'release-evidence-summary.md'); +await writeFile(summaryMdPath, summaryMarkdown, 'utf8'); + +const generatedArtifacts = []; +generatedArtifacts.push( + await finalizeGeneratedArtifact(summaryJsonPath, 'release-evidence', signingKeyPem), +); +generatedArtifacts.push( + await finalizeGeneratedArtifact(summaryMdPath, 'release-evidence', signingKeyPem), +); + +const manifest = { + version: 1, + generatedAt, + branch, + date, + artifacts: [ + ...(await Promise.all( + copiedArtifacts.map(async (artifact) => + createManifestEntry(artifact.path, outDir, artifact.category), + ), + )), + ...(await Promise.all( + generatedArtifacts.map(async (artifact) => { + const baseEntry = await createManifestEntry( + artifact.path, + outDir, + artifact.category, + ); + return { + ...baseEntry, + checksumFile: path.relative(outDir, artifact.checksumPath), + signatureFile: path.relative(outDir, artifact.signaturePath), + }; + }), + )), + ], +}; + +const manifestPath = path.join(outDir, 'release-evidence-manifest.json'); +await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, 'utf8'); +const manifestChecksumPath = await writeChecksumFile(manifestPath); +const manifestSignaturePath = await writeSignatureFile( + manifestPath, + createDetachedSignature(await readFile(manifestPath), { + privateKeyPem: signingKeyPem, + keyId: args.signingKeyId ?? 'release-evidence-manifest', + }), +); + +const docsPath = path.resolve(repoRoot, args.docsPath ?? 'docs/release-readiness-report.md'); +const generatedDocs = renderReleaseReadinessDoc(summary, manifest, outDir); +if (args.check) { + const existing = await readFile(docsPath, 'utf8'); + if (existing !== generatedDocs) { + throw new Error( + `${path.relative(repoRoot, docsPath)} is stale; run synthesize-release-evidence without --check`, + ); + } +} else if (!args.skipDocs) { + await writeFile(docsPath, generatedDocs, 'utf8'); +} + +process.stdout.write( + `${JSON.stringify( + { + outDir, + summaryJsonPath: path.relative(repoRoot, summaryJsonPath), + summaryMdPath: path.relative(repoRoot, summaryMdPath), + manifestPath: path.relative(repoRoot, manifestPath), + manifestChecksumPath: path.relative(repoRoot, manifestChecksumPath), + manifestSignaturePath: path.relative(repoRoot, manifestSignaturePath), + docsPath: path.relative(repoRoot, docsPath), + exactOogParity, + }, + null, + 2, + )}\n`, +); + +async function copyArtifact(sourcePath, targetName, category) { + if (!(await pathExists(sourcePath))) { + throw new Error(`required evidence source is missing: ${sourcePath}`); + } + const destination = await copyIntoEvidenceDir(sourcePath, inputsDir, targetName); + return { category, path: destination }; +} + +async function finalizeGeneratedArtifact(filePath, category, signingKeyPem) { + const checksumPath = await writeChecksumFile(filePath); + const signaturePayload = createDetachedSignature(await readFile(filePath), { + privateKeyPem: signingKeyPem, + keyId: args.signingKeyId ?? 'release-evidence', + }); + const signaturePath = await writeSignatureFile(filePath, signaturePayload); + return { + category, + path: filePath, + checksumPath, + signaturePath, + }; +} + +function renderSummaryMarkdown(summary, copiedArtifacts) { + const lines = [ + '# Release Evidence Summary (Generated)', + '', + `Generated at: ${summary.generatedAt}`, + `Branch: \`${summary.branch}\``, + `Date: ${summary.date}`, + '', + `- engineBuildHash: \`${summary.engineBuildHash ?? 'n/a'}\``, + `- gasVersion: \`${summary.gasVersion ?? 'n/a'}\``, + `- exact OOG parity: **${summary.exactOogParity ? 'pass' : 'fail'}**`, + '', + '## Coverage', + '', + `- execution profiles: ${summary.executionProfileCoverage.length > 0 ? summary.executionProfileCoverage.map((entry) => `\`${entry}\``).join(', ') : 'n/a'}`, + `- consensus fixtures: ${summary.fixtureCounts.consensus}`, + `- workload fixtures: ${summary.fixtureCounts.workloadTotal} (green ${summary.fixtureCounts.workloadGreen} / red ${summary.fixtureCounts.workloadRed} / flagship ${summary.fixtureCounts.workloadFlagship})`, + '', + '## Mismatches', + '', + `- consensus mismatches: ${summary.mismatchCounts.consensus}`, + `- workload mismatches: ${summary.mismatchCounts.workload}`, + `- workload OOG mismatches: ${summary.mismatchCounts.workloadOog}`, + `- consumer parity mismatches: ${summary.mismatchCounts.consumerParity}`, + `- compatibility green delta: ${summary.compatibilityDelta?.greenDelta ?? 'n/a'}`, + '', + '## Included source evidence files', + '', + '| Category | File |', + '| --- | --- |', + ]; + for (const artifact of copiedArtifacts) { + lines.push(`| ${artifact.category} | \`${path.basename(artifact.path)}\` |`); + } + return `${lines.join('\n')}\n`; +} + +function renderReleaseReadinessDoc(summary, manifest, evidenceDir) { + const lines = [ + '# Release-readiness report (current branch snapshot)', + '', + `Date: ${summary.date}`, + `Branch: \`${summary.branch}\``, + '', + '> This file is generated by `node tools/release-evidence/synthesize-release-evidence.mjs`.', + '', + '## Environment', + '', + `- engineBuildHash: \`${summary.engineBuildHash ?? 'n/a'}\``, + `- gasVersion: \`${summary.gasVersion ?? 'n/a'}\``, + '', + '## Consensus-safe vs diagnostic-only', + '', + '### Consensus-safe (release gate)', + '', + '- Executor pair: `wasm-node` vs `wasm-browser` (`wasm32` release artifacts).', + '- Gate requirements: exact value/error parity, exact gas parity, exact tape parity, exact OOG boundary parity.', + `- Consensus mismatch count: \`${summary.mismatchCounts.consensus}\``, + '', + '### Diagnostic-only', + '', + '- Native parity remains diagnostic-only unless explicitly promoted by release policy.', + '', + '## Certification and parity snapshot', + '', + `- Workload totals: \`${summary.fixtureCounts.workloadTotal}\` fixtures (\`${summary.fixtureCounts.workloadGreen}\` green / \`${summary.fixtureCounts.workloadRed}\` red / \`${summary.fixtureCounts.workloadFlagship}\` flagship)`, + `- Workload mismatch count: \`${summary.mismatchCounts.workload}\``, + `- Workload OOG mismatch count: \`${summary.mismatchCounts.workloadOog}\``, + `- Compatibility green delta vs baseline: \`${summary.compatibilityDelta?.greenDelta ?? 'n/a'}\``, + `- Consumer snapshot parity: \`${summary.consumerParity.snapshotEqual}\``, + `- Consumer OOG parity: \`${summary.consumerParity.oogEqual}\``, + `- Exact OOG parity status: \`${summary.exactOogParity}\``, + '', + '## Evidence manifest', + '', + `- Manifest file: \`${path.relative(process.cwd(), path.join(evidenceDir, 'release-evidence-manifest.json'))}\``, + `- Manifest artifact entries: \`${manifest.artifacts.length}\``, + '', + '## Included artifacts', + '', + '| Category | File | SHA256 |', + '| --- | --- | --- |', + ]; + for (const artifact of manifest.artifacts) { + lines.push(`| ${artifact.category} | \`${artifact.file}\` | \`${artifact.sha256}\` |`); + } + return `${lines.join('\n')}\n`; +} + +async function findNewestFile(rootDir, predicate) { + const found = await findNewestFileOptional(rootDir, predicate); + if (!found) { + throw new Error(`no matching files under ${rootDir}`); + } + return found; +} + +async function findNewestFileOptional(rootDir, predicate) { + if (!(await pathExists(rootDir))) { + return null; + } + const files = await walkFiles(rootDir); + let latest = null; + for (const file of files) { + if (!predicate({ name: path.basename(file), path: file })) { + continue; + } + const fileStat = await stat(file); + if (!latest || fileStat.mtimeMs > latest.mtimeMs) { + latest = { file, mtimeMs: fileStat.mtimeMs }; + } + } + return latest?.file ?? null; +} + +async function walkFiles(rootDir) { + const entries = await readdir(rootDir, { withFileTypes: true }); + const files = []; + for (const entry of entries) { + const fullPath = path.join(rootDir, entry.name); + if (entry.isDirectory()) { + files.push(...(await walkFiles(fullPath))); + } else { + files.push(fullPath); + } + } + return files; +} + +async function readOptionalJson(filePath) { + if (!(await pathExists(filePath))) { + return null; + } + return JSON.parse(await readFile(filePath, 'utf8')); +} + +async function pathExists(targetPath) { + try { + await stat(targetPath); + return true; + } catch { + return false; + } +} + +function resolveCurrentBranch(cwd) { + const result = spawnSync('git', ['rev-parse', '--abbrev-ref', 'HEAD'], { + cwd, + encoding: 'utf8', + }); + if (result.status !== 0) { + throw new Error(`unable to resolve current branch: ${result.stderr?.trim() ?? ''}`); + } + return result.stdout.trim(); +} + +function parseArgs(argv) { + const parsed = { + artifactsDir: 'artifacts', + outDir: 'artifacts/release-evidence', + docsPath: 'docs/release-readiness-report.md', + check: false, + skipDocs: false, + }; + + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--') { + continue; + } + if (arg === '--artifacts-dir') { + parsed.artifactsDir = argv[index + 1] ?? parsed.artifactsDir; + index += 1; + continue; + } + if (arg === '--out-dir') { + parsed.outDir = argv[index + 1] ?? parsed.outDir; + index += 1; + continue; + } + if (arg === '--docs-path') { + parsed.docsPath = argv[index + 1] ?? parsed.docsPath; + index += 1; + continue; + } + if (arg === '--consensus-report') { + parsed.consensusReport = argv[index + 1]; + index += 1; + continue; + } + if (arg === '--workload-report') { + parsed.workloadReport = argv[index + 1]; + index += 1; + continue; + } + if (arg === '--workload-oog-report') { + parsed.workloadOogReport = argv[index + 1]; + index += 1; + continue; + } + if (arg === '--workload-matrix-report') { + parsed.workloadMatrixReport = argv[index + 1]; + index += 1; + continue; + } + if (arg === '--consumer-report') { + parsed.consumerReport = argv[index + 1]; + index += 1; + continue; + } + if (arg === '--repeatability-report') { + parsed.repeatabilityReport = argv[index + 1]; + index += 1; + continue; + } + if (arg === '--seeded-report') { + parsed.seededReport = argv[index + 1]; + index += 1; + continue; + } + if (arg === '--workload-delta-report') { + parsed.workloadDeltaReport = argv[index + 1]; + index += 1; + continue; + } + if (arg === '--native-report') { + parsed.nativeReport = argv[index + 1]; + index += 1; + continue; + } + if (arg === '--metadata-path') { + parsed.metadataPath = argv[index + 1]; + index += 1; + continue; + } + if (arg === '--signing-key-path') { + parsed.signingKeyPath = argv[index + 1]; + index += 1; + continue; + } + if (arg === '--signing-key-id') { + parsed.signingKeyId = argv[index + 1]; + index += 1; + continue; + } + if (arg === '--branch') { + parsed.branch = argv[index + 1]; + index += 1; + continue; + } + if (arg === '--date') { + parsed.date = argv[index + 1]; + index += 1; + continue; + } + if (arg === '--check') { + parsed.check = true; + continue; + } + if (arg === '--skip-docs') { + parsed.skipDocs = true; + continue; + } + throw new Error(`unknown argument: ${arg}`); + } + return parsed; +} diff --git a/tools/release-evidence/verify-release-evidence.mjs b/tools/release-evidence/verify-release-evidence.mjs new file mode 100644 index 0000000..a34b80f --- /dev/null +++ b/tools/release-evidence/verify-release-evidence.mjs @@ -0,0 +1,111 @@ +#!/usr/bin/env node + +import { readFile } from 'node:fs/promises'; +import path from 'node:path'; +import process from 'node:process'; +import { spawnSync } from 'node:child_process'; +import { loadOptionalText, verifyManifestBundle } from './_lib.mjs'; + +const args = parseArgs(process.argv.slice(2)); +const repoRoot = process.cwd(); +const evidenceDir = path.resolve(repoRoot, args.evidenceDir); +const manifestPath = path.resolve( + evidenceDir, + args.manifestPath ?? 'release-evidence-manifest.json', +); +const manifest = JSON.parse(await readFile(manifestPath, 'utf8')); + +const publicKeyPem = + (await loadOptionalText(args.publicKeyPath ?? '')) ?? + process.env.RELEASE_EVIDENCE_PUBLIC_KEY ?? + null; + +const verification = await verifyManifestBundle(manifest, evidenceDir, { + publicKeyPem, +}); + +const branchCheck = buildBranchCheck(manifest.branch, args.expectedBranch); +const dateCheck = buildDateCheck(manifest.date, args.expectedDate); + +const output = { + evidenceDir, + manifestPath: path.relative(repoRoot, manifestPath), + artifactCount: manifest.artifacts.length, + verification, + branchCheck, + dateCheck, +}; + +process.stdout.write(`${JSON.stringify(output, null, 2)}\n`); + +if (!verification.ok || !branchCheck.ok || !dateCheck.ok) { + process.exitCode = 1; +} + +function buildBranchCheck(actual, expectedBranchArg) { + const expectedBranch = expectedBranchArg ?? resolveCurrentBranch(process.cwd()); + return { + expected: expectedBranch, + actual, + ok: actual === expectedBranch, + }; +} + +function buildDateCheck(actual, expectedDateArg) { + const expectedDate = expectedDateArg ?? new Date().toISOString().slice(0, 10); + return { + expected: expectedDate, + actual, + ok: actual === expectedDate, + }; +} + +function resolveCurrentBranch(cwd) { + const result = spawnSync('git', ['rev-parse', '--abbrev-ref', 'HEAD'], { + cwd, + encoding: 'utf8', + }); + if (result.status !== 0) { + return null; + } + return result.stdout.trim(); +} + +function parseArgs(argv) { + const parsed = { + evidenceDir: 'artifacts/release-evidence', + }; + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--') { + continue; + } + if (arg === '--evidence-dir') { + parsed.evidenceDir = argv[index + 1] ?? parsed.evidenceDir; + index += 1; + continue; + } + if (arg === '--manifest-path') { + parsed.manifestPath = argv[index + 1]; + index += 1; + continue; + } + if (arg === '--public-key-path') { + parsed.publicKeyPath = argv[index + 1]; + index += 1; + continue; + } + if (arg === '--expected-branch') { + parsed.expectedBranch = argv[index + 1]; + index += 1; + continue; + } + if (arg === '--expected-date') { + parsed.expectedDate = argv[index + 1]; + index += 1; + continue; + } + throw new Error(`unknown argument: ${arg}`); + } + return parsed; +} diff --git a/tools/scripts/check-quickjs-source-prep.sh b/tools/scripts/check-quickjs-source-prep.sh new file mode 100755 index 0000000..067cda6 --- /dev/null +++ b/tools/scripts/check-quickjs-source-prep.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd -- "${SCRIPT_DIR}/../.." && pwd)" + +cd "${REPO_ROOT}" + +bash tools/scripts/prepare-quickjs-source.sh + +node -e ' + const fs = require("fs"); + const manifest = JSON.parse( + fs.readFileSync("vendor/quickjs-patches/manifest.json", "utf8"), + ); + const stamp = JSON.parse( + fs.readFileSync("vendor/quickjs/.blue-quickjs-source.json", "utf8"), + ); + const expected = { + baseCommit: manifest.baseCommit, + headCommit: manifest.headCommit, + patchCount: manifest.patchCount, + baseArchive: manifest.baseArchive ?? null, + baseArchiveSha256: manifest.baseArchiveSha256 ?? null, + }; + const mismatches = Object.entries(expected).filter( + ([key, value]) => stamp[key] !== value, + ); + if (mismatches.length > 0) { + console.error( + JSON.stringify( + { + ok: false, + mismatches, + expected, + actual: stamp, + }, + null, + 2, + ), + ); + process.exit(1); + } + console.log( + JSON.stringify( + { + ok: true, + sourceStamp: "vendor/quickjs/.blue-quickjs-source.json", + baseArchive: stamp.baseArchive, + patchCount: stamp.patchCount, + }, + null, + 2, + ), + ); +' diff --git a/tools/scripts/check-ts-project-references.mjs b/tools/scripts/check-ts-project-references.mjs new file mode 100644 index 0000000..4b348bd --- /dev/null +++ b/tools/scripts/check-ts-project-references.mjs @@ -0,0 +1,209 @@ +#!/usr/bin/env node + +import { readdir, readFile, stat } from 'node:fs/promises'; +import path from 'node:path'; +import process from 'node:process'; +import { pathToFileURL } from 'node:url'; + +const BLUE_PACKAGE_PREFIX = '@blue-quickjs/'; +const SOURCE_FILE_EXTENSIONS = new Set(['.ts', '.tsx', '.mts']); +const TEST_FILE_PATTERN = /\.(spec|test)\.[cm]?[tj]sx?$/; +const TEST_DIRECTORY_NAMES = new Set(['test', 'tests']); +const IMPORT_PATTERN = + /(?:import|export)\s+(?:type\s+)?(?:[^'"]*?\s+from\s+)?['"](@blue-quickjs\/[^'"]+)['"]|import\(\s*['"](@blue-quickjs\/[^'"]+)['"]\s*\)/g; + +if (isMain()) { + const result = await checkTsProjectReferences(process.cwd()); + process.stdout.write(`${JSON.stringify(result, null, 2)}\n`); + if (!result.checks.referencesComplete) { + process.exitCode = 1; + } +} + +export async function checkTsProjectReferences(repoRoot) { + const workspacePackages = await discoverWorkspacePackages(repoRoot); + const packageByName = new Map( + workspacePackages.map((entry) => [entry.packageName, entry]), + ); + const projects = await discoverTsProjects(repoRoot, workspacePackages); + const missingReferences = []; + + for (const project of projects) { + const imports = await collectWorkspaceImports(project); + const references = new Set( + project.references.map((referencePath) => + normalizePath(path.resolve(project.root, referencePath)), + ), + ); + + for (const [packageName, importedBy] of imports) { + const dependency = packageByName.get(packageName); + if (!dependency || dependency.root === project.root || !dependency.tsconfigLibPath) { + continue; + } + + const expectedReference = normalizePath(dependency.tsconfigLibPath); + if (references.has(expectedReference)) { + continue; + } + + missingReferences.push({ + project: project.name, + tsconfig: path.relative(repoRoot, project.tsconfigPath), + import: packageName, + expectedReference: path.relative(repoRoot, dependency.tsconfigLibPath), + importedBy: importedBy.map((filePath) => path.relative(repoRoot, filePath)).sort(), + }); + } + } + + return { + checks: { + referencesComplete: missingReferences.length === 0, + }, + projectCount: projects.length, + missingReferenceCount: missingReferences.length, + missingReferences, + }; +} + +async function discoverWorkspacePackages(repoRoot) { + const packages = []; + for (const scope of ['apps', 'libs', 'tools']) { + const scopeDir = path.join(repoRoot, scope); + for (const entry of await readDirIfExists(scopeDir)) { + if (!entry.isDirectory()) { + continue; + } + const root = path.join(scopeDir, entry.name); + const packageJsonPath = path.join(root, 'package.json'); + const packageJson = await readJsonIfExists(packageJsonPath); + if (!packageJson || typeof packageJson.name !== 'string') { + continue; + } + const tsconfigLibPath = await existingPath( + path.join(root, 'tsconfig.lib.json'), + ); + packages.push({ + packageName: packageJson.name, + projectName: packageJson.nx?.name ?? entry.name, + root, + tsconfigLibPath, + }); + } + } + return packages; +} + +async function discoverTsProjects(repoRoot, workspacePackages) { + const projects = []; + for (const workspacePackage of workspacePackages) { + for (const tsconfigName of ['tsconfig.lib.json', 'tsconfig.app.json']) { + const tsconfigPath = path.join(workspacePackage.root, tsconfigName); + const tsconfig = await readJsonIfExists(tsconfigPath); + if (!tsconfig) { + continue; + } + projects.push({ + name: workspacePackage.projectName, + root: workspacePackage.root, + tsconfigPath, + references: (tsconfig.references ?? []) + .map((reference) => reference?.path) + .filter((referencePath) => typeof referencePath === 'string'), + sourceDir: path.join(workspacePackage.root, 'src'), + repoRoot, + }); + } + } + return projects; +} + +async function collectWorkspaceImports(project) { + const imports = new Map(); + for (const filePath of await walkSourceFiles(project.sourceDir)) { + const text = await readFile(filePath, 'utf8'); + for (const packageName of extractWorkspaceImports(text)) { + const importedBy = imports.get(packageName) ?? []; + importedBy.push(filePath); + imports.set(packageName, importedBy); + } + } + return imports; +} + +function extractWorkspaceImports(text) { + const imports = new Set(); + for (const match of text.matchAll(IMPORT_PATTERN)) { + const specifier = match[1] ?? match[2]; + if (!specifier?.startsWith(BLUE_PACKAGE_PREFIX)) { + continue; + } + const [, scope, name] = specifier.match(/^(@blue-quickjs)\/([^/]+)/) ?? []; + if (scope && name) { + imports.add(`${scope}/${name}`); + } + } + return imports; +} + +async function walkSourceFiles(rootDir) { + const files = []; + for (const entry of await readDirIfExists(rootDir)) { + const fullPath = path.join(rootDir, entry.name); + if (entry.isDirectory()) { + if (TEST_DIRECTORY_NAMES.has(entry.name)) { + continue; + } + files.push(...(await walkSourceFiles(fullPath))); + continue; + } + if (!entry.isFile()) { + continue; + } + if (!SOURCE_FILE_EXTENSIONS.has(path.extname(entry.name))) { + continue; + } + if (TEST_FILE_PATTERN.test(entry.name)) { + continue; + } + files.push(fullPath); + } + return files; +} + +async function readDirIfExists(dirPath) { + try { + return await readdir(dirPath, { withFileTypes: true }); + } catch { + return []; + } +} + +async function readJsonIfExists(filePath) { + try { + return JSON.parse(await readFile(filePath, 'utf8')); + } catch { + return null; + } +} + +async function existingPath(filePath) { + try { + await stat(filePath); + return filePath; + } catch { + return null; + } +} + +function normalizePath(filePath) { + return path.normalize(filePath); +} + +function isMain() { + if (!process.argv[1]) { + return false; + } + return import.meta.url === pathToFileURL(process.argv[1]).href; +} diff --git a/tools/scripts/check-ts-project-references.test.mjs b/tools/scripts/check-ts-project-references.test.mjs new file mode 100644 index 0000000..569c39f --- /dev/null +++ b/tools/scripts/check-ts-project-references.test.mjs @@ -0,0 +1,103 @@ +import assert from 'node:assert/strict'; +import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises'; +import os from 'node:os'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import test from 'node:test'; +import { checkTsProjectReferences } from './check-ts-project-references.mjs'; + +const repoRoot = path.resolve( + path.dirname(fileURLToPath(import.meta.url)), + '../..', +); + +test('production workspace imports are covered by TypeScript project references', async () => { + const result = await checkTsProjectReferences(repoRoot); + + assert.equal(result.checks.referencesComplete, true); + assert.deepEqual(result.missingReferences, []); +}); + +test('src/test helpers do not force production TypeScript project references', async () => { + const fixtureRoot = await createProjectReferenceFixture({ + consumerFiles: { + 'src/test/helper.ts': + "import { value } from '@blue-quickjs/dependency';\nexport { value };\n", + }, + }); + + try { + const result = await checkTsProjectReferences(fixtureRoot); + + assert.equal(result.checks.referencesComplete, true); + assert.deepEqual(result.missingReferences, []); + } finally { + await rm(fixtureRoot, { recursive: true, force: true }); + } +}); + +test('production files still require TypeScript project references', async () => { + const fixtureRoot = await createProjectReferenceFixture({ + consumerFiles: { + 'src/lib/production-file.ts': + "import { value } from '@blue-quickjs/dependency';\nexport { value };\n", + }, + }); + + try { + const result = await checkTsProjectReferences(fixtureRoot); + + assert.equal(result.checks.referencesComplete, false); + assert.equal(result.missingReferences.length, 1); + assert.equal(result.missingReferences[0].project, 'consumer'); + assert.equal(result.missingReferences[0].import, '@blue-quickjs/dependency'); + assert.deepEqual(result.missingReferences[0].importedBy, [ + 'libs/consumer/src/lib/production-file.ts', + ]); + } finally { + await rm(fixtureRoot, { recursive: true, force: true }); + } +}); + +async function createProjectReferenceFixture({ consumerFiles }) { + const fixtureRoot = await mkdtemp( + path.join(os.tmpdir(), 'blue-quickjs-project-refs-'), + ); + const consumerRoot = path.join(fixtureRoot, 'libs/consumer'); + const dependencyRoot = path.join(fixtureRoot, 'libs/dependency'); + + await writeJson(path.join(consumerRoot, 'package.json'), { + name: '@blue-quickjs/consumer', + nx: { name: 'consumer' }, + }); + await writeJson(path.join(consumerRoot, 'tsconfig.lib.json'), { + references: [], + }); + await writeJson(path.join(dependencyRoot, 'package.json'), { + name: '@blue-quickjs/dependency', + nx: { name: 'dependency' }, + }); + await writeJson(path.join(dependencyRoot, 'tsconfig.lib.json'), { + references: [], + }); + await writeText( + path.join(dependencyRoot, 'src/index.ts'), + 'export const value = 1;\n', + ); + + for (const [relativePath, content] of Object.entries(consumerFiles)) { + await writeText(path.join(consumerRoot, relativePath), content); + } + + return fixtureRoot; +} + +async function writeJson(filePath, value) { + await mkdir(path.dirname(filePath), { recursive: true }); + await writeFile(filePath, `${JSON.stringify(value, null, 2)}\n`, 'utf8'); +} + +async function writeText(filePath, content) { + await mkdir(path.dirname(filePath), { recursive: true }); + await writeFile(filePath, content, 'utf8'); +} diff --git a/tools/scripts/doctor.sh b/tools/scripts/doctor.sh new file mode 100644 index 0000000..43419ad --- /dev/null +++ b/tools/scripts/doctor.sh @@ -0,0 +1,160 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +cd "$ROOT" + +failures=0 + +info() { + echo "➡️ $1" +} + +pass() { + echo "✅ $1" +} + +warn() { + echo "⚠️ $1" +} + +fail() { + echo "❌ $1" + failures=$((failures + 1)) +} + +check_cmd() { + local cmd="$1" + local label="$2" + + if command -v "$cmd" >/dev/null 2>&1; then + local version + version="$("$cmd" --version 2>/dev/null | head -n 1 || true)" + if [ -n "$version" ]; then + pass "$label: $version" + else + pass "$label is installed" + fi + else + fail "$label is not installed" + fi +} + +echo "🩺 Repo doctor" +echo + +info "Checking required commands" +check_cmd git "git" +check_cmd node "node" +check_cmd pnpm "pnpm" +check_cmd bash "bash" + +echo +info "Checking repository layout" + +if [ -f "$ROOT/package.json" ]; then + pass "package.json found" +else + fail "package.json missing at repo root" +fi + +if [ -d "$ROOT/vendor/quickjs-patches/series" ]; then + pass "vendor/quickjs patch series found" +else + fail "vendor/quickjs patch series missing" +fi + +if [ -f "$ROOT/vendor/quickjs-patches/manifest.json" ]; then + pass "QuickJS patch manifest found" +else + fail "QuickJS patch manifest missing" +fi + +if [ -f "$ROOT/vendor/quickjs/.blue-quickjs-source.json" ]; then + pass "vendor/quickjs prepared from patch series" +elif [ -d "$ROOT/vendor/quickjs" ]; then + warn "vendor/quickjs exists but is not marked as generated; run: bash tools/scripts/prepare-quickjs-source.sh" +else + warn "vendor/quickjs missing; run: bash tools/scripts/prepare-quickjs-source.sh" +fi + +if [ -f "$ROOT/tools/scripts/setup-emsdk.sh" ]; then + pass "setup-emsdk.sh found" +else + fail "tools/scripts/setup-emsdk.sh missing" +fi + +if [ -f "$ROOT/tools/emsdk/emsdk_env.sh" ]; then + pass "emsdk env script found" +else + fail "tools/emsdk/emsdk_env.sh missing; run: pnpm setup" +fi + +echo +info "Checking Node workspace state" + +if [ -d "$ROOT/node_modules" ]; then + pass "node_modules present" +else + fail "node_modules missing; run: pnpm install" +fi + +echo +info "Checking Playwright Chromium" + +if pnpm exec playwright --version >/dev/null 2>&1; then + pass "Playwright CLI available" +else + fail "Playwright CLI unavailable; run: pnpm install" +fi + +PLAYWRIGHT_BROWSERS_PATH="${PLAYWRIGHT_BROWSERS_PATH:-$HOME/.cache/ms-playwright}" +if [ -d "$PLAYWRIGHT_BROWSERS_PATH" ] && find "$PLAYWRIGHT_BROWSERS_PATH" -maxdepth 1 -iname "*chromium*" | grep -q .; then + pass "Chromium browser appears installed" +else + warn "Chromium browser not detected in cache; run: pnpm exec playwright install --with-deps chromium" +fi + +echo +info "Checking Emscripten toolchain" + +EMSDK_ENV="$ROOT/tools/emsdk/emsdk_env.sh" +if [ -f "$EMSDK_ENV" ]; then + # shellcheck disable=SC1090 + source "$EMSDK_ENV" >/dev/null + + if command -v emcc >/dev/null 2>&1; then + pass "emcc available: $(emcc --version 2>/dev/null | head -n 1)" + else + fail "emcc not available after sourcing emsdk_env.sh" + fi + + if command -v em++ >/dev/null 2>&1; then + pass "em++ available" + else + fail "em++ not available after sourcing emsdk_env.sh" + fi +fi + +echo +info "Checking project scripts" + +if [ -f "$ROOT/apps/bluequickjs-playground/scripts/dev.sh" ]; then + pass "playground script found" +else + fail "playground script missing" +fi + +if [ -d "$ROOT/e2e/consumer-proof-app" ]; then + pass "consumer proof app found" +else + warn "consumer proof app directory missing" +fi + +echo +if [ "$failures" -eq 0 ]; then + echo "🎉 Doctor finished: no blocking issues found." +else + echo "🚨 Doctor finished: $failures blocking issue(s) found." + exit 1 +fi diff --git a/tools/scripts/evidence-verify.sh b/tools/scripts/evidence-verify.sh new file mode 100644 index 0000000..527bee5 --- /dev/null +++ b/tools/scripts/evidence-verify.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +cd "$ROOT" + +step() { + echo "➡️ $1" +} + +ok() { + echo "✅ $1" +} + +fail() { + echo "❌ $1" >&2 + exit 1 +} + +EVIDENCE_DIR="artifacts/release-evidence" + +if [ ! -d "$EVIDENCE_DIR" ]; then + fail "Missing $EVIDENCE_DIR. Run: pnpm evidence" +fi + +step "Verifying release evidence bundle" +pnpm release-evidence:verify -- --evidence-dir "$EVIDENCE_DIR" +ok "Release evidence bundle verified" + +echo +echo "🎉 Evidence verification complete!" +echo +echo "Verified:" +echo " - $EVIDENCE_DIR" \ No newline at end of file diff --git a/tools/scripts/evidence.sh b/tools/scripts/evidence.sh new file mode 100644 index 0000000..9db17c5 --- /dev/null +++ b/tools/scripts/evidence.sh @@ -0,0 +1,82 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +cd "$ROOT" + +step() { + echo "➡️ $1" +} + +ok() { + echo "✅ $1" +} + +fail() { + echo "❌ $1" >&2 + exit 1 +} + +EMSDK_ENV="$ROOT/tools/emsdk/emsdk_env.sh" + +if [ ! -f "$EMSDK_ENV" ]; then + fail "Missing $EMSDK_ENV. Run: pnpm setup" +fi + +step "Loading Emscripten environment" +# shellcheck disable=SC1090 +source "$EMSDK_ENV" >/dev/null +ok "Emscripten environment loaded" + +step "Preparing artifact directories" +mkdir -p \ + artifacts/reproducibility-consensus \ + artifacts/workload-certification \ + artifacts/consumer-proof/tarballs \ + artifacts/release-evidence +ok "Artifact directories ready" + +step "Generating consensus reproducibility report" +node tools/consensus-parity/scripts/archive-consensus-reproducibility-report.mjs \ + --out-dir artifacts/reproducibility-consensus +ok "Consensus reproducibility report generated" + +step "Generating workload certification report" +node apps/ecosystem-certifier/scripts/archive-workload-certification-report.mjs \ + --out-dir artifacts/workload-certification +ok "Workload certification report generated" + +step "Running OOG boundary certification" +node apps/ecosystem-certifier/scripts/run-oog-boundary-certification.mjs \ + --out-dir artifacts/workload-certification +ok "OOG boundary certification generated" + +step "Packing public tarballs" +node tools/workload-certification/pack-public-tarballs.mjs \ + --out-dir artifacts/consumer-proof/tarballs +ok "Public tarballs packed" + +step "Installing tarballs into consumer proof app" +pnpm --dir e2e/consumer-proof-app run install:tarballs \ + -- --tarball-dir ../../artifacts/consumer-proof/tarballs +ok "Consumer proof app tarballs installed" + +step "Running consumer proof reproducibility check" +pnpm --dir e2e/consumer-proof-app run repro +ok "Consumer proof reproducibility check passed" + +step "Synthesizing release evidence bundle" +pnpm release-evidence:synthesize -- --out-dir artifacts/release-evidence +ok "Release evidence bundle synthesized" + +echo +echo "🎉 Evidence generation complete!" +echo +echo "Artifacts:" +echo " - artifacts/reproducibility-consensus" +echo " - artifacts/workload-certification" +echo " - artifacts/consumer-proof/tarballs" +echo " - artifacts/release-evidence" +echo +echo "Next step:" +echo " pnpm evidence:verify" diff --git a/tools/scripts/playground.sh b/tools/scripts/playground.sh new file mode 100644 index 0000000..13e8876 --- /dev/null +++ b/tools/scripts/playground.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +cd "$ROOT" + +step() { + echo "➡️ $1" +} + +ok() { + echo "✅ $1" +} + +fail() { + echo "❌ $1" >&2 + exit 1 +} + +EMSDK_ENV="$ROOT/tools/emsdk/emsdk_env.sh" +PLAYGROUND_SCRIPT="$ROOT/apps/bluequickjs-playground/scripts/dev.sh" + +if [ ! -f "$EMSDK_ENV" ]; then + fail "Emscripten SDK not found. Run: pnpm setup" +fi + +if [ ! -f "$PLAYGROUND_SCRIPT" ]; then + fail "Playground script not found at $PLAYGROUND_SCRIPT" +fi + +step "Loading Emscripten environment" +source "$EMSDK_ENV" >/dev/null +ok "Emscripten ready" + +step "Starting playground" +echo + +exec bash "$PLAYGROUND_SCRIPT" \ No newline at end of file diff --git a/tools/scripts/prepare-quickjs-source.sh b/tools/scripts/prepare-quickjs-source.sh new file mode 100755 index 0000000..82c4e58 --- /dev/null +++ b/tools/scripts/prepare-quickjs-source.sh @@ -0,0 +1,247 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd -- "${SCRIPT_DIR}/../.." && pwd)" + +MANIFEST_PATH="${REPO_ROOT}/vendor/quickjs-patches/manifest.json" +TARGET_DIR="${REPO_ROOT}/vendor/quickjs" +CACHE_DIR="${REPO_ROOT}/vendor/.quickjs-cache" +CACHE_REPO="${CACHE_DIR}/upstream.git" +STAMP_FILE="${TARGET_DIR}/.blue-quickjs-source.json" +LOCK_DIR="${REPO_ROOT}/vendor/.quickjs-lock" + +if [[ ! -f "${MANIFEST_PATH}" ]]; then + echo "QuickJS patch manifest not found at ${MANIFEST_PATH}" >&2 + exit 1 +fi + +if ! command -v git >/dev/null 2>&1; then + echo "git is required to prepare vendor/quickjs" >&2 + exit 1 +fi + +if ! command -v node >/dev/null 2>&1; then + echo "node is required to read ${MANIFEST_PATH}" >&2 + exit 1 +fi + +if ! command -v tar >/dev/null 2>&1; then + echo "tar is required to prepare vendor/quickjs" >&2 + exit 1 +fi + +cleanup_lock() { + if [[ -d "${LOCK_DIR}" ]]; then + rmdir "${LOCK_DIR}" 2>/dev/null || true + fi +} + +acquire_lock() { + local attempt=0 + until mkdir "${LOCK_DIR}" 2>/dev/null; do + attempt=$((attempt + 1)) + if (( attempt == 1 )); then + echo "Waiting for QuickJS source preparation lock at ${LOCK_DIR}" >&2 + fi + sleep 1 + done +} + +acquire_lock +trap cleanup_lock EXIT + +readarray -t MANIFEST_FIELDS < <( + node -e ' + const fs = require("fs"); + const manifest = JSON.parse(fs.readFileSync(process.argv[1], "utf8")); + if (!Number.isInteger(manifest.patchCount) || manifest.patchCount < 0) { + console.error( + `Invalid patchCount in ${process.argv[1]}: ${String(manifest.patchCount)}`, + ); + process.exit(1); + } + console.log(manifest.baseCommit); + console.log(manifest.baseArchive ?? ""); + console.log(manifest.baseArchiveSha256 ?? ""); + console.log(manifest.headCommit); + console.log(manifest.patchDirectory); + console.log(String(manifest.patchCount)); + console.log(manifest.upstreamUrl ?? "https://github.com/bellard/quickjs.git"); + ' "${MANIFEST_PATH}" +) + +BASE_COMMIT="${MANIFEST_FIELDS[0]}" +BASE_ARCHIVE_RELATIVE="${MANIFEST_FIELDS[1]}" +BASE_ARCHIVE_SHA256="${MANIFEST_FIELDS[2]}" +HEAD_COMMIT="${MANIFEST_FIELDS[3]}" +PATCH_DIR="${REPO_ROOT}/${MANIFEST_FIELDS[4]}" +PATCH_COUNT="${MANIFEST_FIELDS[5]}" +UPSTREAM_URL="${MANIFEST_FIELDS[6]}" +BASE_ARCHIVE_PATH="" +if [[ -n "${BASE_ARCHIVE_RELATIVE}" ]]; then + BASE_ARCHIVE_PATH="${REPO_ROOT}/${BASE_ARCHIVE_RELATIVE}" +fi + +if [[ ! -d "${PATCH_DIR}" ]]; then + echo "QuickJS patch directory not found at ${PATCH_DIR}" >&2 + exit 1 +fi + +PATCH_FILES=("${PATCH_DIR}"/*.patch) +if [[ ! -e "${PATCH_FILES[0]}" ]]; then + echo "No patch files found under ${PATCH_DIR}" >&2 + exit 1 +fi + +if (( ${#PATCH_FILES[@]} != PATCH_COUNT )); then + echo "Patch count mismatch: manifest says ${PATCH_COUNT}, found ${#PATCH_FILES[@]}" >&2 + exit 1 +fi + +if [[ -f "${STAMP_FILE}" ]]; then + if node -e ' + const fs = require("fs"); + const stamp = JSON.parse(fs.readFileSync(process.argv[1], "utf8")); + process.exit( + stamp.baseCommit === process.argv[2] && + stamp.headCommit === process.argv[3] && + String(stamp.patchCount) === process.argv[4] && + (stamp.baseArchive ?? null) === (process.argv[5] || null) && + (stamp.baseArchiveSha256 ?? null) === (process.argv[6] || null) + ? 0 + : 1, + ); + ' "${STAMP_FILE}" "${BASE_COMMIT}" "${HEAD_COMMIT}" "${PATCH_COUNT}" "${BASE_ARCHIVE_RELATIVE}" "${BASE_ARCHIVE_SHA256}"; then + echo "QuickJS source is already prepared at ${TARGET_DIR}" >&2 + exit 0 + fi +fi + +verify_base_archive() { + if [[ -z "${BASE_ARCHIVE_PATH}" ]]; then + return 1 + fi + if [[ ! -f "${BASE_ARCHIVE_PATH}" ]]; then + echo "QuickJS base archive not found at ${BASE_ARCHIVE_PATH}" >&2 + exit 1 + fi + if [[ -z "${BASE_ARCHIVE_SHA256}" ]]; then + echo "QuickJS base archive is configured without baseArchiveSha256" >&2 + exit 1 + fi + + node -e ' + const { createHash } = require("crypto"); + const fs = require("fs"); + const archivePath = process.argv[1]; + const expected = process.argv[2]; + const actual = createHash("sha256") + .update(fs.readFileSync(archivePath)) + .digest("hex"); + if (actual !== expected) { + console.error( + `QuickJS base archive checksum mismatch: expected ${expected}, got ${actual}`, + ); + process.exit(1); + } + ' "${BASE_ARCHIVE_PATH}" "${BASE_ARCHIVE_SHA256}" +} + +prepare_base_from_archive() { + verify_base_archive + tar -xzf "${BASE_ARCHIVE_PATH}" -C "${TMP_DIR}" --strip-components=1 + git -C "${TMP_DIR}" init --quiet + git -C "${TMP_DIR}" add -A + git -C "${TMP_DIR}" \ + -c user.name='blue-quickjs automation' \ + -c user.email='automation@blue-quickjs.local' \ + commit --quiet -m "Upstream QuickJS base ${BASE_COMMIT}" + git -C "${TMP_DIR}" remote add origin "${UPSTREAM_URL}" || true +} + +prepare_base_from_git_cache() { + mkdir -p "${CACHE_DIR}" + + seed_cache_from_existing_checkout() { + local checkout_dir="$1" + if ! git -C "${checkout_dir}" rev-parse --is-inside-work-tree >/dev/null 2>&1; then + return 1 + fi + + if ! git -C "${checkout_dir}" rev-parse --verify "${BASE_COMMIT}^{commit}" >/dev/null 2>&1; then + return 1 + fi + + git clone --quiet --mirror --no-local "${checkout_dir}" "${CACHE_REPO}" + } + + if [[ ! -d "${CACHE_REPO}" ]]; then + if ! seed_cache_from_existing_checkout "${TARGET_DIR}"; then + git clone --quiet --mirror "${UPSTREAM_URL}" "${CACHE_REPO}" + fi + else + git -C "${CACHE_REPO}" fetch --quiet --prune --tags origin || true + fi + + if ! git -C "${CACHE_REPO}" rev-parse --verify "${BASE_COMMIT}^{commit}" >/dev/null 2>&1; then + echo "Base commit ${BASE_COMMIT} is not available in ${CACHE_REPO}" >&2 + echo "Delete ${CACHE_REPO} and rerun once network access to ${UPSTREAM_URL} is available." >&2 + exit 1 + fi + + git clone --quiet --no-checkout --no-local "${CACHE_REPO}" "${TMP_DIR}" + git -C "${TMP_DIR}" checkout --quiet "${BASE_COMMIT}" + git -C "${TMP_DIR}" remote set-url origin "${UPSTREAM_URL}" || true +} + +if [[ -e "${TARGET_DIR}" && ! -f "${STAMP_FILE}" ]]; then + BACKUP_DIR="${TARGET_DIR}.backup.$(date +%Y%m%d%H%M%S)" + mv "${TARGET_DIR}" "${BACKUP_DIR}" + echo "Existing vendor/quickjs was moved to ${BACKUP_DIR}" >&2 +fi + +if [[ -f "${STAMP_FILE}" ]]; then + rm -rf "${TARGET_DIR}" +fi + +TMP_DIR="$(mktemp -d "${REPO_ROOT}/vendor/.quickjs-tmp.XXXXXX")" +trap 'rm -rf "${TMP_DIR}"; cleanup_lock' EXIT + +if [[ -n "${BASE_ARCHIVE_PATH}" ]]; then + prepare_base_from_archive +else + prepare_base_from_git_cache +fi + +git -C "${TMP_DIR}" \ + -c user.name='blue-quickjs automation' \ + -c user.email='automation@blue-quickjs.local' \ + am --quiet --committer-date-is-author-date "${PATCH_FILES[@]}" + +node -e ' + const fs = require("fs"); + fs.writeFileSync( + process.argv[1], + JSON.stringify( + { + preparedAt: new Date().toISOString(), + baseCommit: process.argv[2], + headCommit: process.argv[3], + patchCount: Number(process.argv[4]), + upstreamUrl: process.argv[5], + baseArchive: process.argv[6] || null, + baseArchiveSha256: process.argv[7] || null, + }, + null, + 2, + ) + "\n", + ); +' "${TMP_DIR}/.blue-quickjs-source.json" "${BASE_COMMIT}" "${HEAD_COMMIT}" "${PATCH_COUNT}" "${UPSTREAM_URL}" "${BASE_ARCHIVE_RELATIVE}" "${BASE_ARCHIVE_SHA256}" + +rm -rf "${TARGET_DIR}" +mv "${TMP_DIR}" "${TARGET_DIR}" +trap - EXIT +cleanup_lock + +echo "Prepared QuickJS source at ${TARGET_DIR}" >&2 diff --git a/tools/scripts/quickjs-source-prep.test.mjs b/tools/scripts/quickjs-source-prep.test.mjs new file mode 100644 index 0000000..554c702 --- /dev/null +++ b/tools/scripts/quickjs-source-prep.test.mjs @@ -0,0 +1,69 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { readdir, readFile, stat } from 'node:fs/promises'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import test from 'node:test'; + +const repoRoot = path.resolve( + path.dirname(fileURLToPath(import.meta.url)), + '../..', +); + +test('QuickJS source manifest pins a vendored base archive checksum', async () => { + const manifest = await readManifest(); + + assert.equal(typeof manifest.baseArchive, 'string'); + assert.equal(typeof manifest.baseArchiveSha256, 'string'); + assert.match(manifest.baseArchiveSha256, /^[0-9a-f]{64}$/); + + const archivePath = path.join(repoRoot, manifest.baseArchive); + const checksumPath = `${archivePath}.sha256`; + const archiveStat = await stat(archivePath); + assert.equal(archiveStat.isFile(), true); + + const archiveBytes = await readFile(archivePath); + const actualHash = createHash('sha256').update(archiveBytes).digest('hex'); + assert.equal(actualHash, manifest.baseArchiveSha256); + + const checksumText = await readFile(checksumPath, 'utf8'); + assert.equal(checksumText.split(/\s+/)[0], manifest.baseArchiveSha256); +}); + +test('QuickJS patch manifest matches the committed patch series', async () => { + const manifest = await readManifest(); + + assert.equal(typeof manifest.baseCommit, 'string'); + assert.match(manifest.baseCommit, /^[0-9a-f]{40}$/); + assert.equal(typeof manifest.headCommit, 'string'); + assert.match(manifest.headCommit, /^[0-9a-f]{40}$/); + assert.equal(Number.isInteger(manifest.patchCount), true); + assert.ok(manifest.patchCount > 0); + + const patchDir = path.join(repoRoot, manifest.patchDirectory); + const patchFiles = (await readdir(patchDir)) + .filter((name) => name.endsWith('.patch')) + .sort(); + + assert.equal(patchFiles.length, manifest.patchCount); + assert.equal(new Set(patchFiles).size, patchFiles.length); + assert.deepEqual(patchFiles, [...patchFiles].sort()); + + for (const [index, patchFile] of patchFiles.entries()) { + const expectedPrefix = String(index + 1).padStart(4, '0'); + assert.match( + patchFile, + new RegExp(`^${expectedPrefix}-[A-Za-z0-9._-]+\\.patch$`), + `${patchFile} must use a deterministic numbered patch filename`, + ); + await stat(path.join(patchDir, patchFile)); + } +}); + +async function readManifest() { + const manifestPath = path.join( + repoRoot, + 'vendor/quickjs-patches/manifest.json', + ); + return JSON.parse(await readFile(manifestPath, 'utf8')); +} diff --git a/tools/scripts/setup-dev.sh b/tools/scripts/setup-dev.sh new file mode 100644 index 0000000..f027b5d --- /dev/null +++ b/tools/scripts/setup-dev.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" + +cd "$ROOT" + +echo "🔧 Setting up development environment..." +echo + +step() { + echo "➡️ $1" +} + +ok() { + echo "✅ $1" +} + +skip() { + echo "↪️ $1 (already done)" +} + +step "Installing pnpm dependencies" +pnpm install +ok "Dependencies installed" + +step "Preparing QuickJS source from patch series" +bash tools/scripts/prepare-quickjs-source.sh +ok "QuickJS source ready" + + +EMSDK_DIR="$ROOT/tools/emsdk" +if [ ! -d "$EMSDK_DIR" ]; then + step "Installing Emscripten SDK" + bash tools/scripts/setup-emsdk.sh + ok "Emscripten SDK installed" +else + skip "Emscripten SDK" +fi + +source "$EMSDK_DIR/emsdk_env.sh" >/dev/null +ok "Emscripten environment loaded" + +if ! pnpm exec playwright install --help >/dev/null 2>&1; then + step "Installing Playwright" + pnpm exec playwright install chromium + ok "Playwright installed" +else + step "Ensuring Chromium is installed" + pnpm exec playwright install chromium >/dev/null 2>&1 || true + ok "Chromium ready" +fi + +echo +echo "🎉 Setup complete!" +echo +echo "Next steps:" +echo " pnpm verify # run smoke tests" +echo " pnpm playground # open browser playground" diff --git a/tools/scripts/setup-emsdk.sh b/tools/scripts/setup-emsdk.sh index 8d950c4..f357522 100755 --- a/tools/scripts/setup-emsdk.sh +++ b/tools/scripts/setup-emsdk.sh @@ -8,6 +8,98 @@ SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd -- "${SCRIPT_DIR}/../.." && pwd)" EMSDK_VERSION="$(cat "${SCRIPT_DIR}/emsdk-version.txt")" EMSDK_DIR="${REPO_ROOT}/tools/emsdk" +HOST_OS="$(uname -s)" +HOST_ARCH="$(uname -m)" + +resolve_host_python() { + if [ "${HOST_OS}" = "Darwin" ] && [ -x /usr/bin/python3 ]; then + echo /usr/bin/python3 + return 0 + fi + + if command -v python3 >/dev/null 2>&1; then + command -v python3 + return 0 + fi + + if command -v python >/dev/null 2>&1; then + command -v python + return 0 + fi + + echo "" +} + +HOST_PYTHON="$(resolve_host_python)" + +run_with_retry() { + local step_name="$1" + shift + + if "$@"; then + return 0 + fi + + if [ "${HOST_OS}" = "Darwin" ]; then + clear_quarantine_if_possible + fi + + echo "emsdk ${step_name} failed; retrying once..." >&2 + sleep 2 + + if "$@"; then + return 0 + fi + + if [ "${HOST_OS}" = "Darwin" ] && [ "${HOST_ARCH}" = "arm64" ] && [ -z "${EMSDK_ARCH:-}" ]; then + echo "emsdk ${step_name} still failed on macOS arm64; retrying with EMSDK_ARCH=x86_64..." >&2 + sleep 2 + if EMSDK_ARCH=x86_64 "$@"; then + cat >&2 <<'EOF' +emsdk setup succeeded using EMSDK_ARCH=x86_64. + +If this machine does not already have Rosetta installed, install it with: + softwareupdate --install-rosetta --agree-to-license +EOF + return 0 + fi + fi + + cat >&2 <<'EOF' +emsdk setup failed twice. + +If you saw a process get killed part-way through install, rerun: + bash tools/scripts/setup-emsdk.sh + +The script is idempotent and safe to retry after a partial install. +EOF + return 1 +} + +clear_quarantine_if_possible() { + if ! command -v xattr >/dev/null 2>&1; then + return 0 + fi + + xattr -dr com.apple.quarantine "${EMSDK_DIR}" >/dev/null 2>&1 || true +} + +run_emsdk() { + if [ -n "${HOST_PYTHON}" ] && [ -f "${EMSDK_DIR}/emsdk.py" ]; then + env \ + -u PYTHONHOME \ + -u PYTHONPATH \ + -u CONDA_PREFIX \ + -u CONDA_DEFAULT_ENV \ + -u CONDA_EXE \ + -u CONDA_PYTHON_EXE \ + EMSDK_PYTHON="${HOST_PYTHON}" \ + "${HOST_PYTHON}" "${EMSDK_DIR}/emsdk.py" "$@" + return $? + fi + + "${EMSDK_DIR}/emsdk" "$@" +} if [ ! -d "${EMSDK_DIR}" ]; then git clone https://github.com/emscripten-core/emsdk.git "${EMSDK_DIR}" @@ -18,8 +110,8 @@ cd "${EMSDK_DIR}" # Ensure we know about new tags/releases before installing. git fetch --tags origin -./emsdk install "${EMSDK_VERSION}" -./emsdk activate "${EMSDK_VERSION}" +run_with_retry "install" run_emsdk install "${EMSDK_VERSION}" +run_with_retry "activate" run_emsdk activate "${EMSDK_VERSION}" cat <<'EOF' Emscripten installed and activated. diff --git a/tools/scripts/verify-dev.sh b/tools/scripts/verify-dev.sh new file mode 100644 index 0000000..406b027 --- /dev/null +++ b/tools/scripts/verify-dev.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +cd "$ROOT" + +step() { + echo "➡️ $1" +} + +ok() { + echo "✅ $1" +} + +fail() { + echo "❌ $1" >&2 + exit 1 +} + +EMSDK_ENV="$ROOT/tools/emsdk/emsdk_env.sh" + +if [ ! -f "$EMSDK_ENV" ]; then + fail "Missing $EMSDK_ENV. Run: pnpm setup" +fi + +step "Loading Emscripten environment" +source "$EMSDK_ENV" >/dev/null +ok "Emscripten environment loaded" + +step "Ensuring Playwright Chromium is installed" +pnpm exec playwright install chromium >/dev/null +ok "Chromium ready" + +step "Running smoke-node" +pnpm nx test smoke-node +ok "smoke-node passed" + +step "Running smoke-web:e2e" +pnpm nx run smoke-web:e2e +ok "smoke-web:e2e passed" + +echo +echo "🎉 Verify complete!" +echo +echo "Validated:" +echo " - smoke-node" +echo " - smoke-web:e2e" \ No newline at end of file diff --git a/tools/scripts/with-emsdk.sh b/tools/scripts/with-emsdk.sh new file mode 100755 index 0000000..d41f708 --- /dev/null +++ b/tools/scripts/with-emsdk.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/../.." && pwd)" +export EMSDK_QUIET=1 +source "$ROOT/tools/emsdk/emsdk_env.sh" >/dev/null +exec "$@" diff --git a/tools/workload-certification/check-pack-manifests.mjs b/tools/workload-certification/check-pack-manifests.mjs new file mode 100644 index 0000000..90c3f61 --- /dev/null +++ b/tools/workload-certification/check-pack-manifests.mjs @@ -0,0 +1,124 @@ +#!/usr/bin/env node + +import { mkdir, readdir, readFile, unlink, writeFile } from 'node:fs/promises'; +import path from 'node:path'; +import process from 'node:process'; +import { spawn } from 'node:child_process'; +import { PUBLIC_PACKAGES } from './public-packages.mjs'; +import { validatePackedPackageHygiene } from './pack-hygiene.mjs'; + +const args = parseArgs(process.argv.slice(2)); +const repoRoot = process.cwd(); +const outDir = path.resolve(repoRoot, args.outDir); +const useShell = process.platform === 'win32'; +const pnpmCommand = process.platform === 'win32' ? 'pnpm.cmd' : 'pnpm'; +await mkdir(outDir, { recursive: true }); +for (const entry of await readdir(outDir)) { + if (entry.endsWith('.tgz')) { + await unlink(path.join(outDir, entry)); + } +} +const packageDirs = await loadWorkspacePackageDirs(repoRoot); + +const records = []; +for (const pkg of PUBLIC_PACKAGES) { + const packageDir = packageDirs.get(pkg); + if (!packageDir) { + throw new Error(`workspace package not found: ${pkg}`); + } + const packageJson = JSON.parse( + await readFile(path.join(packageDir, 'package.json'), 'utf8'), + ); + await run(pnpmCommand, ['pack', '--pack-destination', outDir], packageDir); + const filename = `${pkg.replace('@', '').replaceAll('/', '-')}-${packageJson.version}.tgz`; + const tarballPath = path.join(outDir, filename); + await validatePackedPackageHygiene(pkg, tarballPath); + records.push({ + package: pkg, + entries: [ + { + name: packageJson.name, + version: packageJson.version, + filename: tarballPath, + }, + ], + }); +} + +const manifest = { + generatedAt: new Date().toISOString(), + packageCount: PUBLIC_PACKAGES.length, + records, +}; +const manifestPath = path.join(outDir, 'pack-manifest.json'); +await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, 'utf8'); + +process.stdout.write( + `${JSON.stringify( + { + outDir, + manifestPath, + packageCount: PUBLIC_PACKAGES.length, + }, + null, + 2, + )}\n`, +); + +function parseArgs(argv) { + let outDir = 'artifacts/consumer-proof/pack-manifests'; + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--') { + continue; + } + if (arg === '--out-dir') { + outDir = argv[index + 1] ?? outDir; + index += 1; + continue; + } + throw new Error(`unknown argument: ${arg}`); + } + return { outDir }; +} + +async function run(command, args, cwd) { + await new Promise((resolve, reject) => { + const child = spawn(command, args, { + cwd, + stdio: 'inherit', + shell: useShell, + }); + child.on('error', reject); + child.on('exit', (code) => { + if (code === 0) { + resolve(undefined); + return; + } + reject(new Error(`command failed (${command} ${args.join(' ')})`)); + }); + }); +} + +async function loadWorkspacePackageDirs(rootDir) { + const packageDirs = new Map(); + for (const scope of ['apps', 'libs', 'tools']) { + const scopeDir = path.join(rootDir, scope); + const entries = await readdir(scopeDir, { withFileTypes: true }); + for (const entry of entries) { + if (!entry.isDirectory()) { + continue; + } + const packageJsonPath = path.join(scopeDir, entry.name, 'package.json'); + try { + const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8')); + if (typeof packageJson.name === 'string') { + packageDirs.set(packageJson.name, path.dirname(packageJsonPath)); + } + } catch { + // Ignore entries that are not workspace packages. + } + } + } + return packageDirs; +} diff --git a/tools/workload-certification/check-public-package-coverage.mjs b/tools/workload-certification/check-public-package-coverage.mjs new file mode 100644 index 0000000..1166aa1 --- /dev/null +++ b/tools/workload-certification/check-public-package-coverage.mjs @@ -0,0 +1,88 @@ +#!/usr/bin/env node + +import { readdir, readFile } from 'node:fs/promises'; +import path from 'node:path'; +import process from 'node:process'; +import { pathToFileURL } from 'node:url'; +import { PUBLIC_PACKAGES } from './public-packages.mjs'; + +if (isMain()) { + const output = await checkPublicPackageCoverage(process.cwd()); + process.stdout.write(`${JSON.stringify(output, null, 2)}\n`); + if (!Object.values(output.checks).every(Boolean)) { + process.exitCode = 1; + } +} + +export async function checkPublicPackageCoverage(repoRoot) { + const workspacePackages = await discoverWorkspacePackages(repoRoot); + const publishablePackages = workspacePackages + .filter((entry) => !entry.private) + .map((entry) => entry.name) + .sort(); + const configuredPackages = [...PUBLIC_PACKAGES].sort(); + const configuredSet = new Set(configuredPackages); + const publishableSet = new Set(publishablePackages); + + const missingFromPublicPackages = publishablePackages.filter( + (packageName) => !configuredSet.has(packageName), + ); + const extraPublicPackages = configuredPackages.filter( + (packageName) => !publishableSet.has(packageName), + ); + const duplicatePublicPackages = configuredPackages.filter( + (packageName, index) => index !== configuredPackages.indexOf(packageName), + ); + + const checks = { + noMissingPublishablePackages: missingFromPublicPackages.length === 0, + noExtraPublicPackages: extraPublicPackages.length === 0, + noDuplicatePublicPackages: duplicatePublicPackages.length === 0, + }; + + return { + checks, + publishablePackageCount: publishablePackages.length, + configuredPackageCount: PUBLIC_PACKAGES.length, + publishablePackages, + configuredPackages, + missingFromPublicPackages, + extraPublicPackages, + duplicatePublicPackages, + }; +} + +function isMain() { + if (!process.argv[1]) { + return false; + } + return import.meta.url === pathToFileURL(process.argv[1]).href; +} + +async function discoverWorkspacePackages(rootDir) { + const packages = []; + for (const scope of ['apps', 'libs', 'tools']) { + const scopeDir = path.join(rootDir, scope); + const entries = await readdir(scopeDir, { withFileTypes: true }); + for (const entry of entries) { + if (!entry.isDirectory()) { + continue; + } + const packageJsonPath = path.join(scopeDir, entry.name, 'package.json'); + try { + const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8')); + if (typeof packageJson.name !== 'string') { + continue; + } + packages.push({ + name: packageJson.name, + private: Boolean(packageJson.private), + path: path.relative(rootDir, packageJsonPath), + }); + } catch { + // Ignore workspace directories that do not contain package manifests. + } + } + } + return packages; +} diff --git a/tools/workload-certification/check-public-package-versions.mjs b/tools/workload-certification/check-public-package-versions.mjs new file mode 100644 index 0000000..d6d74f8 --- /dev/null +++ b/tools/workload-certification/check-public-package-versions.mjs @@ -0,0 +1,61 @@ +#!/usr/bin/env node + +import { readFile, stat } from 'node:fs/promises'; +import path from 'node:path'; +import process from 'node:process'; +import { PUBLIC_PACKAGES } from './public-packages.mjs'; + +const repoRoot = process.cwd(); +const packageInfos = []; + +for (const pkg of PUBLIC_PACKAGES) { + const packageJsonPath = await resolveWorkspacePackageJsonPath(repoRoot, pkg); + const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8')); + packageInfos.push({ + name: packageJson.name, + version: packageJson.version, + private: Boolean(packageJson.private), + path: path.relative(repoRoot, packageJsonPath), + }); +} + +const versionSet = new Set(packageInfos.map((entry) => entry.version)); +const privatePackages = packageInfos.filter((entry) => entry.private); +const checks = { + alignedVersion: versionSet.size === 1, + noPrivatePackages: privatePackages.length === 0, +}; + +const output = { + packageCount: packageInfos.length, + targetVersion: versionSet.size === 1 ? [...versionSet][0] : null, + checks, + packages: packageInfos, + privatePackages, +}; + +process.stdout.write(`${JSON.stringify(output, null, 2)}\n`); +if (!checks.alignedVersion || !checks.noPrivatePackages) { + process.exitCode = 1; +} + +async function resolveWorkspacePackageJsonPath(root, packageName) { + const shortName = packageName.replace('@blue-quickjs/', ''); + const candidatePaths = [ + path.join(root, 'libs', shortName, 'package.json'), + path.join(root, 'tools', shortName, 'package.json'), + ]; + return findExistingPath(candidatePaths, packageName); +} + +async function findExistingPath(candidatePaths, packageName) { + for (const candidate of candidatePaths) { + try { + await stat(candidate); + return candidate; + } catch { + continue; + } + } + throw new Error(`unable to resolve package.json path for ${packageName}`); +} diff --git a/tools/workload-certification/compare-builder-determinism-matrix.mjs b/tools/workload-certification/compare-builder-determinism-matrix.mjs new file mode 100644 index 0000000..fa04932 --- /dev/null +++ b/tools/workload-certification/compare-builder-determinism-matrix.mjs @@ -0,0 +1,103 @@ +#!/usr/bin/env node + +import { readFile, readdir } from 'node:fs/promises'; +import path from 'node:path'; +import process from 'node:process'; + +const args = parseArgs(process.argv.slice(2)); +const inputDir = path.resolve(process.cwd(), args.inputDir); +const reportPaths = await findReports(inputDir); + +if (reportPaths.length === 0) { + throw new Error(`no builder-determinism-report.json files found under ${inputDir}`); +} + +const reports = []; +for (const reportPath of reportPaths) { + reports.push({ + path: reportPath, + payload: JSON.parse(await readFile(reportPath, 'utf8')), + }); +} + +const baseline = reports[0].payload; +const mismatches = []; +for (const report of reports.slice(1)) { + for (let index = 0; index < baseline.fixtures.length; index += 1) { + const baselineFixture = baseline.fixtures[index]; + const candidateFixture = report.payload.fixtures[index]; + if (!candidateFixture) { + mismatches.push({ + type: 'missing_fixture', + report: report.path, + fixtureIndex: index, + }); + continue; + } + if (baselineFixture.graphHash !== candidateFixture.graphHash) { + mismatches.push({ + type: 'graph_hash_mismatch', + report: report.path, + fixtureIndex: index, + baseline: baselineFixture.graphHash, + candidate: candidateFixture.graphHash, + }); + } + if (baselineFixture.canonicalHash !== candidateFixture.canonicalHash) { + mismatches.push({ + type: 'canonical_hash_mismatch', + report: report.path, + fixtureIndex: index, + baseline: baselineFixture.canonicalHash, + candidate: candidateFixture.canonicalHash, + }); + } + } +} + +const output = { + generatedAt: new Date().toISOString(), + inputDir, + reportCount: reports.length, + mismatchCount: mismatches.length, + reports: reports.map((report) => ({ + path: path.relative(inputDir, report.path), + checks: report.payload.checks, + })), + mismatches, +}; + +console.log(JSON.stringify(output, null, 2)); +if (mismatches.length > 0) { + process.exitCode = 1; +} + +async function findReports(targetDir) { + const entries = await readdir(targetDir, { withFileTypes: true }); + const reports = []; + for (const entry of entries) { + const entryPath = path.join(targetDir, entry.name); + if (entry.isDirectory()) { + reports.push(...(await findReports(entryPath))); + continue; + } + if (entry.name === 'builder-determinism-report.json') { + reports.push(entryPath); + } + } + return reports.sort(); +} + +function parseArgs(argv) { + let inputDir = 'artifacts'; + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--input-dir') { + inputDir = argv[index + 1] ?? inputDir; + index += 1; + continue; + } + throw new Error(`unknown argument: ${arg}`); + } + return { inputDir }; +} diff --git a/tools/workload-certification/pack-hygiene.mjs b/tools/workload-certification/pack-hygiene.mjs new file mode 100644 index 0000000..8c56766 --- /dev/null +++ b/tools/workload-certification/pack-hygiene.mjs @@ -0,0 +1,78 @@ +import { execFile } from 'node:child_process'; +import { promisify } from 'node:util'; + +const execFileAsync = promisify(execFile); + +const EMITTED_TEXT_FILE_PATTERN = + /(?:^|\/)dist\/.*\.(?:[cm]?js|[cm]?ts|d\.[cm]?ts)$/; +const TEST_FILE_PATTERN = /\.(?:spec|test)\.[^/]+$/; +const VITEST_REFERENCE_PATTERN = /\bvitest\b/; + +export async function validatePackedPackageHygiene(packageName, tarballPath) { + const { stdout } = await execFileAsync('tar', ['-tzf', tarballPath], { + maxBuffer: 1024 * 1024 * 16, + }); + const entries = stdout + .split('\n') + .map((entry) => entry.trim()) + .filter(Boolean); + const files = []; + + for (const entry of entries) { + const normalizedPath = normalizeTarEntry(entry); + const file = { path: normalizedPath }; + + if (isEmittedTextFile(normalizedPath)) { + const extracted = await execFileAsync('tar', ['-xOf', tarballPath, entry], { + maxBuffer: 1024 * 1024 * 16, + }); + file.text = extracted.stdout; + } + + files.push(file); + } + + const violations = findPackedPackageHygieneViolations(files); + if (violations.length > 0) { + throw new Error( + [ + `${packageName} packed output contains test-only artifacts:`, + ...violations.map((violation) => `- ${violation}`), + ].join('\n'), + ); + } +} + +export function findPackedPackageHygieneViolations(files) { + const violations = []; + + for (const file of files) { + const normalizedPath = normalizeTarEntry(file.path); + + if (normalizedPath === 'dist/test' || normalizedPath.startsWith('dist/test/')) { + violations.push(`${normalizedPath} is under dist/test`); + } + + if (TEST_FILE_PATTERN.test(normalizedPath)) { + violations.push(`${normalizedPath} is a test/spec artifact`); + } + + if ( + isEmittedTextFile(normalizedPath) && + typeof file.text === 'string' && + VITEST_REFERENCE_PATTERN.test(file.text) + ) { + violations.push(`${normalizedPath} references vitest`); + } + } + + return violations; +} + +function isEmittedTextFile(filePath) { + return EMITTED_TEXT_FILE_PATTERN.test(filePath); +} + +function normalizeTarEntry(entry) { + return entry.replaceAll('\\', '/').replace(/^package\//, '').replace(/\/$/, ''); +} diff --git a/tools/workload-certification/pack-hygiene.test.mjs b/tools/workload-certification/pack-hygiene.test.mjs new file mode 100644 index 0000000..8d3b393 --- /dev/null +++ b/tools/workload-certification/pack-hygiene.test.mjs @@ -0,0 +1,30 @@ +import assert from 'node:assert/strict'; +import test from 'node:test'; +import { findPackedPackageHygieneViolations } from './pack-hygiene.mjs'; + +test('packed package hygiene rejects test artifacts and vitest references', () => { + const violations = findPackedPackageHygieneViolations([ + { path: 'package/dist/test/helper.js', text: 'export {};\n' }, + { path: 'package/dist/lib/foo.spec.d.ts', text: 'export {};\n' }, + { + path: 'package/dist/index.js', + text: "import { vi } from 'vitest';\nexport { vi };\n", + }, + ]); + + assert.deepEqual(violations, [ + 'dist/test/helper.js is under dist/test', + 'dist/lib/foo.spec.d.ts is a test/spec artifact', + 'dist/index.js references vitest', + ]); +}); + +test('packed package hygiene allows production dist entries', () => { + const violations = findPackedPackageHygieneViolations([ + { path: 'package/dist/index.js', text: "export * from './lib/foo.js';\n" }, + { path: 'package/dist/lib/foo.d.ts', text: 'export declare const foo = 1;\n' }, + { path: 'package/README.md', text: 'Run tests with vitest.\n' }, + ]); + + assert.deepEqual(violations, []); +}); diff --git a/tools/workload-certification/pack-public-tarballs.mjs b/tools/workload-certification/pack-public-tarballs.mjs new file mode 100644 index 0000000..9cb06ab --- /dev/null +++ b/tools/workload-certification/pack-public-tarballs.mjs @@ -0,0 +1,106 @@ +#!/usr/bin/env node + +import { mkdir, readdir, readFile, unlink, writeFile } from 'node:fs/promises'; +import path from 'node:path'; +import process from 'node:process'; +import { spawn } from 'node:child_process'; +import { PUBLIC_PACKAGES } from './public-packages.mjs'; + +const repoRoot = process.cwd(); +const args = parseArgs(process.argv.slice(2)); +const outDir = path.resolve(repoRoot, args.outDir); +const useShell = process.platform === 'win32'; +const pnpmCommand = process.platform === 'win32' ? 'pnpm.cmd' : 'pnpm'; +await mkdir(outDir, { recursive: true }); +for (const entry of await readdir(outDir)) { + if (entry.endsWith('.tgz')) { + await unlink(path.join(outDir, entry)); + } +} + +const packages = PUBLIC_PACKAGES; +const packageDirs = await loadWorkspacePackageDirs(repoRoot); + +for (const pkg of packages) { + const packageDir = packageDirs.get(pkg); + if (!packageDir) { + throw new Error(`workspace package not found: ${pkg}`); + } + await run( + pnpmCommand, + ['pack', '--pack-destination', outDir], + packageDir, + ); +} + +const tarballs = await listTarballs(outDir); +const manifest = { + generatedAt: new Date().toISOString(), + outDir, + packages, + tarballs, +}; +const manifestPath = path.join(outDir, 'tarball-manifest.json'); +await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, 'utf8'); + +console.log(JSON.stringify({ outDir, manifestPath, count: tarballs.length }, null, 2)); + +async function listTarballs(directory) { + const entries = await readdir(directory); + return entries.filter((entry) => entry.endsWith('.tgz')).sort(); +} + +async function run(command, argsList, cwd) { + await new Promise((resolve, reject) => { + const child = spawn(command, argsList, { + cwd, + stdio: 'inherit', + shell: useShell, + }); + child.on('error', reject); + child.on('exit', (code) => { + if (code === 0) { + resolve(undefined); + return; + } + reject(new Error(`command failed (${command} ${argsList.join(' ')}): ${code}`)); + }); + }); +} + +async function loadWorkspacePackageDirs(rootDir) { + const packageDirs = new Map(); + for (const scope of ['apps', 'libs', 'tools']) { + const scopeDir = path.join(rootDir, scope); + const entries = await readdir(scopeDir, { withFileTypes: true }); + for (const entry of entries) { + if (!entry.isDirectory()) { + continue; + } + const packageJsonPath = path.join(scopeDir, entry.name, 'package.json'); + try { + const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8')); + if (typeof packageJson.name === 'string') { + packageDirs.set(packageJson.name, path.dirname(packageJsonPath)); + } + } catch { + // Ignore entries that are not workspace packages. + } + } + } + return packageDirs; +} + +function parseArgs(argv) { + let outDir = 'artifacts/consumer-proof/tarballs'; + for (let i = 0; i < argv.length; i += 1) { + const arg = argv[i]; + if (arg === '--out-dir') { + outDir = argv[i + 1] ?? outDir; + i += 1; + continue; + } + throw new Error(`unknown argument: ${arg}`); + } + return { outDir }; +} diff --git a/tools/workload-certification/public-package-coverage.test.mjs b/tools/workload-certification/public-package-coverage.test.mjs new file mode 100644 index 0000000..74a4b17 --- /dev/null +++ b/tools/workload-certification/public-package-coverage.test.mjs @@ -0,0 +1,23 @@ +import assert from 'node:assert/strict'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import test from 'node:test'; +import { checkPublicPackageCoverage } from './check-public-package-coverage.mjs'; + +const repoRoot = path.resolve( + path.dirname(fileURLToPath(import.meta.url)), + '../..', +); + +test('public package coverage includes every publishable workspace package', async () => { + const result = await checkPublicPackageCoverage(repoRoot); + + assert.equal(result.checks.noMissingPublishablePackages, true); + assert.equal(result.checks.noExtraPublicPackages, true); + assert.equal(result.checks.noDuplicatePublicPackages, true); + assert.deepEqual(result.missingFromPublicPackages, []); + assert.match( + result.configuredPackages.join('\n'), + /@blue-quickjs\/deterministic-builder/, + ); +}); diff --git a/tools/workload-certification/public-packages.mjs b/tools/workload-certification/public-packages.mjs new file mode 100644 index 0000000..61deca9 --- /dev/null +++ b/tools/workload-certification/public-packages.mjs @@ -0,0 +1,14 @@ +export const PUBLIC_PACKAGES = [ + '@blue-quickjs/abi-manifest', + '@blue-quickjs/dv', + '@blue-quickjs/execution-profiles', + '@blue-quickjs/quickjs-wasm-constants', + '@blue-quickjs/quickjs-wasm', + '@blue-quickjs/quickjs-runtime', + '@blue-quickjs/deterministic-bundler', + '@blue-quickjs/deterministic-builder', +]; + +export const PUBLIC_PACKAGE_PROJECTS = PUBLIC_PACKAGES.map((packageName) => + packageName.replace('@blue-quickjs/', ''), +); diff --git a/tools/workload-certification/public-packages.test.mjs b/tools/workload-certification/public-packages.test.mjs new file mode 100644 index 0000000..51a7c82 --- /dev/null +++ b/tools/workload-certification/public-packages.test.mjs @@ -0,0 +1,59 @@ +import assert from 'node:assert/strict'; +import { readFile } from 'node:fs/promises'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import test from 'node:test'; +import { PUBLIC_PACKAGES } from './public-packages.mjs'; +import { checkPublicPackageCoverage } from './check-public-package-coverage.mjs'; + +const repoRoot = path.resolve( + path.dirname(fileURLToPath(import.meta.url)), + '../..', +); + +test('PUBLIC_PACKAGES includes public release-train packages', () => { + assert.match( + PUBLIC_PACKAGES.join('\n'), + /@blue-quickjs\/deterministic-builder/, + ); + assert.equal(new Set(PUBLIC_PACKAGES).size, PUBLIC_PACKAGES.length); +}); + +test('every configured public package resolves to a non-private workspace manifest', async () => { + const coverage = await checkPublicPackageCoverage(repoRoot); + const expectedVersion = await readPackageVersion( + path.join(repoRoot, 'libs/abi-manifest/package.json'), + ); + + for (const packageName of PUBLIC_PACKAGES) { + const manifestPath = path.join( + repoRoot, + 'libs', + packageName.replace('@blue-quickjs/', ''), + 'package.json', + ); + const manifest = JSON.parse(await readFile(manifestPath, 'utf8')); + + assert.equal(manifest.name, packageName); + assert.notEqual(manifest.private, true, `${packageName} must be public`); + assert.equal( + manifest.version, + expectedVersion, + `${packageName} must match the release train version`, + ); + } + + assert.deepEqual(coverage.extraPublicPackages, []); +}); + +test('PUBLIC_PACKAGES covers every discovered publishable workspace package', async () => { + const coverage = await checkPublicPackageCoverage(repoRoot); + + assert.equal(coverage.checks.noMissingPublishablePackages, true); + assert.deepEqual(coverage.missingFromPublicPackages, []); +}); + +async function readPackageVersion(packageJsonPath) { + const manifest = JSON.parse(await readFile(packageJsonPath, 'utf8')); + return manifest.version; +} diff --git a/tools/workload-certification/release-workflow-package-list.test.mjs b/tools/workload-certification/release-workflow-package-list.test.mjs new file mode 100644 index 0000000..8c72833 --- /dev/null +++ b/tools/workload-certification/release-workflow-package-list.test.mjs @@ -0,0 +1,86 @@ +import assert from 'node:assert/strict'; +import { readFile } from 'node:fs/promises'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import test from 'node:test'; +import { + PUBLIC_PACKAGE_PROJECTS, + PUBLIC_PACKAGES, +} from './public-packages.mjs'; + +const repoRoot = path.resolve( + path.dirname(fileURLToPath(import.meta.url)), + '../..', +); + +test('release workflow package build list matches PUBLIC_PACKAGE_PROJECTS', async () => { + const workflowText = await readFile( + path.join(repoRoot, '.github/workflows/release.yml'), + 'utf8', + ); + const projectLists = extractNxProjectLists(workflowText); + + assert.ok(projectLists.length > 0, 'expected at least one --projects list'); + assert.ok( + projectLists.some((projects) => + sameMembers(projects, PUBLIC_PACKAGE_PROJECTS), + ), + 'release.yml must contain a public package build list matching PUBLIC_PACKAGES', + ); +}); + +test('workload certification workflow mentions every public package project', async () => { + const workflowText = await readFile( + path.join(repoRoot, '.github/workflows/workload-certification.yml'), + 'utf8', + ); + + for (const project of PUBLIC_PACKAGE_PROJECTS) { + assert.match( + workflowText, + new RegExp(`(^|[,\\s])${escapeRegExp(project)}($|[,\\s])`), + `${project} is missing from workload-certification.yml`, + ); + } +}); + +test('Verdaccio rehearsal derives its package set from PUBLIC_PACKAGES', async () => { + const scriptText = await readFile( + path.join( + repoRoot, + 'tools/workload-certification/run-verdaccio-publish-rehearsal.mjs', + ), + 'utf8', + ); + + assert.match(scriptText, /PUBLIC_PACKAGES/); + assert.match(scriptText, /PUBLIC_PACKAGE_PROJECTS/); + for (const packageName of PUBLIC_PACKAGES) { + assert.doesNotMatch( + scriptText, + new RegExp(`['"]${escapeRegExp(packageName)}['"]`), + `${packageName} should come from PUBLIC_PACKAGES, not a local literal`, + ); + } +}); + +function extractNxProjectLists(workflowText) { + return [...workflowText.matchAll(/--projects\s+([^\n]+)/g)].map((match) => + match[1] + .trim() + .split(',') + .map((project) => project.trim()) + .filter(Boolean), + ); +} + +function sameMembers(actual, expected) { + return ( + actual.length === expected.length && + expected.every((project) => actual.includes(project)) + ); +} + +function escapeRegExp(value) { + return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); +} diff --git a/tools/workload-certification/run-verdaccio-publish-rehearsal.mjs b/tools/workload-certification/run-verdaccio-publish-rehearsal.mjs new file mode 100644 index 0000000..7d1eb1c --- /dev/null +++ b/tools/workload-certification/run-verdaccio-publish-rehearsal.mjs @@ -0,0 +1,291 @@ +#!/usr/bin/env node + +import { mkdir, readFile, rm, writeFile } from 'node:fs/promises'; +import path from 'node:path'; +import process from 'node:process'; +import { spawn, spawnSync } from 'node:child_process'; +import { setTimeout as sleep } from 'node:timers/promises'; +import { URL } from 'node:url'; +import { PUBLIC_PACKAGE_PROJECTS, PUBLIC_PACKAGES } from './public-packages.mjs'; + +const args = parseArgs(process.argv.slice(2)); +const repoRoot = process.cwd(); +const outDir = path.resolve(repoRoot, args.outDir); +const consumerAppDir = path.resolve(repoRoot, 'e2e/consumer-proof-app'); +const registryStoragePath = path.resolve(repoRoot, 'tmp/local-registry/storage'); +const listenAddress = resolveListenAddress(args.registryUrl); + +await rm(registryStoragePath, { recursive: true, force: true }); +await mkdir(outDir, { recursive: true }); + +const registryProcess = spawn( + 'pnpm', + [ + 'exec', + 'verdaccio', + '--config', + '.verdaccio/config.yml', + '--listen', + listenAddress, + ], + { + cwd: repoRoot, + stdio: 'pipe', + }, +); +let registryStdout = ''; +let registryStderr = ''; +registryProcess.stdout.on('data', (chunk) => { + registryStdout += chunk.toString(); +}); +registryProcess.stderr.on('data', (chunk) => { + registryStderr += chunk.toString(); +}); + +try { + await waitForRegistry(args.registryUrl, args.registryTimeoutMs); + + run( + 'pnpm', + [ + 'dlx', + 'npm-cli-login', + '-u', + 'ci-user', + '-p', + 'ci-password', + '-e', + 'ci@example.com', + '-r', + args.registryUrl, + ], + repoRoot, + ); + + run( + 'pnpm', + [ + 'nx', + 'run-many', + '-t', + 'build', + '-p', + PUBLIC_PACKAGE_PROJECTS.join(','), + ], + repoRoot, + ); + + const packageVersions = await resolvePublicPackageVersions(repoRoot); + const publishResults = []; + for (const pkg of PUBLIC_PACKAGES) { + const publish = run( + 'pnpm', + [ + '--filter', + pkg, + 'publish', + '--registry', + args.registryUrl, + '--no-git-checks', + '--access', + 'public', + '--tag', + 'rc', + '--force', + ], + repoRoot, + ); + publishResults.push({ + package: pkg, + version: packageVersions.get(pkg), + command: publish.command, + exitCode: publish.exitCode, + }); + } + + run('npm', ['install', '--no-fund', '--no-audit'], consumerAppDir); + run( + 'npm', + ['remove', '--no-save', ...PUBLIC_PACKAGES], + consumerAppDir, + { allowFailure: true }, + ); + run( + 'npm', + [ + 'install', + '--no-save', + '--force', + '--no-fund', + '--no-audit', + '--registry', + args.registryUrl, + ...PUBLIC_PACKAGES.map((pkg) => `${pkg}@${packageVersions.get(pkg)}`), + ], + consumerAppDir, + ); + + if (!args.skipPlaywrightInstall) { + run( + 'pnpm', + ['--dir', 'e2e/consumer-proof-app', 'exec', 'playwright', 'install', '--with-deps', 'chromium'], + repoRoot, + ); + } + + run( + 'pnpm', + ['--dir', 'e2e/consumer-proof-app', 'run', 'repro', '--', '--browser', 'chromium'], + repoRoot, + ); + + const reproReportPath = path.join( + consumerAppDir, + 'reports', + 'reproducibility-report.json', + ); + const reproReport = JSON.parse(await readFile(reproReportPath, 'utf8')); + + const output = { + generatedAt: new Date().toISOString(), + registryUrl: args.registryUrl, + packageCount: PUBLIC_PACKAGES.length, + publishedPackages: publishResults, + consumerReportPath: path.relative(repoRoot, reproReportPath), + consumerParity: reproReport.parity ?? null, + }; + + const outputPath = path.join(outDir, 'verdaccio-publish-rehearsal.json'); + await writeFile(outputPath, `${JSON.stringify(output, null, 2)}\n`, 'utf8'); + await writeFile(path.join(outDir, 'verdaccio-stdout.log'), registryStdout, 'utf8'); + await writeFile(path.join(outDir, 'verdaccio-stderr.log'), registryStderr, 'utf8'); + + process.stdout.write( + `${JSON.stringify( + { + outputPath: path.relative(repoRoot, outputPath), + registryUrl: args.registryUrl, + consumerParity: output.consumerParity, + }, + null, + 2, + )}\n`, + ); +} finally { + if (!registryProcess.killed) { + registryProcess.kill('SIGTERM'); + } + await waitForExit(registryProcess, 5000); + run('npm', ['config', 'set', 'registry', 'https://registry.npmjs.org/'], repoRoot, { + allowFailure: true, + }); + run('npm', ['config', 'delete', '//127.0.0.1:4873/:_authToken'], repoRoot, { + allowFailure: true, + }); +} + +async function resolvePublicPackageVersions(repoRootPath) { + const versionMap = new Map(); + for (const pkg of PUBLIC_PACKAGES) { + const packageJsonPath = path.resolve( + repoRootPath, + 'libs', + pkg.replace('@blue-quickjs/', ''), + 'package.json', + ); + const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8')); + versionMap.set(pkg, packageJson.version); + } + return versionMap; +} + +async function waitForRegistry(registryUrl, timeoutMs) { + const deadline = Date.now() + timeoutMs; + while (Date.now() < deadline) { + try { + const response = await fetch(`${registryUrl}/-/ping`); + if (response.ok) { + return; + } + } catch { + // ignore while waiting + } + await sleep(500); + } + throw new Error(`verdaccio did not become ready within ${timeoutMs}ms`); +} + +function run(command, args, cwd, options = {}) { + const result = spawnSync(command, args, { + cwd, + encoding: 'utf8', + stdio: 'pipe', + env: { + ...process.env, + ...(options.env ?? {}), + }, + input: options.input, + }); + if (result.status !== 0 && !options.allowFailure) { + throw new Error( + `command failed (${command} ${args.join(' ')}): ${result.stderr ?? result.stdout}`, + ); + } + return { + command: `${command} ${args.join(' ')}`, + exitCode: result.status, + stdout: result.stdout, + stderr: result.stderr, + }; +} + +async function waitForExit(child, timeoutMs) { + await Promise.race([ + new Promise((resolve) => { + child.once('exit', () => resolve(undefined)); + }), + sleep(timeoutMs), + ]); +} + +function parseArgs(argv) { + const parsed = { + outDir: 'artifacts/consumer-proof/verdaccio', + registryUrl: 'http://127.0.0.1:4873', + registryTimeoutMs: 60000, + skipPlaywrightInstall: false, + }; + + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--') { + continue; + } + if (arg === '--out-dir') { + parsed.outDir = argv[index + 1] ?? parsed.outDir; + index += 1; + continue; + } + if (arg === '--registry-url') { + parsed.registryUrl = argv[index + 1] ?? parsed.registryUrl; + index += 1; + continue; + } + if (arg === '--registry-timeout-ms') { + parsed.registryTimeoutMs = Number(argv[index + 1] ?? parsed.registryTimeoutMs); + index += 1; + continue; + } + if (arg === '--skip-playwright-install') { + parsed.skipPlaywrightInstall = true; + continue; + } + throw new Error(`unknown argument: ${arg}`); + } + return parsed; +} + +function resolveListenAddress(registryUrl) { + const parsed = new URL(registryUrl); + return `${parsed.hostname}:${parsed.port}`; +} diff --git a/tsconfig.json b/tsconfig.json index 433edb1..1486732 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -29,6 +29,24 @@ }, { "path": "./libs/quickjs-wasm-constants" + }, + { + "path": "./libs/deterministic-bundler" + }, + { + "path": "./libs/deterministic-builder" + }, + { + "path": "./libs/execution-profiles" + }, + { + "path": "./tools/blue-quickjs-cli" + }, + { + "path": "./apps/ecosystem-certifier" + }, + { + "path": "./apps/bluequickjs-playground" } ] } diff --git a/vendor/README.md b/vendor/README.md index cddd76e..9652076 100644 --- a/vendor/README.md +++ b/vendor/README.md @@ -1,20 +1,20 @@ -# QuickJS submodule +# QuickJS source patches -This repo pins the QuickJS fork as a git submodule at `vendor/quickjs` with origin `git@blue.github.com:mjwebblue/quickjs.git`. +This repo stores Blue QuickJS changes as an ordered patch series under +`vendor/quickjs-patches/series`. -## Clone / init -- From a fresh clone run: `git submodule update --init --recursive` to populate `vendor/quickjs`. +The working tree under `vendor/quickjs` is generated from: +- upstream repo `https://github.com/bellard/quickjs.git` +- base commit `e5fd3918c1c4a2ee39016e71b66a9eeda85ce716` +- patch manifest `vendor/quickjs-patches/manifest.json` -## Updating the pinned commit -- Do QuickJS development in the fork repo, not inside the submodule. -- After merging changes to the fork, update the pin here: - 1. `cd vendor/quickjs` - 2. `git fetch origin && git checkout ` - 3. `cd .. && git add vendor/quickjs && git commit -m "chore: bump quickjs submodule"` -- Use `git submodule status` to confirm the pinned SHA. +## Prepare source +- Run `bash tools/scripts/prepare-quickjs-source.sh` to recreate `vendor/quickjs`. +- `pnpm setup` runs the same preparation step automatically. +- `vendor/quickjs` is generated workspace state and should not be committed. -## Remotes and branches -- Configure the upstream remote to track Bellard’s repo (for rebases/cherry-picks): - `cd vendor/quickjs && git remote add upstream git@github.com:bellard/quickjs.git` -- Do not push directly to the fork’s `main/master`. Use feature branches per track (e.g., `deterministic-init`, `gas-metering`, `host-abi`) and merge via PRs into the fork’s protected default branch, tagging/pinning releases you consume here. -- When updating the submodule pin, always reference a merged/annotated commit (or tag) on the fork’s default branch to keep pins reproducible. +## Updating patches +- Make QuickJS changes in a dedicated fork or working branch outside this repo. +- Export the commit series into `vendor/quickjs-patches/series`. +- Update `vendor/quickjs-patches/manifest.json` if the upstream base or patch count changes. +- Re-run `bash tools/scripts/prepare-quickjs-source.sh` to regenerate `vendor/quickjs`. diff --git a/vendor/quickjs b/vendor/quickjs deleted file mode 160000 index 9d1eda6..0000000 --- a/vendor/quickjs +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9d1eda6e0d1ec36c279d87380db77fbcc3acbae8 diff --git a/vendor/quickjs-patches/README.md b/vendor/quickjs-patches/README.md new file mode 100644 index 0000000..54d55a3 --- /dev/null +++ b/vendor/quickjs-patches/README.md @@ -0,0 +1,38 @@ +# QuickJS Patch Series + +This directory contains the exported patch series for the Blue QuickJS fork. + +Source: +- Fork repo: `vendor/quickjs` +- Upstream repo: `https://github.com/bellard/quickjs.git` +- Upstream base commit: `e5fd3918c1c4a2ee39016e71b66a9eeda85ce716` +- Vendored upstream base archive: + `vendor/quickjs-patches/upstream/quickjs-base-e5fd3918c1c4a2ee39016e71b66a9eeda85ce716.tar.gz` +- Vendored archive SHA-256: + `a2ff2baaa328275baa490596f4751b85f1e39419b9f7f44c3e83e9fac9dc9217` +- Exported fork head: `8b3253bddf6a5a792dd098b1a8a154f534b88586` + +Series layout: +- `series/*.patch` preserves the original commit order from the fork. +- Patch `0001` applies first. +- Patch `0051` applies last. + +Generation command: + +```sh +git -C vendor/quickjs format-patch \ + --output-directory ../quickjs-patches/series \ + e5fd3918c1c4a2ee39016e71b66a9eeda85ce716..8b3253bddf6a5a792dd098b1a8a154f534b88586 +``` + +Archive generation command: + +```sh +git -C vendor/.quickjs-cache/upstream.git archive \ + --format=tar \ + --prefix=quickjs-base/ \ + e5fd3918c1c4a2ee39016e71b66a9eeda85ce716 | + gzip -n > vendor/quickjs-patches/upstream/quickjs-base-e5fd3918c1c4a2ee39016e71b66a9eeda85ce716.tar.gz +sha256sum vendor/quickjs-patches/upstream/quickjs-base-e5fd3918c1c4a2ee39016e71b66a9eeda85ce716.tar.gz \ + > vendor/quickjs-patches/upstream/quickjs-base-e5fd3918c1c4a2ee39016e71b66a9eeda85ce716.tar.gz.sha256 +``` diff --git a/vendor/quickjs-patches/manifest.json b/vendor/quickjs-patches/manifest.json new file mode 100644 index 0000000..08eb63a --- /dev/null +++ b/vendor/quickjs-patches/manifest.json @@ -0,0 +1,11 @@ +{ + "name": "blue-quickjs-patch-series", + "sourceRepoPath": "vendor/quickjs", + "baseCommit": "e5fd3918c1c4a2ee39016e71b66a9eeda85ce716", + "baseArchive": "vendor/quickjs-patches/upstream/quickjs-base-e5fd3918c1c4a2ee39016e71b66a9eeda85ce716.tar.gz", + "baseArchiveSha256": "a2ff2baaa328275baa490596f4751b85f1e39419b9f7f44c3e83e9fac9dc9217", + "headCommit": "8b3253bddf6a5a792dd098b1a8a154f534b88586", + "upstreamUrl": "https://github.com/bellard/quickjs.git", + "patchDirectory": "vendor/quickjs-patches/series", + "patchCount": 51 +} diff --git a/vendor/quickjs-patches/series/0001-feat-add-deterministic-runtime-support-with-disabled.patch b/vendor/quickjs-patches/series/0001-feat-add-deterministic-runtime-support-with-disabled.patch new file mode 100644 index 0000000..c8f3e61 --- /dev/null +++ b/vendor/quickjs-patches/series/0001-feat-add-deterministic-runtime-support-with-disabled.patch @@ -0,0 +1,207 @@ +From 254b5556bb4d50b8c7940000acb3797b78cd0185 Mon Sep 17 00:00:00 2001 +From: Mateusz Jonak +Date: Wed, 10 Dec 2025 22:00:03 +0100 +Subject: [PATCH 01/51] feat: Add deterministic runtime support with disabled + eval and function features + +This commit introduces a new deterministic runtime in QuickJS, allowing for controlled execution by disabling the 'eval' and 'Function' features. It includes functions to initialize the deterministic context and define properties for the host environment. The changes enhance the runtime's capabilities for deterministic execution scenarios. +--- + quickjs.c | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ + quickjs.h | 1 + + 2 files changed, 159 insertions(+) + +diff --git a/quickjs.c b/quickjs.c +index 6f461d6..d9e00bf 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -489,6 +489,8 @@ struct JSContext { + const char *input, size_t input_len, + const char *filename, int flags, int scope_idx); + void *user_opaque; ++ ++ BOOL deterministic_mode; + }; + + typedef union JSFloat64Union { +@@ -2221,6 +2223,158 @@ JSContext *JS_NewContext(JSRuntime *rt) + return ctx; + } + ++enum { ++ JS_DETERMINISTIC_DISABLED_EVAL = 1, ++ JS_DETERMINISTIC_DISABLED_FUNCTION = 2, ++}; ++ ++static const char *js_get_disabled_name(int magic) ++{ ++ switch (magic) { ++ case JS_DETERMINISTIC_DISABLED_FUNCTION: ++ return "Function"; ++ case JS_DETERMINISTIC_DISABLED_EVAL: ++ default: ++ return "eval"; ++ } ++} ++ ++static JSValue js_deterministic_disabled(JSContext *ctx, JSValueConst this_val, ++ int argc, JSValueConst *argv, int magic) ++{ ++ const char *name = js_get_disabled_name(magic); ++ return JS_ThrowTypeError(ctx, "%s is disabled in deterministic mode", name); ++} ++ ++static int js_deterministic_disable_eval(JSContext *ctx) ++{ ++ JSValue fn; ++ int ret; ++ ++ fn = JS_NewCFunctionMagic(ctx, js_deterministic_disabled, "eval", 1, ++ JS_CFUNC_generic_magic, JS_DETERMINISTIC_DISABLED_EVAL); ++ if (JS_IsException(fn)) ++ return -1; ++ ++ ret = JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_eval, JS_DupValue(ctx, fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ if (ret < 0) { ++ JS_FreeValue(ctx, fn); ++ return -1; ++ } ++ ++ JS_FreeValue(ctx, ctx->eval_obj); ++ ctx->eval_obj = JS_UNDEFINED; ++ JS_FreeValue(ctx, fn); ++ return 0; ++} ++ ++static int js_deterministic_disable_function(JSContext *ctx) ++{ ++ JSValue fn; ++ int ret; ++ ++ fn = JS_NewCFunctionMagic(ctx, js_deterministic_disabled, "Function", 1, ++ JS_CFUNC_constructor_or_func_magic, JS_DETERMINISTIC_DISABLED_FUNCTION); ++ if (JS_IsException(fn)) ++ return -1; ++ ++ ret = JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_Function, JS_DupValue(ctx, fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ JS_FreeValue(ctx, fn); ++ if (ret < 0) ++ return -1; ++ ++ return 0; ++} ++ ++static int js_deterministic_init_host(JSContext *ctx) ++{ ++ JSValue host_ns, host_v1; ++ int ret; ++ ++ host_ns = JS_NewObjectProto(ctx, JS_NULL); ++ if (JS_IsException(host_ns)) ++ return -1; ++ ++ host_v1 = JS_NewObjectProto(ctx, JS_NULL); ++ if (JS_IsException(host_v1)) { ++ JS_FreeValue(ctx, host_ns); ++ return -1; ++ } ++ ++ ret = JS_DefinePropertyValueStr(ctx, host_ns, "v1", JS_DupValue(ctx, host_v1), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ if (ret < 0) ++ goto fail; ++ ++ ret = JS_DefinePropertyValueStr(ctx, ctx->global_obj, "Host", JS_DupValue(ctx, host_ns), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ if (ret < 0) ++ goto fail; ++ ++ JS_FreeValue(ctx, host_ns); ++ JS_FreeValue(ctx, host_v1); ++ ++ return 0; ++ ++fail: ++ JS_FreeValue(ctx, host_ns); ++ JS_FreeValue(ctx, host_v1); ++ return -1; ++} ++ ++static int js_deterministic_init_context(JSContext *ctx) ++{ ++ if (JS_AddIntrinsicBaseObjects(ctx) || ++ JS_AddIntrinsicEval(ctx) || ++ JS_AddIntrinsicJSON(ctx) || ++ JS_AddIntrinsicMapSet(ctx) || ++ js_deterministic_disable_eval(ctx) || ++ js_deterministic_disable_function(ctx) || ++ js_deterministic_init_host(ctx)) { ++ return -1; ++ } ++ ctx->deterministic_mode = TRUE; ++ return 0; ++} ++ ++int JS_NewDeterministicRuntime(JSRuntime **out_rt, JSContext **out_ctx) ++{ ++ JSRuntime *rt; ++ JSContext *ctx; ++ ++ if (!out_rt || !out_ctx) ++ return -1; ++ ++ *out_rt = NULL; ++ *out_ctx = NULL; ++ ++ rt = JS_NewRuntime(); ++ if (!rt) ++ return -1; ++ ++ ctx = JS_NewContextRaw(rt); ++ if (!ctx) { ++ JS_FreeRuntime(rt); ++ return -1; ++ } ++ ++ if (js_deterministic_init_context(ctx)) { ++ JS_FreeContext(ctx); ++ JS_FreeRuntime(rt); ++ return -1; ++ } ++ ++ *out_rt = rt; ++ *out_ctx = ctx; ++ return 0; ++} ++ + void *JS_GetContextOpaque(JSContext *ctx) + { + return ctx->user_opaque; +@@ -40435,6 +40589,10 @@ static JSValue js_function_proto(JSContext *ctx, JSValueConst this_val, + static JSValue js_function_constructor(JSContext *ctx, JSValueConst new_target, + int argc, JSValueConst *argv, int magic) + { ++ if (unlikely(ctx->deterministic_mode)) { ++ return JS_ThrowTypeError(ctx, "Function constructor is disabled in deterministic mode"); ++ } ++ + JSFunctionKindEnum func_kind = magic; + int i, n, ret; + JSValue s, proto, obj = JS_UNDEFINED; +diff --git a/quickjs.h b/quickjs.h +index 92cc000..766d365 100644 +--- a/quickjs.h ++++ b/quickjs.h +@@ -383,6 +383,7 @@ void JS_RunGC(JSRuntime *rt); + JS_BOOL JS_IsLiveObject(JSRuntime *rt, JSValueConst obj); + + JSContext *JS_NewContext(JSRuntime *rt); ++int JS_NewDeterministicRuntime(JSRuntime **out_rt, JSContext **out_ctx); + void JS_FreeContext(JSContext *s); + JSContext *JS_DupContext(JSContext *ctx); + void *JS_GetContextOpaque(JSContext *ctx); diff --git a/vendor/quickjs-patches/series/0002-feat-add-support-for-deterministic-random-function-i.patch b/vendor/quickjs-patches/series/0002-feat-add-support-for-deterministic-random-function-i.patch new file mode 100644 index 0000000..d2cac99 --- /dev/null +++ b/vendor/quickjs-patches/series/0002-feat-add-support-for-deterministic-random-function-i.patch @@ -0,0 +1,81 @@ +From 2ce753ae916b18716bf62766d9c6b7e7e64505fc Mon Sep 17 00:00:00 2001 +From: Mateusz Jonak +Date: Wed, 10 Dec 2025 23:35:13 +0100 +Subject: [PATCH 02/51] feat: Add support for deterministic random function in + QuickJS + +This commit extends the deterministic runtime by introducing a mechanism to disable the 'Math.random' function. It includes a new function to handle the disabling and updates the context initialization to incorporate this feature, enhancing the control over random number generation in deterministic execution scenarios. +--- + quickjs.c | 37 +++++++++++++++++++++++++++++++++++++ + 1 file changed, 37 insertions(+) + +diff --git a/quickjs.c b/quickjs.c +index d9e00bf..905d8e2 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -2226,11 +2226,14 @@ JSContext *JS_NewContext(JSRuntime *rt) + enum { + JS_DETERMINISTIC_DISABLED_EVAL = 1, + JS_DETERMINISTIC_DISABLED_FUNCTION = 2, ++ JS_DETERMINISTIC_DISABLED_RANDOM = 3, + }; + + static const char *js_get_disabled_name(int magic) + { + switch (magic) { ++ case JS_DETERMINISTIC_DISABLED_RANDOM: ++ return "Math.random"; + case JS_DETERMINISTIC_DISABLED_FUNCTION: + return "Function"; + case JS_DETERMINISTIC_DISABLED_EVAL: +@@ -2290,6 +2293,38 @@ static int js_deterministic_disable_function(JSContext *ctx) + return 0; + } + ++static int js_deterministic_disable_random(JSContext *ctx) ++{ ++ JSValue math, fn; ++ int ret; ++ ++ math = JS_GetProperty(ctx, ctx->global_obj, JS_ATOM_Math); ++ if (JS_IsException(math)) ++ return -1; ++ if (!JS_IsObject(math)) { ++ JS_FreeValue(ctx, math); ++ return -1; ++ } ++ ++ fn = JS_NewCFunctionMagic(ctx, js_deterministic_disabled, "random", 0, ++ JS_CFUNC_generic_magic, JS_DETERMINISTIC_DISABLED_RANDOM); ++ if (JS_IsException(fn)) { ++ JS_FreeValue(ctx, math); ++ return -1; ++ } ++ ++ ret = JS_DefinePropertyValueStr(ctx, math, "random", JS_DupValue(ctx, fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ ++ JS_FreeValue(ctx, fn); ++ JS_FreeValue(ctx, math); ++ if (ret < 0) ++ return -1; ++ ++ return 0; ++} ++ + static int js_deterministic_init_host(JSContext *ctx) + { + JSValue host_ns, host_v1; +@@ -2336,9 +2371,11 @@ static int js_deterministic_init_context(JSContext *ctx) + JS_AddIntrinsicMapSet(ctx) || + js_deterministic_disable_eval(ctx) || + js_deterministic_disable_function(ctx) || ++ js_deterministic_disable_random(ctx) || + js_deterministic_init_host(ctx)) { + return -1; + } ++ ctx->random_state = 1; /* deterministic seed */ + ctx->deterministic_mode = TRUE; + return 0; + } diff --git a/vendor/quickjs-patches/series/0003-feat-add-support-for-disabling-promise-in-determinis.patch b/vendor/quickjs-patches/series/0003-feat-add-support-for-disabling-promise-in-determinis.patch new file mode 100644 index 0000000..9779404 --- /dev/null +++ b/vendor/quickjs-patches/series/0003-feat-add-support-for-disabling-promise-in-determinis.patch @@ -0,0 +1,90 @@ +From 783152591f42abfc9c39a31ff34e3fa67d83b58d Mon Sep 17 00:00:00 2001 +From: Mateusz Jonak +Date: Wed, 10 Dec 2025 23:40:38 +0100 +Subject: [PATCH 03/51] feat: Add support for disabling Promise in + deterministic runtime + +This commit introduces a new feature to the deterministic runtime in QuickJS, allowing the 'Promise' constructor to be disabled. It includes a function to handle the disabling and updates the context initialization to incorporate this feature, enhancing control over asynchronous operations in deterministic execution scenarios. +--- + quickjs.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 49 insertions(+) + +diff --git a/quickjs.c b/quickjs.c +index 905d8e2..dca0621 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -2227,11 +2227,14 @@ enum { + JS_DETERMINISTIC_DISABLED_EVAL = 1, + JS_DETERMINISTIC_DISABLED_FUNCTION = 2, + JS_DETERMINISTIC_DISABLED_RANDOM = 3, ++ JS_DETERMINISTIC_DISABLED_PROMISE = 4, + }; + + static const char *js_get_disabled_name(int magic) + { + switch (magic) { ++ case JS_DETERMINISTIC_DISABLED_PROMISE: ++ return "Promise"; + case JS_DETERMINISTIC_DISABLED_RANDOM: + return "Math.random"; + case JS_DETERMINISTIC_DISABLED_FUNCTION: +@@ -2325,6 +2328,51 @@ static int js_deterministic_disable_random(JSContext *ctx) + return 0; + } + ++static int js_deterministic_disable_promise(JSContext *ctx) ++{ ++ JSValue fn; ++ int ret; ++ ++ fn = JS_NewCFunctionMagic(ctx, js_deterministic_disabled, "Promise", 1, ++ JS_CFUNC_constructor_or_func_magic, JS_DETERMINISTIC_DISABLED_PROMISE); ++ if (JS_IsException(fn)) ++ return -1; ++ ++ ret = JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_Promise, JS_DupValue(ctx, fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ ++ /* Ensure async internals see the disabled ctor */ ++ JS_FreeValue(ctx, ctx->promise_ctor); ++ ctx->promise_ctor = JS_DupValue(ctx, fn); ++ ++ /* Mirror common Promise statics to the same disabled stub */ ++ JS_DefinePropertyValueStr(ctx, fn, "resolve", JS_DupValue(ctx, fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ JS_DefinePropertyValueStr(ctx, fn, "reject", JS_DupValue(ctx, fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ JS_DefinePropertyValueStr(ctx, fn, "all", JS_DupValue(ctx, fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ JS_DefinePropertyValueStr(ctx, fn, "race", JS_DupValue(ctx, fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ JS_DefinePropertyValueStr(ctx, fn, "any", JS_DupValue(ctx, fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ JS_DefinePropertyValueStr(ctx, fn, "allSettled", JS_DupValue(ctx, fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ ++ JS_FreeValue(ctx, fn); ++ if (ret < 0) ++ return -1; ++ ++ return 0; ++} ++ + static int js_deterministic_init_host(JSContext *ctx) + { + JSValue host_ns, host_v1; +@@ -2372,6 +2420,7 @@ static int js_deterministic_init_context(JSContext *ctx) + js_deterministic_disable_eval(ctx) || + js_deterministic_disable_function(ctx) || + js_deterministic_disable_random(ctx) || ++ js_deterministic_disable_promise(ctx) || + js_deterministic_init_host(ctx)) { + return -1; + } diff --git a/vendor/quickjs-patches/series/0004-feat-add-support-for-disabling-regexp-and-proxy-in-d.patch b/vendor/quickjs-patches/series/0004-feat-add-support-for-disabling-regexp-and-proxy-in-d.patch new file mode 100644 index 0000000..ffd89da --- /dev/null +++ b/vendor/quickjs-patches/series/0004-feat-add-support-for-disabling-regexp-and-proxy-in-d.patch @@ -0,0 +1,110 @@ +From 4be069acbbff89e08996a8d8cce2a682c650ce43 Mon Sep 17 00:00:00 2001 +From: Mateusz Jonak +Date: Wed, 10 Dec 2025 23:50:48 +0100 +Subject: [PATCH 04/51] feat: Add support for disabling RegExp and Proxy in + deterministic runtime + +This commit enhances the deterministic runtime in QuickJS by introducing the ability to disable the 'RegExp' and 'Proxy' constructors. It includes functions to handle the disabling of these features and updates the context initialization accordingly, providing greater control over the execution environment in deterministic scenarios. +--- + quickjs.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 62 insertions(+) + +diff --git a/quickjs.c b/quickjs.c +index dca0621..438e8f3 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -2228,11 +2228,17 @@ enum { + JS_DETERMINISTIC_DISABLED_FUNCTION = 2, + JS_DETERMINISTIC_DISABLED_RANDOM = 3, + JS_DETERMINISTIC_DISABLED_PROMISE = 4, ++ JS_DETERMINISTIC_DISABLED_REGEXP = 5, ++ JS_DETERMINISTIC_DISABLED_PROXY = 6, + }; + + static const char *js_get_disabled_name(int magic) + { + switch (magic) { ++ case JS_DETERMINISTIC_DISABLED_PROXY: ++ return "Proxy"; ++ case JS_DETERMINISTIC_DISABLED_REGEXP: ++ return "RegExp"; + case JS_DETERMINISTIC_DISABLED_PROMISE: + return "Promise"; + case JS_DETERMINISTIC_DISABLED_RANDOM: +@@ -2252,6 +2258,14 @@ static JSValue js_deterministic_disabled(JSContext *ctx, JSValueConst this_val, + return JS_ThrowTypeError(ctx, "%s is disabled in deterministic mode", name); + } + ++static JSValue js_deterministic_compile_regexp(JSContext *ctx, JSValueConst pattern, ++ JSValueConst flags) ++{ ++ (void)pattern; ++ (void)flags; ++ return JS_ThrowTypeError(ctx, "RegExp is disabled in deterministic mode"); ++} ++ + static int js_deterministic_disable_eval(JSContext *ctx) + { + JSValue fn; +@@ -2328,6 +2342,52 @@ static int js_deterministic_disable_random(JSContext *ctx) + return 0; + } + ++static int js_deterministic_disable_regexp(JSContext *ctx) ++{ ++ JSValue fn; ++ int ret; ++ ++ fn = JS_NewCFunctionMagic(ctx, js_deterministic_disabled, "RegExp", 2, ++ JS_CFUNC_constructor_or_func_magic, JS_DETERMINISTIC_DISABLED_REGEXP); ++ if (JS_IsException(fn)) ++ return -1; ++ ++ ret = JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_RegExp, JS_DupValue(ctx, fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ if (ret < 0) { ++ JS_FreeValue(ctx, fn); ++ return -1; ++ } ++ ++ JS_FreeValue(ctx, ctx->regexp_ctor); ++ ctx->regexp_ctor = JS_DupValue(ctx, fn); ++ ctx->compile_regexp = js_deterministic_compile_regexp; ++ ++ JS_FreeValue(ctx, fn); ++ return 0; ++} ++ ++static int js_deterministic_disable_proxy(JSContext *ctx) ++{ ++ JSValue fn; ++ int ret; ++ ++ fn = JS_NewCFunctionMagic(ctx, js_deterministic_disabled, "Proxy", 2, ++ JS_CFUNC_constructor_or_func_magic, JS_DETERMINISTIC_DISABLED_PROXY); ++ if (JS_IsException(fn)) ++ return -1; ++ ++ ret = JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_Proxy, JS_DupValue(ctx, fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ JS_FreeValue(ctx, fn); ++ if (ret < 0) ++ return -1; ++ ++ return 0; ++} ++ + static int js_deterministic_disable_promise(JSContext *ctx) + { + JSValue fn; +@@ -2419,6 +2479,8 @@ static int js_deterministic_init_context(JSContext *ctx) + JS_AddIntrinsicMapSet(ctx) || + js_deterministic_disable_eval(ctx) || + js_deterministic_disable_function(ctx) || ++ js_deterministic_disable_regexp(ctx) || ++ js_deterministic_disable_proxy(ctx) || + js_deterministic_disable_random(ctx) || + js_deterministic_disable_promise(ctx) || + js_deterministic_init_host(ctx)) { diff --git a/vendor/quickjs-patches/series/0005-feat-add-support-for-disabling-typed-arrays-webassem.patch b/vendor/quickjs-patches/series/0005-feat-add-support-for-disabling-typed-arrays-webassem.patch new file mode 100644 index 0000000..b46451a --- /dev/null +++ b/vendor/quickjs-patches/series/0005-feat-add-support-for-disabling-typed-arrays-webassem.patch @@ -0,0 +1,139 @@ +From d2a7b19ce971aaa315c881778ccb2172a659958b Mon Sep 17 00:00:00 2001 +From: Mateusz Jonak +Date: Thu, 11 Dec 2025 00:04:15 +0100 +Subject: [PATCH 05/51] feat: Add support for disabling Typed Arrays, + WebAssembly, and Atomics in deterministic runtime + +This commit enhances the deterministic runtime in QuickJS by introducing the ability to disable Typed Arrays, WebAssembly, and Atomics. It includes new functions to handle the disabling of these features and updates the context initialization accordingly, providing greater control over the execution environment in deterministic scenarios. +--- + quickjs.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 88 insertions(+) + +diff --git a/quickjs.c b/quickjs.c +index 438e8f3..99466f2 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -2230,11 +2230,29 @@ enum { + JS_DETERMINISTIC_DISABLED_PROMISE = 4, + JS_DETERMINISTIC_DISABLED_REGEXP = 5, + JS_DETERMINISTIC_DISABLED_PROXY = 6, ++ JS_DETERMINISTIC_DISABLED_TYPED_ARRAY = 7, ++ JS_DETERMINISTIC_DISABLED_ARRAY_BUFFER = 8, ++ JS_DETERMINISTIC_DISABLED_SHARED_ARRAY_BUFFER = 9, ++ JS_DETERMINISTIC_DISABLED_DATAVIEW = 10, ++ JS_DETERMINISTIC_DISABLED_WEBASSEMBLY = 11, ++ JS_DETERMINISTIC_DISABLED_ATOMICS = 12, + }; + + static const char *js_get_disabled_name(int magic) + { + switch (magic) { ++ case JS_DETERMINISTIC_DISABLED_ATOMICS: ++ return "Atomics"; ++ case JS_DETERMINISTIC_DISABLED_WEBASSEMBLY: ++ return "WebAssembly"; ++ case JS_DETERMINISTIC_DISABLED_DATAVIEW: ++ return "DataView"; ++ case JS_DETERMINISTIC_DISABLED_SHARED_ARRAY_BUFFER: ++ return "SharedArrayBuffer"; ++ case JS_DETERMINISTIC_DISABLED_ARRAY_BUFFER: ++ return "ArrayBuffer"; ++ case JS_DETERMINISTIC_DISABLED_TYPED_ARRAY: ++ return "Typed arrays"; + case JS_DETERMINISTIC_DISABLED_PROXY: + return "Proxy"; + case JS_DETERMINISTIC_DISABLED_REGEXP: +@@ -2255,9 +2273,32 @@ static JSValue js_deterministic_disabled(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int magic) + { + const char *name = js_get_disabled_name(magic); ++ if (magic == JS_DETERMINISTIC_DISABLED_TYPED_ARRAY) ++ return JS_ThrowTypeError(ctx, "%s are disabled in deterministic mode", name); + return JS_ThrowTypeError(ctx, "%s is disabled in deterministic mode", name); + } + ++static int js_deterministic_define_disabled_global(JSContext *ctx, const char *name, ++ int length, int magic) ++{ ++ JSValue fn; ++ int ret; ++ ++ fn = JS_NewCFunctionMagic(ctx, js_deterministic_disabled, name, length, ++ JS_CFUNC_constructor_or_func_magic, magic); ++ if (JS_IsException(fn)) ++ return -1; ++ ++ ret = JS_DefinePropertyValueStr(ctx, ctx->global_obj, name, JS_DupValue(ctx, fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ JS_FreeValue(ctx, fn); ++ if (ret < 0) ++ return -1; ++ ++ return 0; ++} ++ + static JSValue js_deterministic_compile_regexp(JSContext *ctx, JSValueConst pattern, + JSValueConst flags) + { +@@ -2433,6 +2474,50 @@ static int js_deterministic_disable_promise(JSContext *ctx) + return 0; + } + ++static int js_deterministic_disable_typed_arrays(JSContext *ctx) ++{ ++ static const struct { ++ const char *name; ++ int length; ++ int magic; ++ } entries[] = { ++ { "ArrayBuffer", 1, JS_DETERMINISTIC_DISABLED_ARRAY_BUFFER }, ++ { "SharedArrayBuffer", 1, JS_DETERMINISTIC_DISABLED_SHARED_ARRAY_BUFFER }, ++ { "DataView", 3, JS_DETERMINISTIC_DISABLED_DATAVIEW }, ++ { "Uint8Array", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, ++ { "Uint8ClampedArray", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, ++ { "Int8Array", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, ++ { "Uint16Array", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, ++ { "Int16Array", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, ++ { "Uint32Array", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, ++ { "Int32Array", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, ++ { "BigInt64Array", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, ++ { "BigUint64Array", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, ++ { "Float16Array", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, ++ { "Float32Array", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, ++ { "Float64Array", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, ++ }; ++ ++ for (size_t i = 0; i < countof(entries); i++) { ++ if (js_deterministic_define_disabled_global(ctx, entries[i].name, ++ entries[i].length, entries[i].magic)) ++ return -1; ++ } ++ return 0; ++} ++ ++static int js_deterministic_disable_webassembly(JSContext *ctx) ++{ ++ return js_deterministic_define_disabled_global(ctx, "WebAssembly", 1, ++ JS_DETERMINISTIC_DISABLED_WEBASSEMBLY); ++} ++ ++static int js_deterministic_disable_atomics(JSContext *ctx) ++{ ++ return js_deterministic_define_disabled_global(ctx, "Atomics", 3, ++ JS_DETERMINISTIC_DISABLED_ATOMICS); ++} ++ + static int js_deterministic_init_host(JSContext *ctx) + { + JSValue host_ns, host_v1; +@@ -2483,6 +2568,9 @@ static int js_deterministic_init_context(JSContext *ctx) + js_deterministic_disable_proxy(ctx) || + js_deterministic_disable_random(ctx) || + js_deterministic_disable_promise(ctx) || ++ js_deterministic_disable_typed_arrays(ctx) || ++ js_deterministic_disable_atomics(ctx) || ++ js_deterministic_disable_webassembly(ctx) || + js_deterministic_init_host(ctx)) { + return -1; + } diff --git a/vendor/quickjs-patches/series/0006-feat-add-support-for-disabling-console-and-print-in-.patch b/vendor/quickjs-patches/series/0006-feat-add-support-for-disabling-console-and-print-in-.patch new file mode 100644 index 0000000..06a60ee --- /dev/null +++ b/vendor/quickjs-patches/series/0006-feat-add-support-for-disabling-console-and-print-in-.patch @@ -0,0 +1,92 @@ +From 78f37b6d562bb0b0cec14248da46e6f9ee99694a Mon Sep 17 00:00:00 2001 +From: Mateusz Jonak +Date: Thu, 11 Dec 2025 00:06:44 +0100 +Subject: [PATCH 06/51] feat: Add support for disabling console and print in + deterministic runtime + +This commit enhances the deterministic runtime in QuickJS by introducing the ability to disable the 'console' and 'print' features. It includes new functions to handle the disabling of these features and updates the context initialization accordingly, providing greater control over the execution environment in deterministic scenarios. +--- + quickjs.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 51 insertions(+) + +diff --git a/quickjs.c b/quickjs.c +index 99466f2..7ab8406 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -2236,11 +2236,17 @@ enum { + JS_DETERMINISTIC_DISABLED_DATAVIEW = 10, + JS_DETERMINISTIC_DISABLED_WEBASSEMBLY = 11, + JS_DETERMINISTIC_DISABLED_ATOMICS = 12, ++ JS_DETERMINISTIC_DISABLED_CONSOLE = 13, ++ JS_DETERMINISTIC_DISABLED_PRINT = 14, + }; + + static const char *js_get_disabled_name(int magic) + { + switch (magic) { ++ case JS_DETERMINISTIC_DISABLED_PRINT: ++ return "print"; ++ case JS_DETERMINISTIC_DISABLED_CONSOLE: ++ return "console"; + case JS_DETERMINISTIC_DISABLED_ATOMICS: + return "Atomics"; + case JS_DETERMINISTIC_DISABLED_WEBASSEMBLY: +@@ -2518,6 +2524,49 @@ static int js_deterministic_disable_atomics(JSContext *ctx) + JS_DETERMINISTIC_DISABLED_ATOMICS); + } + ++static int js_deterministic_disable_console(JSContext *ctx) ++{ ++ JSValue console; ++ ++ console = JS_NewObjectProto(ctx, JS_NULL); ++ if (JS_IsException(console)) ++ return -1; ++ ++ static const char *const methods[] = { "log", "info", "warn", "error", "debug" }; ++ for (size_t i = 0; i < countof(methods); i++) { ++ JSValue fn = JS_NewCFunctionMagic(ctx, js_deterministic_disabled, "console", 1, ++ JS_CFUNC_generic_magic, JS_DETERMINISTIC_DISABLED_CONSOLE); ++ if (JS_IsException(fn)) { ++ JS_FreeValue(ctx, console); ++ return -1; ++ } ++ if (JS_DefinePropertyValueStr(ctx, console, methods[i], JS_DupValue(ctx, fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE) < 0) { ++ JS_FreeValue(ctx, fn); ++ JS_FreeValue(ctx, console); ++ return -1; ++ } ++ JS_FreeValue(ctx, fn); ++ } ++ ++ if (JS_DefinePropertyValueStr(ctx, ctx->global_obj, "console", JS_DupValue(ctx, console), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE) < 0) { ++ JS_FreeValue(ctx, console); ++ return -1; ++ } ++ ++ JS_FreeValue(ctx, console); ++ return 0; ++} ++ ++static int js_deterministic_disable_print(JSContext *ctx) ++{ ++ return js_deterministic_define_disabled_global(ctx, "print", 1, ++ JS_DETERMINISTIC_DISABLED_PRINT); ++} ++ + static int js_deterministic_init_host(JSContext *ctx) + { + JSValue host_ns, host_v1; +@@ -2570,6 +2619,8 @@ static int js_deterministic_init_context(JSContext *ctx) + js_deterministic_disable_promise(ctx) || + js_deterministic_disable_typed_arrays(ctx) || + js_deterministic_disable_atomics(ctx) || ++ js_deterministic_disable_console(ctx) || ++ js_deterministic_disable_print(ctx) || + js_deterministic_disable_webassembly(ctx) || + js_deterministic_init_host(ctx)) { + return -1; diff --git a/vendor/quickjs-patches/series/0007-feat-add-support-for-preventing-extensions-in-determ.patch b/vendor/quickjs-patches/series/0007-feat-add-support-for-preventing-extensions-in-determ.patch new file mode 100644 index 0000000..cb99000 --- /dev/null +++ b/vendor/quickjs-patches/series/0007-feat-add-support-for-preventing-extensions-in-determ.patch @@ -0,0 +1,25 @@ +From d6758d3402c323a696abf75ed00b3a4d2458b20d Mon Sep 17 00:00:00 2001 +From: Mateusz Jonak +Date: Thu, 11 Dec 2025 00:13:57 +0100 +Subject: [PATCH 07/51] feat: Add support for preventing extensions in + deterministic runtime + +This commit enhances the deterministic runtime in QuickJS by introducing the ability to prevent extensions on host objects. It includes checks to ensure that extensions are disabled during context initialization, further improving control over the execution environment in deterministic scenarios. +--- + quickjs.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/quickjs.c b/quickjs.c +index 7ab8406..f6cdb03 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -2594,6 +2594,9 @@ static int js_deterministic_init_host(JSContext *ctx) + if (ret < 0) + goto fail; + ++ if (JS_PreventExtensions(ctx, host_v1) < 0 || JS_PreventExtensions(ctx, host_ns) < 0) ++ goto fail; ++ + JS_FreeValue(ctx, host_ns); + JS_FreeValue(ctx, host_v1); + diff --git a/vendor/quickjs-patches/series/0008-feat-introduce-gas-management-in-quickjs-runtime.patch b/vendor/quickjs-patches/series/0008-feat-introduce-gas-management-in-quickjs-runtime.patch new file mode 100644 index 0000000..cd847a2 --- /dev/null +++ b/vendor/quickjs-patches/series/0008-feat-introduce-gas-management-in-quickjs-runtime.patch @@ -0,0 +1,407 @@ +From 3503ee976b61f4efa939243839885d9c2a3f3704 Mon Sep 17 00:00:00 2001 +From: Mateusz Jonak +Date: Thu, 11 Dec 2025 09:52:57 +0100 +Subject: [PATCH 08/51] feat: Introduce gas management in QuickJS runtime + +This commit adds a gas management system to the QuickJS runtime, allowing for resource usage tracking and control. It introduces new functions to set gas limits, check remaining gas, and handle out-of-gas scenarios. The changes enhance the deterministic runtime by providing mechanisms to prevent excessive resource consumption during execution, improving overall control in deterministic environments. +--- + quickjs.c | 234 +++++++++++++++++++++++++++++++++++++++++++++++++++++- + quickjs.h | 8 ++ + 2 files changed, 238 insertions(+), 4 deletions(-) + +diff --git a/quickjs.c b/quickjs.c +index f6cdb03..2ee5695 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -490,6 +490,10 @@ struct JSContext { + const char *filename, int flags, int scope_idx); + void *user_opaque; + ++ uint64_t gas_limit; ++ uint64_t gas_remaining; ++ uint32_t gas_version; ++ + BOOL deterministic_mode; + }; + +@@ -1087,6 +1091,23 @@ enum OPCodeEnum { + OP_TEMP_END, + }; + ++static const uint16_t js_opcode_gas_cost[OP_COUNT] = { ++#define FMT(f) ++#define DEF(id, size, n_pop, n_push, f) [OP_ ## id] = 1, ++#define def(id, size, n_pop, n_push, f) ++#include "quickjs-opcode.h" ++#undef def ++#undef DEF ++#undef FMT ++}; ++ ++static inline uint16_t js_get_opcode_gas_cost(uint8_t opcode) ++{ ++ if (opcode < OP_COUNT) ++ return js_opcode_gas_cost[opcode]; ++ return 0; ++} ++ + static int JS_InitAtoms(JSRuntime *rt); + static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len, + int atom_type); +@@ -2189,6 +2210,9 @@ JSContext *JS_NewContextRaw(JSRuntime *rt) + ctx->iterator_ctor = JS_NULL; + ctx->regexp_ctor = JS_NULL; + ctx->promise_ctor = JS_NULL; ++ ctx->gas_limit = JS_GAS_UNLIMITED; ++ ctx->gas_remaining = JS_GAS_UNLIMITED; ++ ctx->gas_version = JS_GAS_VERSION_LATEST; + init_list_head(&ctx->loaded_modules); + + if (JS_AddIntrinsicBasicObjects(ctx)) { +@@ -2238,11 +2262,20 @@ enum { + JS_DETERMINISTIC_DISABLED_ATOMICS = 12, + JS_DETERMINISTIC_DISABLED_CONSOLE = 13, + JS_DETERMINISTIC_DISABLED_PRINT = 14, ++ JS_DETERMINISTIC_DISABLED_JSON_PARSE = 15, ++ JS_DETERMINISTIC_DISABLED_JSON_STRINGIFY = 16, ++ JS_DETERMINISTIC_DISABLED_ARRAY_SORT = 17, + }; + + static const char *js_get_disabled_name(int magic) + { + switch (magic) { ++ case JS_DETERMINISTIC_DISABLED_ARRAY_SORT: ++ return "Array.prototype.sort"; ++ case JS_DETERMINISTIC_DISABLED_JSON_STRINGIFY: ++ return "JSON.stringify"; ++ case JS_DETERMINISTIC_DISABLED_JSON_PARSE: ++ return "JSON.parse"; + case JS_DETERMINISTIC_DISABLED_PRINT: + return "print"; + case JS_DETERMINISTIC_DISABLED_CONSOLE: +@@ -2567,6 +2600,99 @@ static int js_deterministic_disable_print(JSContext *ctx) + JS_DETERMINISTIC_DISABLED_PRINT); + } + ++static int js_deterministic_disable_json(JSContext *ctx) ++{ ++ JSValue json, parse_fn, stringify_fn; ++ int ret; ++ ++ json = JS_GetProperty(ctx, ctx->global_obj, JS_ATOM_JSON); ++ if (JS_IsException(json)) ++ return -1; ++ if (!JS_IsObject(json)) { ++ JS_FreeValue(ctx, json); ++ return -1; ++ } ++ ++ parse_fn = JS_NewCFunctionMagic(ctx, js_deterministic_disabled, "parse", 2, ++ JS_CFUNC_generic_magic, JS_DETERMINISTIC_DISABLED_JSON_PARSE); ++ if (JS_IsException(parse_fn)) { ++ JS_FreeValue(ctx, json); ++ return -1; ++ } ++ stringify_fn = JS_NewCFunctionMagic(ctx, js_deterministic_disabled, "stringify", 3, ++ JS_CFUNC_generic_magic, JS_DETERMINISTIC_DISABLED_JSON_STRINGIFY); ++ if (JS_IsException(stringify_fn)) { ++ JS_FreeValue(ctx, parse_fn); ++ JS_FreeValue(ctx, json); ++ return -1; ++ } ++ ++ ret = JS_DefinePropertyValueStr(ctx, json, "parse", JS_DupValue(ctx, parse_fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ if (ret < 0) ++ goto fail; ++ ++ ret = JS_DefinePropertyValueStr(ctx, json, "stringify", JS_DupValue(ctx, stringify_fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ if (ret < 0) ++ goto fail; ++ ++ JS_FreeValue(ctx, parse_fn); ++ JS_FreeValue(ctx, stringify_fn); ++ JS_FreeValue(ctx, json); ++ return 0; ++ ++fail: ++ JS_FreeValue(ctx, parse_fn); ++ JS_FreeValue(ctx, stringify_fn); ++ JS_FreeValue(ctx, json); ++ return -1; ++} ++ ++static int js_deterministic_disable_array_sort(JSContext *ctx) ++{ ++ JSValue array_ctor, array_proto, sort_fn; ++ int ret; ++ ++ array_ctor = JS_GetProperty(ctx, ctx->global_obj, JS_ATOM_Array); ++ if (JS_IsException(array_ctor)) ++ return -1; ++ if (!JS_IsObject(array_ctor)) { ++ JS_FreeValue(ctx, array_ctor); ++ return -1; ++ } ++ ++ array_proto = JS_GetProperty(ctx, array_ctor, JS_ATOM_prototype); ++ if (JS_IsException(array_proto)) { ++ JS_FreeValue(ctx, array_ctor); ++ return -1; ++ } ++ JS_FreeValue(ctx, array_ctor); ++ if (!JS_IsObject(array_proto)) { ++ JS_FreeValue(ctx, array_proto); ++ return -1; ++ } ++ ++ sort_fn = JS_NewCFunctionMagic(ctx, js_deterministic_disabled, "sort", 1, ++ JS_CFUNC_generic_magic, JS_DETERMINISTIC_DISABLED_ARRAY_SORT); ++ if (JS_IsException(sort_fn)) { ++ JS_FreeValue(ctx, array_proto); ++ return -1; ++ } ++ ++ ret = JS_DefinePropertyValueStr(ctx, array_proto, "sort", JS_DupValue(ctx, sort_fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ ++ JS_FreeValue(ctx, sort_fn); ++ JS_FreeValue(ctx, array_proto); ++ if (ret < 0) ++ return -1; ++ return 0; ++} ++ + static int js_deterministic_init_host(JSContext *ctx) + { + JSValue host_ns, host_v1; +@@ -2624,6 +2750,8 @@ static int js_deterministic_init_context(JSContext *ctx) + js_deterministic_disable_atomics(ctx) || + js_deterministic_disable_console(ctx) || + js_deterministic_disable_print(ctx) || ++ js_deterministic_disable_json(ctx) || ++ js_deterministic_disable_array_sort(ctx) || + js_deterministic_disable_webassembly(ctx) || + js_deterministic_init_host(ctx)) { + return -1; +@@ -2675,6 +2803,75 @@ void JS_SetContextOpaque(JSContext *ctx, void *opaque) + ctx->user_opaque = opaque; + } + ++static JSValue JS_ThrowOutOfGas(JSContext *ctx) ++{ ++ JSValue obj, name, message, code; ++ ++ obj = JS_NewError(ctx); ++ if (JS_IsException(obj)) ++ return JS_EXCEPTION; ++ ++ name = JS_NewString(ctx, "OutOfGas"); ++ message = JS_NewString(ctx, "out of gas"); ++ code = JS_NewString(ctx, "OOG"); ++ if (JS_IsException(name) || JS_IsException(message) || JS_IsException(code)) { ++ if (!JS_IsException(name)) ++ JS_FreeValue(ctx, name); ++ if (!JS_IsException(message)) ++ JS_FreeValue(ctx, message); ++ if (!JS_IsException(code)) ++ JS_FreeValue(ctx, code); ++ JS_FreeValue(ctx, obj); ++ return JS_EXCEPTION; ++ } ++ ++ JS_DefinePropertyValue(ctx, obj, JS_ATOM_name, name, ++ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); ++ JS_DefinePropertyValue(ctx, obj, JS_ATOM_message, message, ++ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); ++ JS_DefinePropertyValueStr(ctx, obj, "code", code, ++ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); ++ JS_Throw(ctx, obj); ++ JS_SetUncatchableException(ctx, TRUE); ++ return JS_EXCEPTION; ++} ++ ++void JS_SetGasLimit(JSContext *ctx, uint64_t gas_limit) ++{ ++ ctx->gas_limit = gas_limit; ++ ctx->gas_remaining = gas_limit; ++} ++ ++uint64_t JS_GetGasRemaining(JSContext *ctx) ++{ ++ return ctx->gas_remaining; ++} ++ ++uint64_t JS_GetGasLimit(JSContext *ctx) ++{ ++ return ctx->gas_limit; ++} ++ ++uint32_t JS_GetGasVersion(JSContext *ctx) ++{ ++ return ctx->gas_version; ++} ++ ++int JS_UseGas(JSContext *ctx, uint64_t amount) ++{ ++ if (ctx->gas_limit == JS_GAS_UNLIMITED) ++ return 0; ++ if (amount == 0) ++ return 0; ++ if (amount > ctx->gas_remaining) { ++ ctx->gas_remaining = 0; ++ JS_ThrowOutOfGas(ctx); ++ return -1; ++ } ++ ctx->gas_remaining -= amount; ++ return 0; ++} ++ + /* set the new value and free the old value after (freeing the value + can reallocate the object data) */ + static inline void set_value(JSContext *ctx, JSValue *pval, JSValue new_val) +@@ -17813,7 +18010,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, + size_t alloca_size; + + #if !DIRECT_DISPATCH +-#define SWITCH(pc) switch (opcode = *pc++) ++#define DISPATCH() switch (opcode) + #define CASE(op) case op + #define DEFAULT default + #define BREAK break +@@ -17828,10 +18025,10 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, + #include "quickjs-opcode.h" + [ OP_COUNT ... 255 ] = &&case_default + }; +-#define SWITCH(pc) goto *dispatch_table[opcode = *pc++]; ++#define DISPATCH() goto *dispatch_table[opcode] + #define CASE(op) case_ ## op + #define DEFAULT case_default +-#define BREAK SWITCH(pc) ++#define BREAK goto dispatch_next + #endif + + if (js_poll_interrupts(caller_ctx)) +@@ -17924,8 +18121,16 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, + for(;;) { + int call_argc; + JSValue *call_argv; ++ opcode = *pc++; ++ uint16_t gas_cost = js_get_opcode_gas_cost(opcode); ++ if (unlikely(JS_UseGas(ctx, gas_cost) != 0)) ++ goto exception; + +- SWITCH(pc) { ++ #if !DIRECT_DISPATCH ++ DISPATCH() { ++ #else ++ DISPATCH(); ++ #endif + CASE(OP_push_i32): + *sp++ = JS_NewInt32(ctx, get_u32(pc)); + pc += 4; +@@ -20505,7 +20710,13 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, + JS_ThrowInternalError(ctx, "invalid opcode: pc=%u opcode=0x%02x", + (int)(pc - b->byte_code_buf - 1), opcode); + goto exception; ++#if !DIRECT_DISPATCH + } ++#endif ++#if DIRECT_DISPATCH ++ dispatch_next: ++ ; ++#endif + } + exception: + if (is_backtrace_needed(ctx, rt->current_exception)) { +@@ -41925,6 +42136,9 @@ exception: + #define special_filter 4 + #define special_TA 8 + ++#define JS_GAS_ARRAY_CB_BASE 5 ++#define JS_GAS_ARRAY_CB_PER_ELEMENT 2 ++ + static JSValue js_typed_array___speciesCreate(JSContext *ctx, + JSValueConst this_val, + int argc, JSValueConst *argv); +@@ -41938,8 +42152,11 @@ static JSValue js_array_every(JSContext *ctx, JSValueConst this_val, + int64_t len, k, n; + int present; + ++ obj = JS_UNDEFINED; + ret = JS_UNDEFINED; + val = JS_UNDEFINED; ++ if (unlikely(JS_UseGas(ctx, JS_GAS_ARRAY_CB_BASE) != 0)) ++ goto exception; + if (special & special_TA) { + obj = JS_DupValue(ctx, this_val); + len = js_typed_array_get_length_unsafe(ctx, obj); +@@ -41994,6 +42211,8 @@ static JSValue js_array_every(JSContext *ctx, JSValueConst this_val, + n = 0; + + for(k = 0; k < len; k++) { ++ if (unlikely(JS_UseGas(ctx, JS_GAS_ARRAY_CB_PER_ELEMENT) != 0)) ++ goto exception; + if (special & special_TA) { + val = JS_GetPropertyInt64(ctx, obj, k); + if (JS_IsException(val)) +@@ -42095,8 +42314,11 @@ static JSValue js_array_reduce(JSContext *ctx, JSValueConst this_val, + int64_t len, k, k1; + int present; + ++ obj = JS_UNDEFINED; + acc = JS_UNDEFINED; + val = JS_UNDEFINED; ++ if (unlikely(JS_UseGas(ctx, JS_GAS_ARRAY_CB_BASE) != 0)) ++ goto exception; + if (special & special_TA) { + obj = JS_DupValue(ctx, this_val); + len = js_typed_array_get_length_unsafe(ctx, obj); +@@ -42117,6 +42339,8 @@ static JSValue js_array_reduce(JSContext *ctx, JSValueConst this_val, + acc = JS_DupValue(ctx, argv[1]); + } else { + for(;;) { ++ if (unlikely(JS_UseGas(ctx, JS_GAS_ARRAY_CB_PER_ELEMENT) != 0)) ++ goto exception; + if (k >= len) { + JS_ThrowTypeError(ctx, "empty array"); + goto exception; +@@ -42139,6 +42363,8 @@ static JSValue js_array_reduce(JSContext *ctx, JSValueConst this_val, + } + for (; k < len; k++) { + k1 = (special & special_reduceRight) ? len - k - 1 : k; ++ if (unlikely(JS_UseGas(ctx, JS_GAS_ARRAY_CB_PER_ELEMENT) != 0)) ++ goto exception; + if (special & special_TA) { + val = JS_GetPropertyInt64(ctx, obj, k1); + if (JS_IsException(val)) +diff --git a/quickjs.h b/quickjs.h +index 766d365..afcebe5 100644 +--- a/quickjs.h ++++ b/quickjs.h +@@ -347,6 +347,9 @@ typedef JSValue JSCFunction(JSContext *ctx, JSValueConst this_val, int argc, JSV + typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); + typedef JSValue JSCFunctionData(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic, JSValue *func_data); + ++#define JS_GAS_VERSION_LATEST 1 ++#define JS_GAS_UNLIMITED UINT64_C(0xffffffffffffffff) ++ + typedef struct JSMallocState { + size_t malloc_count; + size_t malloc_size; +@@ -388,6 +391,11 @@ void JS_FreeContext(JSContext *s); + JSContext *JS_DupContext(JSContext *ctx); + void *JS_GetContextOpaque(JSContext *ctx); + void JS_SetContextOpaque(JSContext *ctx, void *opaque); ++void JS_SetGasLimit(JSContext *ctx, uint64_t gas_limit); ++uint64_t JS_GetGasRemaining(JSContext *ctx); ++uint64_t JS_GetGasLimit(JSContext *ctx); ++uint32_t JS_GetGasVersion(JSContext *ctx); ++int JS_UseGas(JSContext *ctx, uint64_t amount); + JSRuntime *JS_GetRuntime(JSContext *ctx); + void JS_SetClassProto(JSContext *ctx, JSClassID class_id, JSValue obj); + JSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id); diff --git a/vendor/quickjs-patches/series/0009-feat-implement-gas-allocation-tracking-in-memory-man.patch b/vendor/quickjs-patches/series/0009-feat-implement-gas-allocation-tracking-in-memory-man.patch new file mode 100644 index 0000000..787804e --- /dev/null +++ b/vendor/quickjs-patches/series/0009-feat-implement-gas-allocation-tracking-in-memory-man.patch @@ -0,0 +1,179 @@ +From 0b191267eb0bc0e287c95b37fbb434a5c1db04a7 Mon Sep 17 00:00:00 2001 +From: Mateusz Jonak +Date: Thu, 11 Dec 2025 12:57:05 +0100 +Subject: [PATCH 09/51] feat: Implement gas allocation tracking in memory + management functions + +This commit enhances the QuickJS runtime by introducing gas allocation tracking in memory management functions. It adds a mechanism to charge gas for memory allocations, preventing excessive resource consumption. The changes include new functions for calculating gas costs and handling out-of-gas scenarios, improving control over resource usage in deterministic environments. +--- + quickjs.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 69 insertions(+), 6 deletions(-) + +diff --git a/quickjs.c b/quickjs.c +index 2ee5695..a3efc3f 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -274,6 +274,8 @@ struct JSRuntime { + BOOL current_exception_is_uncatchable : 8; + /* true if inside an out of memory error, to avoid recursing */ + BOOL in_out_of_memory : 8; ++ /* true if inside out-of-gas handling to avoid recursion */ ++ BOOL in_out_of_gas : 8; + + struct JSStackFrame *current_stack_frame; + +@@ -1394,6 +1396,39 @@ static void js_trigger_gc(JSRuntime *rt, size_t size) + } + } + ++#define JS_GAS_ALLOC_BASE 3 ++#define JS_GAS_ALLOC_PER_BYTE_SHIFT 4 ++ ++static uint64_t js_gas_allocation_cost(size_t size) ++{ ++ const uint64_t unit = UINT64_C(1) << JS_GAS_ALLOC_PER_BYTE_SHIFT; ++ uint64_t units; ++ ++ if (size == 0) { ++ units = 0; ++ } else if (size > UINT64_MAX - (unit - 1)) { ++ units = UINT64_MAX; ++ } else { ++ units = ((uint64_t)size + (unit - 1)) >> JS_GAS_ALLOC_PER_BYTE_SHIFT; ++ } ++ ++ if (units > UINT64_MAX - JS_GAS_ALLOC_BASE) ++ return UINT64_MAX; ++ return JS_GAS_ALLOC_BASE + units; ++} ++ ++static int js_charge_gas_allocation_ctx(JSContext *ctx, size_t size) ++{ ++ JSRuntime *rt = ctx->rt; ++ ++ if (ctx->gas_limit == JS_GAS_UNLIMITED) ++ return 0; ++ if (rt->in_out_of_gas || rt->current_exception_is_uncatchable) ++ return 0; ++ ++ return JS_UseGas(ctx, js_gas_allocation_cost(size)); ++} ++ + static size_t js_malloc_usable_size_unknown(const void *ptr) + { + return 0; +@@ -1432,9 +1467,12 @@ void *js_mallocz_rt(JSRuntime *rt, size_t size) + void *js_malloc(JSContext *ctx, size_t size) + { + void *ptr; ++ if (size != 0 && js_charge_gas_allocation_ctx(ctx, size)) ++ return NULL; + ptr = js_malloc_rt(ctx->rt, size); + if (unlikely(!ptr)) { +- JS_ThrowOutOfMemory(ctx); ++ if (JS_IsUninitialized(ctx->rt->current_exception)) ++ JS_ThrowOutOfMemory(ctx); + return NULL; + } + return ptr; +@@ -1444,9 +1482,12 @@ void *js_malloc(JSContext *ctx, size_t size) + void *js_mallocz(JSContext *ctx, size_t size) + { + void *ptr; ++ if (size != 0 && js_charge_gas_allocation_ctx(ctx, size)) ++ return NULL; + ptr = js_mallocz_rt(ctx->rt, size); + if (unlikely(!ptr)) { +- JS_ThrowOutOfMemory(ctx); ++ if (JS_IsUninitialized(ctx->rt->current_exception)) ++ JS_ThrowOutOfMemory(ctx); + return NULL; + } + return ptr; +@@ -1461,9 +1502,12 @@ void js_free(JSContext *ctx, void *ptr) + void *js_realloc(JSContext *ctx, void *ptr, size_t size) + { + void *ret; ++ if (size != 0 && js_charge_gas_allocation_ctx(ctx, size)) ++ return NULL; + ret = js_realloc_rt(ctx->rt, ptr, size); + if (unlikely(!ret && size != 0)) { +- JS_ThrowOutOfMemory(ctx); ++ if (JS_IsUninitialized(ctx->rt->current_exception)) ++ JS_ThrowOutOfMemory(ctx); + return NULL; + } + return ret; +@@ -1473,9 +1517,12 @@ void *js_realloc(JSContext *ctx, void *ptr, size_t size) + void *js_realloc2(JSContext *ctx, void *ptr, size_t size, size_t *pslack) + { + void *ret; ++ if (size != 0 && js_charge_gas_allocation_ctx(ctx, size)) ++ return NULL; + ret = js_realloc_rt(ctx->rt, ptr, size); + if (unlikely(!ret && size != 0)) { +- JS_ThrowOutOfMemory(ctx); ++ if (JS_IsUninitialized(ctx->rt->current_exception)) ++ JS_ThrowOutOfMemory(ctx); + return NULL; + } + if (pslack) { +@@ -1720,6 +1767,7 @@ JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque) + JS_UpdateStackTop(rt); + + rt->current_exception = JS_UNINITIALIZED; ++ rt->in_out_of_gas = FALSE; + + return rt; + fail: +@@ -1968,6 +2016,11 @@ static JSString *js_alloc_string_rt(JSRuntime *rt, int max_len, int is_wide_char + static JSString *js_alloc_string(JSContext *ctx, int max_len, int is_wide_char) + { + JSString *p; ++ size_t alloc_size = sizeof(JSString) + ++ (((size_t)max_len << is_wide_char) + 1 - is_wide_char); ++ ++ if (js_charge_gas_allocation_ctx(ctx, alloc_size)) ++ return NULL; + p = js_alloc_string_rt(ctx->rt, max_len, is_wide_char); + if (unlikely(!p)) { + JS_ThrowOutOfMemory(ctx); +@@ -2805,11 +2858,16 @@ void JS_SetContextOpaque(JSContext *ctx, void *opaque) + + static JSValue JS_ThrowOutOfGas(JSContext *ctx) + { ++ JSRuntime *rt = ctx->rt; + JSValue obj, name, message, code; + ++ if (rt->in_out_of_gas) ++ return JS_EXCEPTION; ++ ++ rt->in_out_of_gas = TRUE; + obj = JS_NewError(ctx); + if (JS_IsException(obj)) +- return JS_EXCEPTION; ++ goto fail; + + name = JS_NewString(ctx, "OutOfGas"); + message = JS_NewString(ctx, "out of gas"); +@@ -2822,7 +2880,7 @@ static JSValue JS_ThrowOutOfGas(JSContext *ctx) + if (!JS_IsException(code)) + JS_FreeValue(ctx, code); + JS_FreeValue(ctx, obj); +- return JS_EXCEPTION; ++ goto fail; + } + + JS_DefinePropertyValue(ctx, obj, JS_ATOM_name, name, +@@ -2833,6 +2891,11 @@ static JSValue JS_ThrowOutOfGas(JSContext *ctx) + JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); + JS_Throw(ctx, obj); + JS_SetUncatchableException(ctx, TRUE); ++ rt->in_out_of_gas = FALSE; ++ return JS_EXCEPTION; ++ ++fail: ++ rt->in_out_of_gas = FALSE; + return JS_EXCEPTION; + } + diff --git a/vendor/quickjs-patches/series/0010-feat-enhance-deterministic-runtime-with-garbage-coll.patch b/vendor/quickjs-patches/series/0010-feat-enhance-deterministic-runtime-with-garbage-coll.patch new file mode 100644 index 0000000..261bd36 --- /dev/null +++ b/vendor/quickjs-patches/series/0010-feat-enhance-deterministic-runtime-with-garbage-coll.patch @@ -0,0 +1,104 @@ +From f7dcf2d22dd1b3ec2270db0a01d2fbf2c58bfa06 Mon Sep 17 00:00:00 2001 +From: Mateusz Jonak +Date: Thu, 11 Dec 2025 14:48:56 +0100 +Subject: [PATCH 10/51] feat: Enhance deterministic runtime with garbage + collection improvements + +This commit introduces new features to the QuickJS deterministic runtime, including support for a checkpoint-based garbage collection mechanism. It adds fields to track the state of deterministic garbage collection and modifies the garbage collection trigger to respect the deterministic mode. Additionally, a new function, JS_RunGCCheckpoint, is implemented to manage garbage collection in a controlled manner, improving resource management in deterministic environments. +--- + quickjs.c | 34 ++++++++++++++++++++++++++++++++++ + quickjs.h | 1 + + 2 files changed, 35 insertions(+) + +diff --git a/quickjs.c b/quickjs.c +index a3efc3f..1c80298 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -260,6 +260,9 @@ struct JSRuntime { + struct list_head tmp_obj_list; /* used during GC */ + JSGCPhaseEnum gc_phase : 8; + size_t malloc_gc_threshold; ++ BOOL deterministic_mode : 8; ++ BOOL det_gc_pending : 8; ++ uint64_t det_gc_alloc_bytes; + struct list_head weakref_list; /* list of JSWeakRefHeader.link */ + #ifdef DUMP_LEAKS + struct list_head string_list; /* list of JSString.link */ +@@ -1379,6 +1382,9 @@ static JSClassID js_class_id_alloc = JS_CLASS_INIT_COUNT; + static void js_trigger_gc(JSRuntime *rt, size_t size) + { + BOOL force_gc; ++ ++ if (rt->deterministic_mode) ++ return; + #ifdef FORCE_GC_AT_MALLOC + force_gc = TRUE; + #else +@@ -1398,6 +1404,7 @@ static void js_trigger_gc(JSRuntime *rt, size_t size) + + #define JS_GAS_ALLOC_BASE 3 + #define JS_GAS_ALLOC_PER_BYTE_SHIFT 4 ++#define JS_DET_GC_THRESHOLD_BYTES (512 * 1024) + + static uint64_t js_gas_allocation_cost(size_t size) + { +@@ -1426,6 +1433,12 @@ static int js_charge_gas_allocation_ctx(JSContext *ctx, size_t size) + if (rt->in_out_of_gas || rt->current_exception_is_uncatchable) + return 0; + ++ if (rt->deterministic_mode) { ++ rt->det_gc_alloc_bytes += size; ++ if (rt->det_gc_alloc_bytes >= JS_DET_GC_THRESHOLD_BYTES) ++ rt->det_gc_pending = TRUE; ++ } ++ + return JS_UseGas(ctx, js_gas_allocation_cost(size)); + } + +@@ -2829,6 +2842,11 @@ int JS_NewDeterministicRuntime(JSRuntime **out_rt, JSContext **out_ctx) + if (!rt) + return -1; + ++ rt->deterministic_mode = TRUE; ++ rt->det_gc_pending = FALSE; ++ rt->det_gc_alloc_bytes = 0; ++ JS_SetGCThreshold(rt, (size_t)-1); ++ + ctx = JS_NewContextRaw(rt); + if (!ctx) { + JS_FreeRuntime(rt); +@@ -2935,6 +2953,22 @@ int JS_UseGas(JSContext *ctx, uint64_t amount) + return 0; + } + ++int JS_RunGCCheckpoint(JSContext *ctx) ++{ ++ JSRuntime *rt = ctx->rt; ++ ++ if (rt->current_exception_is_uncatchable || rt->in_out_of_gas) ++ return 0; ++ ++ if (rt->deterministic_mode && !rt->det_gc_pending) ++ return 0; ++ ++ JS_RunGC(rt); ++ rt->det_gc_pending = FALSE; ++ rt->det_gc_alloc_bytes = 0; ++ return 0; ++} ++ + /* set the new value and free the old value after (freeing the value + can reallocate the object data) */ + static inline void set_value(JSContext *ctx, JSValue *pval, JSValue new_val) +diff --git a/quickjs.h b/quickjs.h +index afcebe5..a027514 100644 +--- a/quickjs.h ++++ b/quickjs.h +@@ -383,6 +383,7 @@ void JS_SetRuntimeOpaque(JSRuntime *rt, void *opaque); + typedef void JS_MarkFunc(JSRuntime *rt, JSGCObjectHeader *gp); + void JS_MarkValue(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); + void JS_RunGC(JSRuntime *rt); ++int JS_RunGCCheckpoint(JSContext *ctx); + JS_BOOL JS_IsLiveObject(JSRuntime *rt, JSValueConst obj); + + JSContext *JS_NewContext(JSRuntime *rt); diff --git a/vendor/quickjs-patches/series/0011-feat-implement-gas-tracing-functionality-in-quickjs-.patch b/vendor/quickjs-patches/series/0011-feat-implement-gas-tracing-functionality-in-quickjs-.patch new file mode 100644 index 0000000..7b7dc05 --- /dev/null +++ b/vendor/quickjs-patches/series/0011-feat-implement-gas-tracing-functionality-in-quickjs-.patch @@ -0,0 +1,271 @@ +From b9eea5e39f3ab0497c9cbdfc715b35304b4c838f Mon Sep 17 00:00:00 2001 +From: Mateusz Jonak +Date: Thu, 11 Dec 2025 16:55:15 +0100 +Subject: [PATCH 11/51] feat: Implement gas tracing functionality in QuickJS + runtime + +This commit introduces a gas tracing system to the QuickJS runtime, allowing for detailed tracking of gas usage during execution. It adds a new structure, JSGasTraceData, to store gas usage metrics, and functions to enable, reset, and read gas trace data. The changes enhance resource management by providing insights into gas consumption for opcode execution, array callbacks, and memory allocations, improving control in deterministic environments. +--- + quickjs.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- + quickjs.h | 14 ++++++ + 2 files changed, 149 insertions(+), 3 deletions(-) + +diff --git a/quickjs.c b/quickjs.c +index 1c80298..6b052ab 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -234,6 +234,7 @@ typedef enum { + } JSGCPhaseEnum; + + typedef enum OPCodeEnum OPCodeEnum; ++typedef struct JSGasTraceData JSGasTraceData; + + struct JSRuntime { + JSMallocFunctions mf; +@@ -499,6 +500,7 @@ struct JSContext { + uint64_t gas_remaining; + uint32_t gas_version; + ++ JSGasTraceData *gas_trace; + BOOL deterministic_mode; + }; + +@@ -1113,6 +1115,77 @@ static inline uint16_t js_get_opcode_gas_cost(uint8_t opcode) + return 0; + } + ++struct JSGasTraceData { ++ BOOL enabled; ++ uint64_t opcode_count_total; ++ uint64_t opcode_gas; ++ uint64_t builtin_array_cb_base_count; ++ uint64_t builtin_array_cb_base_gas; ++ uint64_t builtin_array_cb_per_element_count; ++ uint64_t builtin_array_cb_per_element_gas; ++ uint64_t allocation_count; ++ uint64_t allocation_bytes; ++ uint64_t allocation_gas; ++}; ++ ++static void js_gas_trace_reset_counts(JSGasTraceData *trace) ++{ ++ BOOL enabled = trace->enabled; ++ memset(trace, 0, sizeof(*trace)); ++ trace->enabled = enabled; ++} ++ ++static JSGasTraceData *js_gas_trace_or_null(JSContext *ctx) ++{ ++ if (!ctx || !ctx->gas_trace || !ctx->gas_trace->enabled) ++ return NULL; ++ return ctx->gas_trace; ++} ++ ++static JSGasTraceData *js_gas_trace_ensure(JSContext *ctx) ++{ ++ if (!ctx->gas_trace) { ++ ctx->gas_trace = js_mallocz_rt(ctx->rt, sizeof(JSGasTraceData)); ++ } ++ return ctx->gas_trace; ++} ++ ++static void js_gas_trace_record_opcode(JSContext *ctx, uint8_t opcode, uint16_t gas_cost) ++{ ++ JSGasTraceData *trace = js_gas_trace_or_null(ctx); ++ if (!trace) ++ return; ++ ++ trace->opcode_count_total++; ++ trace->opcode_gas += gas_cost; ++} ++ ++static void js_gas_trace_record_array_cb(JSContext *ctx, uint16_t gas_cost, BOOL per_element) ++{ ++ JSGasTraceData *trace = js_gas_trace_or_null(ctx); ++ if (!trace) ++ return; ++ ++ if (per_element) { ++ trace->builtin_array_cb_per_element_count++; ++ trace->builtin_array_cb_per_element_gas += gas_cost; ++ } else { ++ trace->builtin_array_cb_base_count++; ++ trace->builtin_array_cb_base_gas += gas_cost; ++ } ++} ++ ++static void js_gas_trace_record_allocation(JSContext *ctx, size_t size, uint64_t gas_cost) ++{ ++ JSGasTraceData *trace = js_gas_trace_or_null(ctx); ++ if (!trace) ++ return; ++ ++ trace->allocation_count++; ++ trace->allocation_bytes += size; ++ trace->allocation_gas += gas_cost; ++} ++ + static int JS_InitAtoms(JSRuntime *rt); + static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len, + int atom_type); +@@ -1427,9 +1500,8 @@ static uint64_t js_gas_allocation_cost(size_t size) + static int js_charge_gas_allocation_ctx(JSContext *ctx, size_t size) + { + JSRuntime *rt = ctx->rt; ++ uint64_t gas_cost; + +- if (ctx->gas_limit == JS_GAS_UNLIMITED) +- return 0; + if (rt->in_out_of_gas || rt->current_exception_is_uncatchable) + return 0; + +@@ -1439,7 +1511,12 @@ static int js_charge_gas_allocation_ctx(JSContext *ctx, size_t size) + rt->det_gc_pending = TRUE; + } + +- return JS_UseGas(ctx, js_gas_allocation_cost(size)); ++ gas_cost = js_gas_allocation_cost(size); ++ if (JS_UseGas(ctx, gas_cost)) ++ return -1; ++ ++ js_gas_trace_record_allocation(ctx, size, gas_cost); ++ return 0; + } + + static size_t js_malloc_usable_size_unknown(const void *ptr) +@@ -2938,6 +3015,53 @@ uint32_t JS_GetGasVersion(JSContext *ctx) + return ctx->gas_version; + } + ++int JS_EnableGasTrace(JSContext *ctx, int enabled) ++{ ++ JSGasTraceData *trace; ++ ++ if (!ctx) ++ return -1; ++ ++ trace = js_gas_trace_ensure(ctx); ++ if (!trace) ++ return -1; ++ ++ memset(trace, 0, sizeof(*trace)); ++ trace->enabled = enabled ? TRUE : FALSE; ++ return 0; ++} ++ ++int JS_ResetGasTrace(JSContext *ctx) ++{ ++ JSGasTraceData *trace = js_gas_trace_or_null(ctx); ++ ++ if (!trace) ++ return -1; ++ ++ js_gas_trace_reset_counts(trace); ++ return 0; ++} ++ ++int JS_ReadGasTrace(JSContext *ctx, JSGasTrace *out_trace) ++{ ++ JSGasTraceData *trace = js_gas_trace_or_null(ctx); ++ ++ if (!trace || !out_trace) ++ return -1; ++ ++ out_trace->opcode_count = trace->opcode_count_total; ++ out_trace->opcode_gas = trace->opcode_gas; ++ out_trace->builtin_array_cb_base_count = trace->builtin_array_cb_base_count; ++ out_trace->builtin_array_cb_base_gas = trace->builtin_array_cb_base_gas; ++ out_trace->builtin_array_cb_per_element_count = trace->builtin_array_cb_per_element_count; ++ out_trace->builtin_array_cb_per_element_gas = trace->builtin_array_cb_per_element_gas; ++ out_trace->allocation_count = trace->allocation_count; ++ out_trace->allocation_bytes = trace->allocation_bytes; ++ out_trace->allocation_gas = trace->allocation_gas; ++ ++ return 0; ++} ++ + int JS_UseGas(JSContext *ctx, uint64_t amount) + { + if (ctx->gas_limit == JS_GAS_UNLIMITED) +@@ -3140,6 +3264,8 @@ void JS_FreeContext(JSContext *ctx) + + list_del(&ctx->link); + remove_gc_object(&ctx->header); ++ if (ctx->gas_trace) ++ js_free_rt(ctx->rt, ctx->gas_trace); + js_free_rt(ctx->rt, ctx); + } + +@@ -18222,6 +18348,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, + uint16_t gas_cost = js_get_opcode_gas_cost(opcode); + if (unlikely(JS_UseGas(ctx, gas_cost) != 0)) + goto exception; ++ js_gas_trace_record_opcode(ctx, opcode, gas_cost); + + #if !DIRECT_DISPATCH + DISPATCH() { +@@ -42254,6 +42381,7 @@ static JSValue js_array_every(JSContext *ctx, JSValueConst this_val, + val = JS_UNDEFINED; + if (unlikely(JS_UseGas(ctx, JS_GAS_ARRAY_CB_BASE) != 0)) + goto exception; ++ js_gas_trace_record_array_cb(ctx, JS_GAS_ARRAY_CB_BASE, FALSE); + if (special & special_TA) { + obj = JS_DupValue(ctx, this_val); + len = js_typed_array_get_length_unsafe(ctx, obj); +@@ -42310,6 +42438,7 @@ static JSValue js_array_every(JSContext *ctx, JSValueConst this_val, + for(k = 0; k < len; k++) { + if (unlikely(JS_UseGas(ctx, JS_GAS_ARRAY_CB_PER_ELEMENT) != 0)) + goto exception; ++ js_gas_trace_record_array_cb(ctx, JS_GAS_ARRAY_CB_PER_ELEMENT, TRUE); + if (special & special_TA) { + val = JS_GetPropertyInt64(ctx, obj, k); + if (JS_IsException(val)) +@@ -42416,6 +42545,7 @@ static JSValue js_array_reduce(JSContext *ctx, JSValueConst this_val, + val = JS_UNDEFINED; + if (unlikely(JS_UseGas(ctx, JS_GAS_ARRAY_CB_BASE) != 0)) + goto exception; ++ js_gas_trace_record_array_cb(ctx, JS_GAS_ARRAY_CB_BASE, FALSE); + if (special & special_TA) { + obj = JS_DupValue(ctx, this_val); + len = js_typed_array_get_length_unsafe(ctx, obj); +@@ -42438,6 +42568,7 @@ static JSValue js_array_reduce(JSContext *ctx, JSValueConst this_val, + for(;;) { + if (unlikely(JS_UseGas(ctx, JS_GAS_ARRAY_CB_PER_ELEMENT) != 0)) + goto exception; ++ js_gas_trace_record_array_cb(ctx, JS_GAS_ARRAY_CB_PER_ELEMENT, TRUE); + if (k >= len) { + JS_ThrowTypeError(ctx, "empty array"); + goto exception; +@@ -42462,6 +42593,7 @@ static JSValue js_array_reduce(JSContext *ctx, JSValueConst this_val, + k1 = (special & special_reduceRight) ? len - k - 1 : k; + if (unlikely(JS_UseGas(ctx, JS_GAS_ARRAY_CB_PER_ELEMENT) != 0)) + goto exception; ++ js_gas_trace_record_array_cb(ctx, JS_GAS_ARRAY_CB_PER_ELEMENT, TRUE); + if (special & special_TA) { + val = JS_GetPropertyInt64(ctx, obj, k1); + if (JS_IsException(val)) +diff --git a/quickjs.h b/quickjs.h +index a027514..6d362b5 100644 +--- a/quickjs.h ++++ b/quickjs.h +@@ -396,6 +396,20 @@ void JS_SetGasLimit(JSContext *ctx, uint64_t gas_limit); + uint64_t JS_GetGasRemaining(JSContext *ctx); + uint64_t JS_GetGasLimit(JSContext *ctx); + uint32_t JS_GetGasVersion(JSContext *ctx); ++typedef struct JSGasTrace { ++ uint64_t opcode_count; ++ uint64_t opcode_gas; ++ uint64_t builtin_array_cb_base_count; ++ uint64_t builtin_array_cb_base_gas; ++ uint64_t builtin_array_cb_per_element_count; ++ uint64_t builtin_array_cb_per_element_gas; ++ uint64_t allocation_count; ++ uint64_t allocation_bytes; ++ uint64_t allocation_gas; ++} JSGasTrace; ++int JS_EnableGasTrace(JSContext *ctx, int enabled); ++int JS_ResetGasTrace(JSContext *ctx); ++int JS_ReadGasTrace(JSContext *ctx, JSGasTrace *out_trace); + int JS_UseGas(JSContext *ctx, uint64_t amount); + JSRuntime *JS_GetRuntime(JSContext *ctx); + void JS_SetClassProto(JSContext *ctx, JSClassID class_id, JSValue obj); diff --git a/vendor/quickjs-patches/series/0012-fix-reset-gas-trace-counts-using-dedicated-function.patch b/vendor/quickjs-patches/series/0012-fix-reset-gas-trace-counts-using-dedicated-function.patch new file mode 100644 index 0000000..c774f16 --- /dev/null +++ b/vendor/quickjs-patches/series/0012-fix-reset-gas-trace-counts-using-dedicated-function.patch @@ -0,0 +1,23 @@ +From 7c9b3bcec82dc223de7096b2206965f4205f1e0d Mon Sep 17 00:00:00 2001 +From: Mateusz Jonak +Date: Fri, 12 Dec 2025 15:53:28 +0100 +Subject: [PATCH 12/51] fix: Reset gas trace counts using dedicated function + +This commit updates the gas tracing functionality in the QuickJS runtime by replacing the direct memory reset with a call to the new function js_gas_trace_reset_counts. This change improves code clarity and ensures that gas trace counts are reset correctly, enhancing the overall reliability of the gas tracing system. +--- + quickjs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/quickjs.c b/quickjs.c +index 6b052ab..ac14932 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -3026,7 +3026,7 @@ int JS_EnableGasTrace(JSContext *ctx, int enabled) + if (!trace) + return -1; + +- memset(trace, 0, sizeof(*trace)); ++ js_gas_trace_reset_counts(trace); + trace->enabled = enabled ? TRUE : FALSE; + return 0; + } diff --git a/vendor/quickjs-patches/series/0013-feat-quickjs-add-dv-canonical-cbor-encode-decode.patch b/vendor/quickjs-patches/series/0013-feat-quickjs-add-dv-canonical-cbor-encode-decode.patch new file mode 100644 index 0000000..5810f78 --- /dev/null +++ b/vendor/quickjs-patches/series/0013-feat-quickjs-add-dv-canonical-cbor-encode-decode.patch @@ -0,0 +1,1144 @@ +From 7bf66276ded3cf31d15515104dbc6f8578d94e52 Mon Sep 17 00:00:00 2001 +From: Mateusz Jonak +Date: Mon, 15 Dec 2025 18:16:50 +0100 +Subject: [PATCH 13/51] feat(quickjs): add DV (canonical CBOR) encode/decode + +Add a Deterministic Values (DV) codec to the QuickJS fork. + +- Add quickjs-dv.c implementing JS_EncodeDV / JS_DecodeDV for a restricted CBOR subset + (null/bool/finite numbers, UTF-8 text, arrays, plain objects as maps). +- Enforce canonical encoding: shortest-length integers, float64-only (no non-finite), + no indefinite lengths, canonical map key ordering, and duplicate key rejection. +- Add public API types JSDvLimits/JSDvBuffer, defaults (JS_DV_LIMIT_DEFAULTS), + and JS_FreeDVBuffer for output ownership cleanup. +- Validate UTF-8 and normalize -0 to 0 for deterministic round-trips. +--- + quickjs-dv.c | 1087 ++++++++++++++++++++++++++++++++++++++++++++++++++ + quickjs.h | 20 + + 2 files changed, 1107 insertions(+) + create mode 100644 quickjs-dv.c + +diff --git a/quickjs-dv.c b/quickjs-dv.c +new file mode 100644 +index 0000000..e82dad5 +--- /dev/null ++++ b/quickjs-dv.c +@@ -0,0 +1,1087 @@ ++#include "quickjs.h" ++#include ++#include ++#include ++#include ++#include ++ ++#ifndef JS_CLASS_OBJECT ++/* Upstream class id for Object; used here to fetch the intrinsic prototype ++ without relying on the global Object binding. */ ++#define JS_CLASS_OBJECT 1 ++#endif ++ ++/* Internal allocator hooks from quickjs.c */ ++extern void *js_malloc(JSContext *ctx, size_t size); ++extern void *js_realloc(JSContext *ctx, void *ptr, size_t size); ++extern void js_free(JSContext *ctx, void *ptr); ++ ++#define DV_CBOR_MAJOR_UINT 0 ++#define DV_CBOR_MAJOR_NINT 1 ++#define DV_CBOR_MAJOR_TEXT 3 ++#define DV_CBOR_MAJOR_ARRAY 4 ++#define DV_CBOR_MAJOR_MAP 5 ++#define DV_CBOR_MAJOR_SIMPLE 7 ++ ++static const int64_t dv_max_safe_int = 9007199254740991LL; /* 2^53 - 1 */ ++static const int64_t dv_min_safe_int = -9007199254740991LL; /* -(2^53 - 1) */ ++ ++static const JSDvLimits *dv_limits_or_default(const JSDvLimits *limits) { ++ return limits ? limits : &JS_DV_LIMIT_DEFAULTS; ++} ++ ++typedef struct { ++ JSContext *ctx; ++ uint8_t *data; ++ size_t size; ++ size_t capacity; ++ size_t max_size; ++} JSDvBuilder; ++ ++typedef struct { ++ const uint8_t *data; ++ size_t size; ++ size_t pos; ++ JSContext *ctx; ++} JSDvReader; ++ ++typedef struct { ++ JSAtom atom; ++ JSValue key_value; ++ uint8_t *encoded_key; ++ size_t encoded_key_len; ++} JSDvKeyEntry; ++ ++static int dv_throw(JSContext *ctx, const char *fmt, ...) { ++ va_list ap; ++ va_start(ap, fmt); ++ char buf[256]; ++ vsnprintf(buf, sizeof(buf), fmt, ap); ++ va_end(ap); ++ JS_ThrowTypeError(ctx, "%s", buf); ++ return -1; ++} ++ ++static int dv_builder_reserve(JSDvBuilder *builder, size_t additional) { ++ if (additional > builder->max_size - builder->size) { ++ JS_ThrowTypeError( ++ builder->ctx, ++ "DV encode: encoded DV exceeds maxEncodedBytes (%zu > %zu)", ++ builder->size + additional, ++ builder->max_size); ++ return -1; ++ } ++ ++ size_t required = builder->size + additional; ++ if (required <= builder->capacity) { ++ return 0; ++ } ++ ++ size_t new_capacity = builder->capacity ? builder->capacity : 64; ++ while (new_capacity < required) { ++ size_t next = new_capacity * 2; ++ if (next <= new_capacity) { ++ new_capacity = builder->max_size; ++ break; ++ } ++ new_capacity = next; ++ } ++ ++ if (new_capacity > builder->max_size) { ++ new_capacity = builder->max_size; ++ } ++ ++ uint8_t *reallocated = js_realloc(builder->ctx, builder->data, new_capacity); ++ if (!reallocated) { ++ return -1; ++ } ++ ++ builder->data = reallocated; ++ builder->capacity = new_capacity; ++ return 0; ++} ++ ++static void dv_builder_free(JSDvBuilder *builder) { ++ if (builder->data) { ++ js_free(builder->ctx, builder->data); ++ builder->data = NULL; ++ } ++ builder->size = 0; ++ builder->capacity = 0; ++} ++ ++static int dv_builder_push_u8(JSDvBuilder *builder, uint8_t value) { ++ if (dv_builder_reserve(builder, 1) != 0) { ++ return -1; ++ } ++ builder->data[builder->size++] = value; ++ return 0; ++} ++ ++static int dv_builder_push_bytes(JSDvBuilder *builder, const uint8_t *data, size_t length) { ++ if (length == 0) { ++ return 0; ++ } ++ if (dv_builder_reserve(builder, length) != 0) { ++ return -1; ++ } ++ memcpy(builder->data + builder->size, data, length); ++ builder->size += length; ++ return 0; ++} ++ ++static int dv_builder_push_u64_be(JSDvBuilder *builder, uint64_t value, size_t width) { ++ uint8_t buf[8]; ++ for (size_t i = 0; i < width; i++) { ++ buf[width - 1 - i] = (uint8_t)(value & 0xff); ++ value >>= 8; ++ } ++ return dv_builder_push_bytes(builder, buf, width); ++} ++ ++static int dv_validate_utf8(JSContext *ctx, const uint8_t *data, size_t length) { ++ size_t i = 0; ++ while (i < length) { ++ uint8_t byte = data[i]; ++ uint32_t codepoint; ++ size_t needed; ++ ++ if (byte < 0x80) { ++ codepoint = byte; ++ needed = 0; ++ } else if ((byte & 0xe0) == 0xc0) { ++ codepoint = byte & 0x1f; ++ needed = 1; ++ if (codepoint == 0) { ++ return dv_throw(ctx, "DV string contains invalid UTF-8"); ++ } ++ } else if ((byte & 0xf0) == 0xe0) { ++ codepoint = byte & 0x0f; ++ needed = 2; ++ } else if ((byte & 0xf8) == 0xf0) { ++ codepoint = byte & 0x07; ++ needed = 3; ++ } else { ++ return dv_throw(ctx, "DV string contains invalid UTF-8"); ++ } ++ ++ if (i + needed >= length) { ++ return dv_throw(ctx, "DV string contains invalid UTF-8"); ++ } ++ ++ for (size_t j = 0; j < needed; j++) { ++ uint8_t cont = data[i + 1 + j]; ++ if ((cont & 0xc0) != 0x80) { ++ return dv_throw(ctx, "DV string contains invalid UTF-8"); ++ } ++ codepoint = (codepoint << 6) | (cont & 0x3f); ++ } ++ ++ if ((needed == 1 && codepoint < 0x80) || ++ (needed == 2 && codepoint < 0x800) || ++ (needed == 3 && codepoint < 0x10000)) { ++ return dv_throw(ctx, "DV string contains invalid UTF-8"); ++ } ++ ++ if (codepoint > 0x10ffff) { ++ return dv_throw(ctx, "DV string contains invalid UTF-8"); ++ } ++ if (codepoint >= 0xd800 && codepoint <= 0xdfff) { ++ return dv_throw(ctx, "DV string contains lone surrogate code points"); ++ } ++ ++ i += needed + 1; ++ } ++ return 0; ++} ++ ++static int dv_encode_type_and_length(JSDvBuilder *builder, uint8_t major, uint64_t length) { ++ if (length <= 23) { ++ return dv_builder_push_u8(builder, (uint8_t)((major << 5) | length)); ++ } ++ if (length <= 0xff) { ++ if (dv_builder_push_u8(builder, (uint8_t)((major << 5) | 24)) != 0) { ++ return -1; ++ } ++ return dv_builder_push_u64_be(builder, length, 1); ++ } ++ if (length <= 0xffff) { ++ if (dv_builder_push_u8(builder, (uint8_t)((major << 5) | 25)) != 0) { ++ return -1; ++ } ++ return dv_builder_push_u64_be(builder, length, 2); ++ } ++ if (length <= 0xffffffff) { ++ if (dv_builder_push_u8(builder, (uint8_t)((major << 5) | 26)) != 0) { ++ return -1; ++ } ++ return dv_builder_push_u64_be(builder, length, 4); ++ } ++ if (dv_builder_push_u8(builder, (uint8_t)((major << 5) | 27)) != 0) { ++ return -1; ++ } ++ return dv_builder_push_u64_be(builder, length, 8); ++} ++ ++static int dv_encode_number(JSContext *ctx, double value, JSDvBuilder *builder) { ++ if (!isfinite(value)) { ++ return dv_throw(ctx, "DV numbers must be finite"); ++ } ++ ++ if (value == 0 && signbit(value)) { ++ value = 0; ++ } ++ ++ double int_part; ++ if (modf(value, &int_part) == 0.0) { ++ if (value > (double)dv_max_safe_int || value < (double)dv_min_safe_int) { ++ return dv_throw(ctx, ++ "integer is outside safe range (not in [%" PRId64 ", %" PRId64 "])", ++ dv_min_safe_int, ++ dv_max_safe_int); ++ } ++ ++ uint64_t unsigned_val; ++ if (value >= 0) { ++ unsigned_val = (uint64_t)value; ++ return dv_encode_type_and_length(builder, DV_CBOR_MAJOR_UINT, unsigned_val); ++ } ++ ++ unsigned_val = (uint64_t)(-1 - (int64_t)value); ++ return dv_encode_type_and_length(builder, DV_CBOR_MAJOR_NINT, unsigned_val); ++ } ++ ++ if (dv_builder_push_u8(builder, 0xfb) != 0) { ++ return -1; ++ } ++ union { ++ double d; ++ uint64_t u; ++ } u; ++ u.d = value; ++ return dv_builder_push_u64_be(builder, u.u, 8); ++} ++ ++static int dv_encode_string_bytes(JSContext *ctx, ++ JSValueConst value, ++ const JSDvLimits *limits, ++ uint8_t **out_bytes, ++ size_t *out_len) { ++ size_t byte_length = 0; ++ const char *raw = JS_ToCStringLen2(ctx, &byte_length, value, 0); ++ if (!raw) { ++ return -1; ++ } ++ ++ if (byte_length > limits->max_string_bytes) { ++ JS_FreeCString(ctx, raw); ++ return dv_throw(ctx, ++ "string exceeds maxStringBytes (%zu > %u)", ++ byte_length, ++ limits->max_string_bytes); ++ } ++ ++ if (dv_validate_utf8(ctx, (const uint8_t *)raw, byte_length) != 0) { ++ JS_FreeCString(ctx, raw); ++ return -1; ++ } ++ ++ uint8_t *copy = NULL; ++ if (byte_length > 0) { ++ copy = js_malloc(ctx, byte_length); ++ if (!copy) { ++ JS_FreeCString(ctx, raw); ++ return -1; ++ } ++ memcpy(copy, raw, byte_length); ++ } ++ JS_FreeCString(ctx, raw); ++ *out_bytes = copy; ++ *out_len = byte_length; ++ return 0; ++} ++ ++static int dv_encode_value(JSContext *ctx, ++ JSValueConst value, ++ const JSDvLimits *limits, ++ uint32_t depth, ++ JSDvBuilder *builder); ++ ++static int dv_encode_array(JSContext *ctx, ++ JSValueConst value, ++ const JSDvLimits *limits, ++ uint32_t depth, ++ JSDvBuilder *builder) { ++ uint32_t next_depth = depth + 1; ++ if (next_depth > limits->max_depth) { ++ return dv_throw(ctx, "maxDepth %u exceeded", limits->max_depth); ++ } ++ ++ uint64_t length64 = 0; ++ JSValue length_val = JS_GetPropertyStr(ctx, value, "length"); ++ if (JS_IsException(length_val)) { ++ return -1; ++ } ++ int len_rc = JS_ToIndex(ctx, &length64, length_val); ++ JS_FreeValue(ctx, length_val); ++ if (len_rc < 0) { ++ return -1; ++ } ++ ++ if (length64 > limits->max_array_length) { ++ return dv_throw(ctx, ++ "array length exceeds maxArrayLength (%" PRIu64 " > %u)", ++ length64, ++ limits->max_array_length); ++ } ++ ++ uint32_t length = (uint32_t)length64; ++ if (dv_encode_type_and_length(builder, DV_CBOR_MAJOR_ARRAY, length) != 0) { ++ return -1; ++ } ++ ++ for (uint32_t i = 0; i < length; i++) { ++ JSValue element = JS_GetPropertyUint32(ctx, value, i); ++ if (JS_IsException(element)) { ++ return -1; ++ } ++ int rc = dv_encode_value(ctx, element, limits, next_depth, builder); ++ JS_FreeValue(ctx, element); ++ if (rc != 0) { ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++static int dv_compare_encoded_keys(const void *a, const void *b) { ++ const JSDvKeyEntry *ka = (const JSDvKeyEntry *)a; ++ const JSDvKeyEntry *kb = (const JSDvKeyEntry *)b; ++ ++ if (ka->encoded_key_len != kb->encoded_key_len) { ++ return ka->encoded_key_len < kb->encoded_key_len ? -1 : 1; ++ } ++ return memcmp(ka->encoded_key, kb->encoded_key, ka->encoded_key_len); ++} ++ ++static int dv_encode_object(JSContext *ctx, ++ JSValueConst value, ++ const JSDvLimits *limits, ++ uint32_t depth, ++ JSDvBuilder *builder) { ++ uint32_t next_depth = depth + 1; ++ if (next_depth > limits->max_depth) { ++ return dv_throw(ctx, "maxDepth %u exceeded", limits->max_depth); ++ } ++ ++ JSValue proto = JS_GetPrototype(ctx, value); ++ if (JS_IsException(proto)) { ++ return -1; ++ } ++ ++ int is_plain = 0; ++ if (JS_IsNull(proto)) { ++ is_plain = 1; ++ } else { ++ JSValue object_proto = JS_GetClassProto(ctx, JS_CLASS_OBJECT); ++ if (JS_IsException(object_proto)) { ++ JS_FreeValue(ctx, proto); ++ return -1; ++ } ++ ++ int same = JS_SameValue(ctx, proto, object_proto); ++ JS_FreeValue(ctx, object_proto); ++ if (same < 0) { ++ JS_FreeValue(ctx, proto); ++ return -1; ++ } ++ ++ is_plain = same; ++ } ++ ++ JS_FreeValue(ctx, proto); ++ ++ if (!is_plain) { ++ return dv_throw(ctx, "unsupported DV type: object"); ++ } ++ ++ JSPropertyEnum *props = NULL; ++ uint32_t prop_len = 0; ++ if (JS_GetOwnPropertyNames(ctx, ++ &props, ++ &prop_len, ++ value, ++ JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY) < 0) { ++ return -1; ++ } ++ ++ if (prop_len > limits->max_map_length) { ++ JS_FreePropertyEnum(ctx, props, prop_len); ++ return dv_throw(ctx, ++ "map entries exceed maxMapLength (%u > %u)", ++ prop_len, ++ limits->max_map_length); ++ } ++ ++ JSDvKeyEntry *entries = NULL; ++ if (prop_len > 0) { ++ entries = js_malloc(ctx, prop_len * sizeof(*entries)); ++ if (!entries) { ++ JS_FreePropertyEnum(ctx, props, prop_len); ++ return -1; ++ } ++ } ++ ++ for (uint32_t i = 0; i < prop_len; i++) { ++ entries[i].atom = props[i].atom; ++ entries[i].encoded_key = NULL; ++ entries[i].encoded_key_len = 0; ++ entries[i].key_value = JS_UNDEFINED; ++ ++ JSValue key_val = JS_AtomToString(ctx, props[i].atom); ++ if (JS_IsException(key_val)) { ++ goto encode_object_error; ++ } ++ ++ uint8_t *key_bytes = NULL; ++ size_t key_len = 0; ++ if (dv_encode_string_bytes(ctx, key_val, limits, &key_bytes, &key_len) != 0) { ++ JS_FreeValue(ctx, key_val); ++ goto encode_object_error; ++ } ++ ++ JSDvBuilder key_builder = { ++ .ctx = ctx, ++ .data = NULL, ++ .size = 0, ++ .capacity = 0, ++ .max_size = limits->max_encoded_bytes, ++ }; ++ ++ if (dv_encode_type_and_length(&key_builder, DV_CBOR_MAJOR_TEXT, key_len) != 0 || ++ dv_builder_push_bytes(&key_builder, key_bytes, key_len) != 0) { ++ dv_builder_free(&key_builder); ++ js_free(ctx, key_bytes); ++ JS_FreeValue(ctx, key_val); ++ goto encode_object_error; ++ } ++ ++ if (key_bytes) { ++ js_free(ctx, key_bytes); ++ } ++ ++ entries[i].encoded_key = key_builder.data; ++ entries[i].encoded_key_len = key_builder.size; ++ entries[i].key_value = key_val; ++ } ++ ++ qsort(entries, prop_len, sizeof(entries[0]), dv_compare_encoded_keys); ++ ++ for (uint32_t i = 1; i < prop_len; i++) { ++ int cmp = dv_compare_encoded_keys(&entries[i - 1], &entries[i]); ++ if (cmp == 0) { ++ JSValue str_val = JS_JSONStringify(ctx, ++ entries[i].key_value, ++ JS_UNDEFINED, ++ JS_UNDEFINED); ++ if (!JS_IsException(str_val)) { ++ const char *dup = JS_ToCString(ctx, str_val); ++ const char *dup_key = dup ? dup : ""; ++ dv_throw(ctx, "map contains duplicate key %s", dup_key); ++ if (dup) { ++ JS_FreeCString(ctx, dup); ++ } ++ JS_FreeValue(ctx, str_val); ++ } else { ++ dv_throw(ctx, "map contains duplicate key"); ++ } ++ goto encode_object_error; ++ } ++ } ++ ++ if (dv_encode_type_and_length(builder, DV_CBOR_MAJOR_MAP, prop_len) != 0) { ++ goto encode_object_error; ++ } ++ ++ for (uint32_t i = 0; i < prop_len; i++) { ++ if (dv_builder_push_bytes(builder, entries[i].encoded_key, entries[i].encoded_key_len) != 0) { ++ goto encode_object_error; ++ } ++ JSValue prop_val = JS_GetProperty(ctx, value, entries[i].atom); ++ if (JS_IsException(prop_val)) { ++ goto encode_object_error; ++ } ++ int rc = dv_encode_value(ctx, prop_val, limits, next_depth, builder); ++ JS_FreeValue(ctx, prop_val); ++ if (rc != 0) { ++ goto encode_object_error; ++ } ++ } ++ ++ for (uint32_t i = 0; i < prop_len; i++) { ++ if (entries[i].encoded_key) { ++ js_free(ctx, entries[i].encoded_key); ++ } ++ JS_FreeValue(ctx, entries[i].key_value); ++ } ++ if (entries) { ++ js_free(ctx, entries); ++ } ++ if (props) { ++ JS_FreePropertyEnum(ctx, props, prop_len); ++ } ++ return 0; ++ ++encode_object_error: ++ if (entries) { ++ for (uint32_t i = 0; i < prop_len; i++) { ++ if (entries[i].encoded_key) { ++ js_free(ctx, entries[i].encoded_key); ++ } ++ if (!JS_IsUndefined(entries[i].key_value)) { ++ JS_FreeValue(ctx, entries[i].key_value); ++ } ++ } ++ js_free(ctx, entries); ++ } ++ if (props) { ++ JS_FreePropertyEnum(ctx, props, prop_len); ++ } ++ return -1; ++} ++ ++static int dv_encode_value(JSContext *ctx, ++ JSValueConst value, ++ const JSDvLimits *limits, ++ uint32_t depth, ++ JSDvBuilder *builder) { ++ if (depth > limits->max_depth) { ++ return dv_throw(ctx, "maxDepth %u exceeded", limits->max_depth); ++ } ++ ++ int tag = JS_VALUE_GET_NORM_TAG(value); ++ switch (tag) { ++ case JS_TAG_NULL: ++ return dv_builder_push_u8(builder, 0xf6); ++ case JS_TAG_BOOL: { ++ return dv_builder_push_u8(builder, JS_VALUE_GET_BOOL(value) ? 0xf5 : 0xf4); ++ } ++ case JS_TAG_INT: ++ return dv_encode_number(ctx, JS_VALUE_GET_INT(value), builder); ++ case JS_TAG_FLOAT64: ++ return dv_encode_number(ctx, JS_VALUE_GET_FLOAT64(value), builder); ++ case JS_TAG_STRING: ++ case JS_TAG_STRING_ROPE: { ++ uint8_t *bytes = NULL; ++ size_t len = 0; ++ if (dv_encode_string_bytes(ctx, value, limits, &bytes, &len) != 0) { ++ return -1; ++ } ++ int rc = dv_encode_type_and_length(builder, DV_CBOR_MAJOR_TEXT, len); ++ if (rc == 0) { ++ rc = dv_builder_push_bytes(builder, bytes, len); ++ } ++ if (bytes) { ++ js_free(ctx, bytes); ++ } ++ return rc; ++ } ++ case JS_TAG_OBJECT: { ++ int is_array = JS_IsArray(ctx, value); ++ if (is_array < 0) { ++ return -1; ++ } ++ if (is_array) { ++ return dv_encode_array(ctx, value, limits, depth, builder); ++ } ++ return dv_encode_object(ctx, value, limits, depth, builder); ++ } ++ default: ++ return dv_throw(ctx, "unsupported DV type: %d", tag); ++ } ++} ++ ++int JS_EncodeDV(JSContext *ctx, ++ JSValueConst value, ++ const JSDvLimits *maybe_limits, ++ JSDvBuffer *out_buffer) { ++ const JSDvLimits *limits = dv_limits_or_default(maybe_limits); ++ if (out_buffer) { ++ out_buffer->data = NULL; ++ out_buffer->length = 0; ++ } ++ ++ JSDvBuilder builder = { ++ .ctx = ctx, ++ .data = NULL, ++ .size = 0, ++ .capacity = 0, ++ .max_size = limits->max_encoded_bytes, ++ }; ++ ++ if (dv_encode_value(ctx, value, limits, 0, &builder) != 0) { ++ dv_builder_free(&builder); ++ return -1; ++ } ++ ++ if (out_buffer) { ++ out_buffer->data = builder.data; ++ out_buffer->length = builder.size; ++ } else { ++ dv_builder_free(&builder); ++ } ++ return 0; ++} ++ ++static int dv_reader_need(JSDvReader *reader, size_t amount) { ++ if (reader->pos + amount > reader->size) { ++ JS_ThrowTypeError(reader->ctx, "unexpected end of buffer"); ++ return -1; ++ } ++ return 0; ++} ++ ++static int dv_reader_read_u8(JSDvReader *reader, uint8_t *out) { ++ if (dv_reader_need(reader, 1) != 0) { ++ return -1; ++ } ++ *out = reader->data[reader->pos++]; ++ return 0; ++} ++ ++static int dv_reader_read_be(JSDvReader *reader, size_t width, uint64_t *out) { ++ if (dv_reader_need(reader, width) != 0) { ++ return -1; ++ } ++ uint64_t value = 0; ++ for (size_t i = 0; i < width; i++) { ++ value = (value << 8) | reader->data[reader->pos + i]; ++ } ++ reader->pos += width; ++ *out = value; ++ return 0; ++} ++ ++static int dv_read_length(JSDvReader *reader, uint8_t additional, uint64_t *out) { ++ if (additional <= 23) { ++ *out = additional; ++ return 0; ++ } ++ ++ uint64_t value = 0; ++ switch (additional) { ++ case 24: ++ if (dv_reader_read_be(reader, 1, &value) != 0) { ++ return -1; ++ } ++ if (value < 24) { ++ return dv_throw(reader->ctx, "length not using shortest encoding"); ++ } ++ break; ++ case 25: ++ if (dv_reader_read_be(reader, 2, &value) != 0) { ++ return -1; ++ } ++ if (value <= 0xff) { ++ return dv_throw(reader->ctx, "length not using shortest encoding"); ++ } ++ break; ++ case 26: ++ if (dv_reader_read_be(reader, 4, &value) != 0) { ++ return -1; ++ } ++ if (value <= 0xffff) { ++ return dv_throw(reader->ctx, "length not using shortest encoding"); ++ } ++ break; ++ case 27: ++ if (dv_reader_read_be(reader, 8, &value) != 0) { ++ return -1; ++ } ++ if (value <= 0xffffffff) { ++ return dv_throw(reader->ctx, "length not using shortest encoding"); ++ } ++ break; ++ case 31: ++ return dv_throw(reader->ctx, "indefinite lengths are not allowed"); ++ default: ++ return dv_throw(reader->ctx, "unsupported additional info %u", additional); ++ } ++ ++ *out = value; ++ return 0; ++} ++ ++static JSValue dv_decode_value(JSContext *ctx, ++ JSDvReader *reader, ++ const JSDvLimits *limits, ++ uint32_t depth); ++ ++static JSValue dv_decode_text(JSContext *ctx, ++ JSDvReader *reader, ++ const JSDvLimits *limits, ++ uint8_t additional) { ++ uint64_t length64 = 0; ++ if (dv_read_length(reader, additional, &length64) != 0) { ++ return JS_EXCEPTION; ++ } ++ ++ if (length64 > limits->max_string_bytes) { ++ JS_ThrowTypeError(ctx, ++ "string exceeds maxStringBytes (%" PRIu64 " > %u)", ++ length64, ++ limits->max_string_bytes); ++ return JS_EXCEPTION; ++ } ++ ++ size_t length = (size_t)length64; ++ if (dv_reader_need(reader, length) != 0) { ++ return JS_EXCEPTION; ++ } ++ ++ const uint8_t *bytes = reader->data + reader->pos; ++ if (dv_validate_utf8(ctx, bytes, length) != 0) { ++ return JS_EXCEPTION; ++ } ++ ++ JSValue str = JS_NewStringLen(ctx, (const char *)bytes, length); ++ reader->pos += length; ++ return str; ++} ++ ++static JSValue dv_decode_array(JSContext *ctx, ++ JSDvReader *reader, ++ const JSDvLimits *limits, ++ uint32_t depth, ++ uint8_t additional) { ++ uint64_t length64 = 0; ++ if (dv_read_length(reader, additional, &length64) != 0) { ++ return JS_EXCEPTION; ++ } ++ ++ if (length64 > limits->max_array_length) { ++ JS_ThrowTypeError(ctx, ++ "array length exceeds maxArrayLength (%" PRIu64 " > %u)", ++ length64, ++ limits->max_array_length); ++ return JS_EXCEPTION; ++ } ++ ++ if (depth + 1 > limits->max_depth) { ++ JS_ThrowTypeError(ctx, "maxDepth %u exceeded", limits->max_depth); ++ return JS_EXCEPTION; ++ } ++ ++ uint32_t length = (uint32_t)length64; ++ JSValue arr = JS_NewArray(ctx); ++ if (JS_IsException(arr)) { ++ return JS_EXCEPTION; ++ } ++ ++ for (uint32_t i = 0; i < length; i++) { ++ JSValue element = dv_decode_value(ctx, reader, limits, depth + 1); ++ if (JS_IsException(element)) { ++ JS_FreeValue(ctx, arr); ++ return JS_EXCEPTION; ++ } ++ if (JS_SetPropertyUint32(ctx, arr, i, element) < 0) { ++ JS_FreeValue(ctx, arr); ++ return JS_EXCEPTION; ++ } ++ } ++ ++ return arr; ++} ++ ++static JSValue dv_decode_map(JSContext *ctx, ++ JSDvReader *reader, ++ const JSDvLimits *limits, ++ uint32_t depth, ++ uint8_t additional) { ++ uint64_t length64 = 0; ++ if (dv_read_length(reader, additional, &length64) != 0) { ++ return JS_EXCEPTION; ++ } ++ ++ if (length64 > limits->max_map_length) { ++ JS_ThrowTypeError(ctx, ++ "map entries exceed maxMapLength (%" PRIu64 " > %u)", ++ length64, ++ limits->max_map_length); ++ return JS_EXCEPTION; ++ } ++ ++ if (depth + 1 > limits->max_depth) { ++ JS_ThrowTypeError(ctx, "maxDepth %u exceeded", limits->max_depth); ++ return JS_EXCEPTION; ++ } ++ ++ uint32_t length = (uint32_t)length64; ++ JSValue obj = JS_NewObjectProto(ctx, JS_NULL); ++ if (JS_IsException(obj)) { ++ return JS_EXCEPTION; ++ } ++ ++ uint8_t *prev_key = NULL; ++ size_t prev_key_len = 0; ++ ++ for (uint32_t i = 0; i < length; i++) { ++ size_t key_start = reader->pos; ++ uint8_t key_initial; ++ if (dv_reader_read_u8(reader, &key_initial) != 0) { ++ JS_FreeValue(ctx, obj); ++ js_free(ctx, prev_key); ++ return JS_EXCEPTION; ++ } ++ ++ uint8_t key_major = key_initial >> 5; ++ if (key_major != DV_CBOR_MAJOR_TEXT) { ++ JS_FreeValue(ctx, obj); ++ js_free(ctx, prev_key); ++ JS_ThrowTypeError(ctx, "map keys must be text strings"); ++ return JS_EXCEPTION; ++ } ++ ++ JSValue key_val = dv_decode_text(ctx, reader, limits, key_initial & 0x1f); ++ if (JS_IsException(key_val)) { ++ JS_FreeValue(ctx, obj); ++ js_free(ctx, prev_key); ++ return JS_EXCEPTION; ++ } ++ ++ size_t key_end = reader->pos; ++ size_t key_len = key_end - key_start; ++ const uint8_t *key_bytes = reader->data + key_start; ++ ++ if (prev_key) { ++ int cmp = dv_compare_encoded_keys(&(JSDvKeyEntry){.encoded_key = prev_key, .encoded_key_len = prev_key_len}, ++ &(JSDvKeyEntry){.encoded_key = (uint8_t *)key_bytes, .encoded_key_len = key_len}); ++ if (cmp == 0) { ++ JS_ThrowTypeError(ctx, "map contains duplicate key"); ++ JS_FreeValue(ctx, key_val); ++ JS_FreeValue(ctx, obj); ++ js_free(ctx, prev_key); ++ return JS_EXCEPTION; ++ } ++ if (cmp > 0) { ++ JS_ThrowTypeError(ctx, "map keys are not in canonical order"); ++ JS_FreeValue(ctx, key_val); ++ JS_FreeValue(ctx, obj); ++ js_free(ctx, prev_key); ++ return JS_EXCEPTION; ++ } ++ } ++ ++ if (prev_key) { ++ js_free(ctx, prev_key); ++ } ++ prev_key = NULL; ++ if (key_len > 0) { ++ prev_key = js_malloc(ctx, key_len); ++ if (!prev_key) { ++ JS_FreeValue(ctx, key_val); ++ JS_FreeValue(ctx, obj); ++ return JS_EXCEPTION; ++ } ++ memcpy(prev_key, key_bytes, key_len); ++ } ++ prev_key_len = key_len; ++ ++ JSValue decoded = dv_decode_value(ctx, reader, limits, depth + 1); ++ if (JS_IsException(decoded)) { ++ JS_FreeValue(ctx, key_val); ++ JS_FreeValue(ctx, obj); ++ js_free(ctx, prev_key); ++ return JS_EXCEPTION; ++ } ++ ++ size_t key_str_len = 0; ++ const char *key_str = JS_ToCStringLen(ctx, &key_str_len, key_val); ++ if (!key_str) { ++ JS_FreeValue(ctx, decoded); ++ JS_FreeValue(ctx, key_val); ++ JS_FreeValue(ctx, obj); ++ js_free(ctx, prev_key); ++ return JS_EXCEPTION; ++ } ++ ++ JSAtom atom = JS_NewAtomLen(ctx, key_str, key_str_len); ++ JS_FreeCString(ctx, key_str); ++ JS_FreeValue(ctx, key_val); ++ if (atom == JS_ATOM_NULL) { ++ JS_FreeValue(ctx, decoded); ++ JS_FreeValue(ctx, obj); ++ js_free(ctx, prev_key); ++ return JS_EXCEPTION; ++ } ++ ++ if (JS_DefinePropertyValue(ctx, obj, atom, decoded, JS_PROP_C_W_E) < 0) { ++ JS_FreeAtom(ctx, atom); ++ JS_FreeValue(ctx, obj); ++ js_free(ctx, prev_key); ++ return JS_EXCEPTION; ++ } ++ JS_FreeAtom(ctx, atom); ++ } ++ ++ if (prev_key) { ++ js_free(ctx, prev_key); ++ } ++ return obj; ++} ++ ++static JSValue dv_decode_simple_or_float(JSContext *ctx, ++ JSDvReader *reader, ++ const JSDvLimits *limits, ++ uint8_t additional) { ++ (void)limits; ++ switch (additional) { ++ case 20: ++ return JS_FALSE; ++ case 21: ++ return JS_TRUE; ++ case 22: ++ return JS_NULL; ++ case 27: { ++ uint64_t bits = 0; ++ if (dv_reader_read_be(reader, 8, &bits) != 0) { ++ return JS_EXCEPTION; ++ } ++ union { ++ uint64_t u; ++ double d; ++ } u; ++ u.u = bits; ++ if (!isfinite(u.d)) { ++ JS_ThrowTypeError(ctx, "DV numbers must be finite"); ++ return JS_EXCEPTION; ++ } ++ double int_part; ++ if (modf(u.d, &int_part) == 0.0) { ++ JS_ThrowTypeError(ctx, "integers must use CBOR integer encoding"); ++ return JS_EXCEPTION; ++ } ++ if (u.d == 0 && signbit(u.d)) { ++ u.d = 0; ++ } ++ return JS_NewFloat64(ctx, u.d); ++ } ++ case 24: ++ case 25: ++ case 26: ++ JS_ThrowTypeError(ctx, "only float64 is allowed"); ++ return JS_EXCEPTION; ++ case 31: ++ JS_ThrowTypeError(ctx, "indefinite lengths are not allowed"); ++ return JS_EXCEPTION; ++ default: ++ JS_ThrowTypeError(ctx, "unsupported simple value %u", additional); ++ return JS_EXCEPTION; ++ } ++} ++ ++static JSValue dv_decode_value(JSContext *ctx, ++ JSDvReader *reader, ++ const JSDvLimits *limits, ++ uint32_t depth) { ++ uint8_t initial = 0; ++ if (dv_reader_read_u8(reader, &initial) != 0) { ++ return JS_EXCEPTION; ++ } ++ ++ uint8_t major = initial >> 5; ++ uint8_t additional = initial & 0x1f; ++ ++ switch (major) { ++ case DV_CBOR_MAJOR_UINT: { ++ uint64_t value = 0; ++ if (dv_read_length(reader, additional, &value) != 0) { ++ return JS_EXCEPTION; ++ } ++ if (value > (uint64_t)dv_max_safe_int) { ++ JS_ThrowTypeError(ctx, "integer is outside safe range (%" PRIu64 " > %" PRIu64 ")", ++ value, ++ (uint64_t)dv_max_safe_int); ++ return JS_EXCEPTION; ++ } ++ return JS_NewInt64(ctx, (int64_t)value); ++ } ++ case DV_CBOR_MAJOR_NINT: { ++ uint64_t value = 0; ++ if (dv_read_length(reader, additional, &value) != 0) { ++ return JS_EXCEPTION; ++ } ++ if (value >= (uint64_t)dv_max_safe_int) { ++ JS_ThrowTypeError(ctx, "integer is outside safe range (-1 - %" PRIu64 " < %" PRId64 ")", ++ value, ++ dv_min_safe_int); ++ return JS_EXCEPTION; ++ } ++ int64_t neg = -1 - (int64_t)value; ++ return JS_NewInt64(ctx, neg); ++ } ++ case DV_CBOR_MAJOR_TEXT: ++ return dv_decode_text(ctx, reader, limits, additional); ++ case DV_CBOR_MAJOR_ARRAY: ++ return dv_decode_array(ctx, reader, limits, depth, additional); ++ case DV_CBOR_MAJOR_MAP: ++ return dv_decode_map(ctx, reader, limits, depth, additional); ++ case DV_CBOR_MAJOR_SIMPLE: ++ return dv_decode_simple_or_float(ctx, reader, limits, additional); ++ default: ++ JS_ThrowTypeError(ctx, "unsupported CBOR major type %u", major); ++ return JS_EXCEPTION; ++ } ++} ++ ++JSValue JS_DecodeDV(JSContext *ctx, ++ const uint8_t *data, ++ size_t length, ++ const JSDvLimits *maybe_limits) { ++ const JSDvLimits *limits = dv_limits_or_default(maybe_limits); ++ if (length > limits->max_encoded_bytes) { ++ JS_ThrowTypeError(ctx, ++ "encoded DV exceeds maxEncodedBytes (%zu > %u)", ++ length, ++ limits->max_encoded_bytes); ++ return JS_EXCEPTION; ++ } ++ ++ JSDvReader reader = { ++ .data = data, ++ .size = length, ++ .pos = 0, ++ .ctx = ctx, ++ }; ++ ++ JSValue result = dv_decode_value(ctx, &reader, limits, 0); ++ if (JS_IsException(result)) { ++ return result; ++ } ++ ++ if (reader.pos != reader.size) { ++ JS_FreeValue(ctx, result); ++ JS_ThrowTypeError(ctx, "unexpected trailing bytes after DV value"); ++ return JS_EXCEPTION; ++ } ++ ++ return result; ++} ++ ++void JS_FreeDVBuffer(JSContext *ctx, JSDvBuffer *buffer) { ++ if (!buffer || !buffer->data) { ++ return; ++ } ++ js_free(ctx, buffer->data); ++ buffer->data = NULL; ++ buffer->length = 0; ++} ++ ++const JSDvLimits JS_DV_LIMIT_DEFAULTS = { ++ .max_depth = 64, ++ .max_encoded_bytes = 1048576, ++ .max_string_bytes = 262144, ++ .max_array_length = 65535, ++ .max_map_length = 65535, ++}; +diff --git a/quickjs.h b/quickjs.h +index 6d362b5..c850ba7 100644 +--- a/quickjs.h ++++ b/quickjs.h +@@ -411,6 +411,26 @@ int JS_EnableGasTrace(JSContext *ctx, int enabled); + int JS_ResetGasTrace(JSContext *ctx); + int JS_ReadGasTrace(JSContext *ctx, JSGasTrace *out_trace); + int JS_UseGas(JSContext *ctx, uint64_t amount); ++ ++typedef struct JSDvLimits { ++ uint32_t max_depth; ++ uint32_t max_encoded_bytes; ++ uint32_t max_string_bytes; ++ uint32_t max_array_length; ++ uint32_t max_map_length; ++} JSDvLimits; ++ ++typedef struct JSDvBuffer { ++ uint8_t *data; ++ size_t length; ++} JSDvBuffer; ++ ++extern const JSDvLimits JS_DV_LIMIT_DEFAULTS; ++ ++int JS_EncodeDV(JSContext *ctx, JSValueConst value, const JSDvLimits *limits, JSDvBuffer *out_buffer); ++JSValue JS_DecodeDV(JSContext *ctx, const uint8_t *data, size_t length, const JSDvLimits *limits); ++void JS_FreeDVBuffer(JSContext *ctx, JSDvBuffer *buffer); ++ + JSRuntime *JS_GetRuntime(JSContext *ctx); + void JS_SetClassProto(JSContext *ctx, JSClassID class_id, JSValue obj); + JSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id); diff --git a/vendor/quickjs-patches/series/0014-feat-quickjs-add-deterministic-context-init-with-abi.patch b/vendor/quickjs-patches/series/0014-feat-quickjs-add-deterministic-context-init-with-abi.patch new file mode 100644 index 0000000..7e0ce5f --- /dev/null +++ b/vendor/quickjs-patches/series/0014-feat-quickjs-add-deterministic-context-init-with-abi.patch @@ -0,0 +1,443 @@ +From 59c29ef5ac40f514160b5c3e5aa06a692e5d8e18 Mon Sep 17 00:00:00 2001 +From: Mateusz Jonak +Date: Tue, 16 Dec 2025 11:12:25 +0100 +Subject: [PATCH 14/51] feat(quickjs): add deterministic context init with ABI + manifest hash check + +Introduce JS_InitDeterministicContext() and JSDeterministicInitOptions to +initialize a deterministic JSContext from an ABI manifest + optional context +blob and gas limit. + +Validate manifest size and required hash, compute/compare SHA-256, throw a +ManifestError (ABI_MANIFEST_HASH_MISMATCH) on mismatch, and store owned copies +on the context (freed in JS_FreeContext). Add internal SHA-256 helpers and link +quickjs-dv/quickjs-sha256 into the QuickJS lib build. +--- + Makefile | 2 +- + quickjs-internal.h | 11 +++ + quickjs-sha256.c | 163 +++++++++++++++++++++++++++++++++++++++++++++ + quickjs.c | 158 +++++++++++++++++++++++++++++++++++++++++++ + quickjs.h | 12 ++++ + 5 files changed, 345 insertions(+), 1 deletion(-) + create mode 100644 quickjs-internal.h + create mode 100644 quickjs-sha256.c + +diff --git a/Makefile b/Makefile +index dcbbf7e..47e5ac1 100644 +--- a/Makefile ++++ b/Makefile +@@ -243,7 +243,7 @@ endif + + all: $(OBJDIR) $(OBJDIR)/quickjs.check.o $(OBJDIR)/qjs.check.o $(PROGS) + +-QJS_LIB_OBJS=$(OBJDIR)/quickjs.o $(OBJDIR)/dtoa.o $(OBJDIR)/libregexp.o $(OBJDIR)/libunicode.o $(OBJDIR)/cutils.o $(OBJDIR)/quickjs-libc.o ++QJS_LIB_OBJS=$(OBJDIR)/quickjs.o $(OBJDIR)/quickjs-dv.o $(OBJDIR)/quickjs-sha256.o $(OBJDIR)/dtoa.o $(OBJDIR)/libregexp.o $(OBJDIR)/libunicode.o $(OBJDIR)/cutils.o $(OBJDIR)/quickjs-libc.o + + QJS_OBJS=$(OBJDIR)/qjs.o $(OBJDIR)/repl.o $(QJS_LIB_OBJS) + +diff --git a/quickjs-internal.h b/quickjs-internal.h +new file mode 100644 +index 0000000..942ca08 +--- /dev/null ++++ b/quickjs-internal.h +@@ -0,0 +1,11 @@ ++#ifndef QUICKJS_INTERNAL_H ++#define QUICKJS_INTERNAL_H ++ ++#include ++#include ++ ++/* Internal helpers not exposed in the public QuickJS API surface. */ ++void js_sha256(const uint8_t *data, size_t len, uint8_t out_hash[32]); ++void js_sha256_to_hex(const uint8_t hash[32], char out_hex[65]); ++ ++#endif /* QUICKJS_INTERNAL_H */ +diff --git a/quickjs-sha256.c b/quickjs-sha256.c +new file mode 100644 +index 0000000..3cb4896 +--- /dev/null ++++ b/quickjs-sha256.c +@@ -0,0 +1,163 @@ ++#include ++#include ++#include ++ ++typedef struct { ++ uint8_t data[64]; ++ uint32_t datalen; ++ uint64_t bitlen; ++ uint32_t state[8]; ++} JSSHA256Context; ++ ++static const uint32_t js_sha256_k[64] = { ++ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, ++ 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, ++ 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, ++ 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, ++ 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, ++ 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, ++ 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, ++ 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, ++ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, ++ 0xc67178f2}; ++ ++#define JS_SHA256_ROTR(x, n) (((x) >> (n)) | ((x) << (32 - (n)))) ++#define JS_SHA256_CH(x, y, z) (((x) & (y)) ^ (~(x) & (z))) ++#define JS_SHA256_MAJ(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) ++#define JS_SHA256_EP0(x) (JS_SHA256_ROTR(x, 2) ^ JS_SHA256_ROTR(x, 13) ^ JS_SHA256_ROTR(x, 22)) ++#define JS_SHA256_EP1(x) (JS_SHA256_ROTR(x, 6) ^ JS_SHA256_ROTR(x, 11) ^ JS_SHA256_ROTR(x, 25)) ++#define JS_SHA256_SIG0(x) (JS_SHA256_ROTR(x, 7) ^ JS_SHA256_ROTR(x, 18) ^ ((x) >> 3)) ++#define JS_SHA256_SIG1(x) (JS_SHA256_ROTR(x, 17) ^ JS_SHA256_ROTR(x, 19) ^ ((x) >> 10)) ++ ++static void js_sha256_transform(JSSHA256Context *ctx, const uint8_t data[64]) ++{ ++ uint32_t m[64]; ++ uint32_t a, b, c, d, e, f, g, h; ++ size_t i; ++ ++ for(i = 0; i < 16; i++) { ++ m[i] = ((uint32_t)data[i * 4] << 24) | ((uint32_t)data[i * 4 + 1] << 16) | ++ ((uint32_t)data[i * 4 + 2] << 8) | ((uint32_t)data[i * 4 + 3]); ++ } ++ ++ for(; i < 64; i++) { ++ m[i] = JS_SHA256_SIG1(m[i - 2]) + m[i - 7] + JS_SHA256_SIG0(m[i - 15]) + m[i - 16]; ++ } ++ ++ a = ctx->state[0]; ++ b = ctx->state[1]; ++ c = ctx->state[2]; ++ d = ctx->state[3]; ++ e = ctx->state[4]; ++ f = ctx->state[5]; ++ g = ctx->state[6]; ++ h = ctx->state[7]; ++ ++ for(i = 0; i < 64; i++) { ++ uint32_t t1 = h + JS_SHA256_EP1(e) + JS_SHA256_CH(e, f, g) + js_sha256_k[i] + m[i]; ++ uint32_t t2 = JS_SHA256_EP0(a) + JS_SHA256_MAJ(a, b, c); ++ h = g; ++ g = f; ++ f = e; ++ e = d + t1; ++ d = c; ++ c = b; ++ b = a; ++ a = t1 + t2; ++ } ++ ++ ctx->state[0] += a; ++ ctx->state[1] += b; ++ ctx->state[2] += c; ++ ctx->state[3] += d; ++ ctx->state[4] += e; ++ ctx->state[5] += f; ++ ctx->state[6] += g; ++ ctx->state[7] += h; ++} ++ ++static void js_sha256_init(JSSHA256Context *ctx) ++{ ++ ctx->datalen = 0; ++ ctx->bitlen = 0; ++ ctx->state[0] = 0x6a09e667; ++ ctx->state[1] = 0xbb67ae85; ++ ctx->state[2] = 0x3c6ef372; ++ ctx->state[3] = 0xa54ff53a; ++ ctx->state[4] = 0x510e527f; ++ ctx->state[5] = 0x9b05688c; ++ ctx->state[6] = 0x1f83d9ab; ++ ctx->state[7] = 0x5be0cd19; ++} ++ ++static void js_sha256_update(JSSHA256Context *ctx, const uint8_t *data, size_t len) ++{ ++ for(size_t i = 0; i < len; i++) { ++ ctx->data[ctx->datalen] = data[i]; ++ ctx->datalen++; ++ if(ctx->datalen == 64) { ++ js_sha256_transform(ctx, ctx->data); ++ ctx->bitlen += 512; ++ ctx->datalen = 0; ++ } ++ } ++} ++ ++static void js_sha256_final(JSSHA256Context *ctx, uint8_t hash[32]) ++{ ++ uint32_t i = ctx->datalen; ++ ++ if(ctx->datalen < 56) { ++ ctx->data[i++] = 0x80; ++ while(i < 56) { ++ ctx->data[i++] = 0x00; ++ } ++ } else { ++ ctx->data[i++] = 0x80; ++ while(i < 64) { ++ ctx->data[i++] = 0x00; ++ } ++ js_sha256_transform(ctx, ctx->data); ++ memset(ctx->data, 0, 56); ++ } ++ ++ ctx->bitlen += (uint64_t)ctx->datalen * 8; ++ ctx->data[63] = (uint8_t)(ctx->bitlen); ++ ctx->data[62] = (uint8_t)(ctx->bitlen >> 8); ++ ctx->data[61] = (uint8_t)(ctx->bitlen >> 16); ++ ctx->data[60] = (uint8_t)(ctx->bitlen >> 24); ++ ctx->data[59] = (uint8_t)(ctx->bitlen >> 32); ++ ctx->data[58] = (uint8_t)(ctx->bitlen >> 40); ++ ctx->data[57] = (uint8_t)(ctx->bitlen >> 48); ++ ctx->data[56] = (uint8_t)(ctx->bitlen >> 56); ++ js_sha256_transform(ctx, ctx->data); ++ ++ for(i = 0; i < 4; i++) { ++ hash[i] = (uint8_t)((ctx->state[0] >> (24 - i * 8)) & 0xff); ++ hash[i + 4] = (uint8_t)((ctx->state[1] >> (24 - i * 8)) & 0xff); ++ hash[i + 8] = (uint8_t)((ctx->state[2] >> (24 - i * 8)) & 0xff); ++ hash[i + 12] = (uint8_t)((ctx->state[3] >> (24 - i * 8)) & 0xff); ++ hash[i + 16] = (uint8_t)((ctx->state[4] >> (24 - i * 8)) & 0xff); ++ hash[i + 20] = (uint8_t)((ctx->state[5] >> (24 - i * 8)) & 0xff); ++ hash[i + 24] = (uint8_t)((ctx->state[6] >> (24 - i * 8)) & 0xff); ++ hash[i + 28] = (uint8_t)((ctx->state[7] >> (24 - i * 8)) & 0xff); ++ } ++} ++ ++void js_sha256(const uint8_t *data, size_t len, uint8_t out_hash[32]) ++{ ++ JSSHA256Context ctx; ++ js_sha256_init(&ctx); ++ js_sha256_update(&ctx, data, len); ++ js_sha256_final(&ctx, out_hash); ++} ++ ++void js_sha256_to_hex(const uint8_t hash[32], char out_hex[65]) ++{ ++ static const char hex_alphabet[] = "0123456789abcdef"; ++ for(size_t i = 0; i < 32; i++) { ++ out_hex[i * 2] = hex_alphabet[hash[i] >> 4]; ++ out_hex[i * 2 + 1] = hex_alphabet[hash[i] & 0x0f]; ++ } ++ out_hex[64] = '\0'; ++} +diff --git a/quickjs.c b/quickjs.c +index ac14932..cf6a562 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -42,6 +42,7 @@ + + #include "cutils.h" + #include "list.h" ++#include "quickjs-internal.h" + #include "quickjs.h" + #include "libregexp.h" + #include "libunicode.h" +@@ -500,6 +501,13 @@ struct JSContext { + uint64_t gas_remaining; + uint32_t gas_version; + ++ uint8_t *abi_manifest_bytes; ++ size_t abi_manifest_size; ++ uint8_t abi_manifest_hash[32]; ++ char abi_manifest_hash_hex[65]; ++ uint8_t *deterministic_context_blob; ++ size_t deterministic_context_blob_size; ++ + JSGasTraceData *gas_trace; + BOOL deterministic_mode; + }; +@@ -2941,6 +2949,151 @@ int JS_NewDeterministicRuntime(JSRuntime **out_rt, JSContext **out_ctx) + return 0; + } + ++static JSValue JS_ThrowManifestError(JSContext *ctx, const char *code, const char *message) ++{ ++ JSValue obj, name, msg, code_val; ++ ++ obj = JS_NewError(ctx); ++ if (JS_IsException(obj)) ++ return JS_EXCEPTION; ++ ++ name = JS_NewString(ctx, "ManifestError"); ++ msg = JS_NewString(ctx, message); ++ code_val = JS_NewString(ctx, code); ++ if (JS_IsException(name) || JS_IsException(msg) || JS_IsException(code_val)) { ++ if (!JS_IsException(name)) ++ JS_FreeValue(ctx, name); ++ if (!JS_IsException(msg)) ++ JS_FreeValue(ctx, msg); ++ if (!JS_IsException(code_val)) ++ JS_FreeValue(ctx, code_val); ++ JS_FreeValue(ctx, obj); ++ return JS_EXCEPTION; ++ } ++ ++ JS_DefinePropertyValue(ctx, obj, JS_ATOM_name, name, ++ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); ++ JS_DefinePropertyValue(ctx, obj, JS_ATOM_message, msg, ++ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); ++ JS_DefinePropertyValueStr(ctx, obj, "code", code_val, ++ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); ++ JS_Throw(ctx, obj); ++ return JS_EXCEPTION; ++} ++ ++static int js_hex_nibble(int c) ++{ ++ if (c >= '0' && c <= '9') ++ return c - '0'; ++ if (c >= 'a' && c <= 'f') ++ return c - 'a' + 10; ++ return -1; ++} ++ ++static int js_parse_hash_hex(JSContext *ctx, const char *hex, uint8_t *out, size_t out_size) ++{ ++ size_t hex_len, i; ++ ++ if (!hex || !out) ++ return -1; ++ ++ hex_len = strlen(hex); ++ if (hex_len != out_size * 2) { ++ JS_ThrowTypeError(ctx, "abi manifest hash must be 64 lowercase hex characters"); ++ return -1; ++ } ++ ++ for(i = 0; i < out_size; i++) { ++ int high = js_hex_nibble(hex[i * 2]); ++ int low = js_hex_nibble(hex[i * 2 + 1]); ++ if (high < 0 || low < 0) { ++ JS_ThrowTypeError(ctx, "abi manifest hash must be 64 lowercase hex characters"); ++ return -1; ++ } ++ out[i] = (uint8_t)((high << 4) | low); ++ } ++ ++ return 0; ++} ++ ++int JS_InitDeterministicContext(JSContext *ctx, const JSDeterministicInitOptions *options) ++{ ++ uint8_t computed_hash[32]; ++ uint8_t expected_hash[32]; ++ uint8_t *manifest_copy = NULL; ++ uint8_t *context_copy = NULL; ++ ++ if (!ctx || !options) ++ return -1; ++ ++ if (ctx->abi_manifest_bytes) { ++ JS_ThrowTypeError(ctx, "abi manifest is already initialized"); ++ return -1; ++ } ++ ++ if (!options->manifest_bytes || options->manifest_size == 0) { ++ JS_ThrowTypeError(ctx, "abi manifest is required"); ++ return -1; ++ } ++ ++ if (options->manifest_size > JS_DETERMINISTIC_MAX_MANIFEST_BYTES) { ++ JS_ThrowTypeError(ctx, "abi manifest exceeds maximum size"); ++ return -1; ++ } ++ ++ if (!options->manifest_hash_hex) { ++ JS_ThrowTypeError(ctx, "abi manifest hash is required"); ++ return -1; ++ } ++ ++ if (js_parse_hash_hex(ctx, options->manifest_hash_hex, expected_hash, sizeof(expected_hash)) != 0) ++ return -1; ++ ++ if (options->context_blob_size > 0 && !options->context_blob) { ++ JS_ThrowTypeError(ctx, "context blob is required when context_blob_size is set"); ++ return -1; ++ } ++ ++ js_sha256(options->manifest_bytes, options->manifest_size, computed_hash); ++ if (memcmp(computed_hash, expected_hash, sizeof(expected_hash)) != 0) { ++ JS_ThrowManifestError(ctx, "ABI_MANIFEST_HASH_MISMATCH", "abi manifest hash mismatch"); ++ return -1; ++ } ++ ++ manifest_copy = js_malloc_rt(ctx->rt, options->manifest_size); ++ if (!manifest_copy) { ++ JS_ThrowOutOfMemory(ctx); ++ return -1; ++ } ++ memcpy(manifest_copy, options->manifest_bytes, options->manifest_size); ++ ++ if (options->context_blob && options->context_blob_size > 0) { ++ if (options->context_blob_size > JS_DETERMINISTIC_MAX_CONTEXT_BLOB_BYTES) { ++ js_free_rt(ctx->rt, manifest_copy); ++ JS_ThrowTypeError(ctx, "context blob exceeds maximum size"); ++ return -1; ++ } ++ ++ context_copy = js_malloc_rt(ctx->rt, options->context_blob_size); ++ if (!context_copy) { ++ js_free_rt(ctx->rt, manifest_copy); ++ JS_ThrowOutOfMemory(ctx); ++ return -1; ++ } ++ memcpy(context_copy, options->context_blob, options->context_blob_size); ++ } ++ ++ memcpy(ctx->abi_manifest_hash, computed_hash, sizeof(computed_hash)); ++ js_sha256_to_hex(computed_hash, ctx->abi_manifest_hash_hex); ++ ctx->abi_manifest_bytes = manifest_copy; ++ ctx->abi_manifest_size = options->manifest_size; ++ ctx->deterministic_context_blob = context_copy; ++ ctx->deterministic_context_blob_size = context_copy ? options->context_blob_size : 0; ++ JS_SetGasLimit(ctx, options->gas_limit); ++ ++ return 0; ++} ++ + void *JS_GetContextOpaque(JSContext *ctx) + { + return ctx->user_opaque; +@@ -3262,6 +3415,11 @@ void JS_FreeContext(JSContext *ctx) + js_free_shape_null(ctx->rt, ctx->regexp_shape); + js_free_shape_null(ctx->rt, ctx->regexp_result_shape); + ++ if (ctx->abi_manifest_bytes) ++ js_free_rt(ctx->rt, ctx->abi_manifest_bytes); ++ if (ctx->deterministic_context_blob) ++ js_free_rt(ctx->rt, ctx->deterministic_context_blob); ++ + list_del(&ctx->link); + remove_gc_object(&ctx->header); + if (ctx->gas_trace) +diff --git a/quickjs.h b/quickjs.h +index c850ba7..6fbafed 100644 +--- a/quickjs.h ++++ b/quickjs.h +@@ -343,6 +343,9 @@ static inline JSValue __JS_NewShortBigInt(JSContext *ctx, int64_t d) + promise. Only allowed with JS_EVAL_TYPE_GLOBAL */ + #define JS_EVAL_FLAG_ASYNC (1 << 7) + ++#define JS_DETERMINISTIC_MAX_MANIFEST_BYTES 1048576 ++#define JS_DETERMINISTIC_MAX_CONTEXT_BLOB_BYTES 1048576 ++ + typedef JSValue JSCFunction(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); + typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); + typedef JSValue JSCFunctionData(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic, JSValue *func_data); +@@ -388,6 +391,15 @@ JS_BOOL JS_IsLiveObject(JSRuntime *rt, JSValueConst obj); + + JSContext *JS_NewContext(JSRuntime *rt); + int JS_NewDeterministicRuntime(JSRuntime **out_rt, JSContext **out_ctx); ++typedef struct JSDeterministicInitOptions { ++ const uint8_t *manifest_bytes; ++ size_t manifest_size; ++ const char *manifest_hash_hex; ++ const uint8_t *context_blob; ++ size_t context_blob_size; ++ uint64_t gas_limit; ++} JSDeterministicInitOptions; ++int JS_InitDeterministicContext(JSContext *ctx, const JSDeterministicInitOptions *options); + void JS_FreeContext(JSContext *s); + JSContext *JS_DupContext(JSContext *ctx); + void *JS_GetContextOpaque(JSContext *ctx); diff --git a/vendor/quickjs-patches/series/0015-feat-quickjs-add-deterministic-host_call-dispatcher-.patch b/vendor/quickjs-patches/series/0015-feat-quickjs-add-deterministic-host_call-dispatcher-.patch new file mode 100644 index 0000000..d87ddde --- /dev/null +++ b/vendor/quickjs-patches/series/0015-feat-quickjs-add-deterministic-host_call-dispatcher-.patch @@ -0,0 +1,276 @@ +From 8676edf5c127dd82a9cbc7599a0a4c8756e28b9f Mon Sep 17 00:00:00 2001 +From: Mateusz Jonak +Date: Tue, 16 Dec 2025 14:35:44 +0100 +Subject: [PATCH 15/51] feat(quickjs): add deterministic host_call dispatcher + API (wasm import + reentrancy guard) + +- add JS_SetHostCallDispatcher() and JS_HostCall() public API, including JSHostCallFunc/JSHostCallResult and JS_HOST_CALL_TRANSPORT_ERROR +- implement host_call plumbing in deterministic runtime with per-context scratch response buffer + bounds/limit checks +- on Emscripten, default dispatcher calls imported host.host_call; otherwise dispatcher is unset by default +- prevent reentrant host calls via rt->in_host_call and free host_call response buffer on context teardown +--- + quickjs.c | 165 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ + quickjs.h | 25 +++++++++ + 2 files changed, 190 insertions(+) + +diff --git a/quickjs.c b/quickjs.c +index cf6a562..e54a2fc 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -281,6 +281,8 @@ struct JSRuntime { + BOOL in_out_of_memory : 8; + /* true if inside out-of-gas handling to avoid recursion */ + BOOL in_out_of_gas : 8; ++ /* true if inside a host_call to prevent reentrancy */ ++ BOOL in_host_call : 8; + + struct JSStackFrame *current_stack_frame; + +@@ -289,6 +291,8 @@ struct JSRuntime { + + JSHostPromiseRejectionTracker *host_promise_rejection_tracker; + void *host_promise_rejection_tracker_opaque; ++ JSHostCallFunc *host_call_func; ++ void *host_call_opaque; + + struct list_head job_list; /* list of JSJobEntry.link */ + +@@ -508,6 +512,9 @@ struct JSContext { + uint8_t *deterministic_context_blob; + size_t deterministic_context_blob_size; + ++ uint8_t *host_call_resp_buf; ++ uint32_t host_call_resp_capacity; ++ + JSGasTraceData *gas_trace; + BOOL deterministic_mode; + }; +@@ -1883,6 +1890,16 @@ void JS_SetRuntimeOpaque(JSRuntime *rt, void *opaque) + rt->user_opaque = opaque; + } + ++int JS_SetHostCallDispatcher(JSRuntime *rt, JSHostCallFunc *func, void *opaque) ++{ ++ if (!rt) ++ return -1; ++ ++ rt->host_call_func = func; ++ rt->host_call_opaque = opaque; ++ return 0; ++} ++ + /* default memory allocation functions with memory limitation */ + static size_t js_def_malloc_usable_size(const void *ptr) + { +@@ -2912,6 +2929,25 @@ static int js_deterministic_init_context(JSContext *ctx) + return 0; + } + ++#ifdef __EMSCRIPTEN__ ++__attribute__((import_module("host"), import_name("host_call"))) ++uint32_t js_wasm_import_host_call(uint32_t fn_id, uint32_t req_ptr, uint32_t req_len, ++ uint32_t resp_ptr, uint32_t resp_capacity); ++ ++static uint32_t js_wasm_host_call(JSContext *ctx, uint32_t fn_id, const uint8_t *req_ptr, ++ uint32_t req_len, uint8_t *resp_ptr, ++ uint32_t resp_capacity, void *opaque) ++{ ++ (void)ctx; ++ (void)opaque; ++ return js_wasm_import_host_call(fn_id, ++ (uint32_t)(uintptr_t)req_ptr, ++ req_len, ++ (uint32_t)(uintptr_t)resp_ptr, ++ resp_capacity); ++} ++#endif ++ + int JS_NewDeterministicRuntime(JSRuntime **out_rt, JSContext **out_ctx) + { + JSRuntime *rt; +@@ -2930,6 +2966,13 @@ int JS_NewDeterministicRuntime(JSRuntime **out_rt, JSContext **out_ctx) + rt->deterministic_mode = TRUE; + rt->det_gc_pending = FALSE; + rt->det_gc_alloc_bytes = 0; ++#ifdef __EMSCRIPTEN__ ++ rt->host_call_func = js_wasm_host_call; ++#else ++ rt->host_call_func = NULL; ++#endif ++ rt->host_call_opaque = NULL; ++ rt->in_host_call = FALSE; + JS_SetGCThreshold(rt, (size_t)-1); + + ctx = JS_NewContextRaw(rt); +@@ -3094,6 +3137,126 @@ int JS_InitDeterministicContext(JSContext *ctx, const JSDeterministicInitOptions + return 0; + } + ++static int js_reserve_host_response_buffer(JSContext *ctx, uint32_t capacity) ++{ ++ uint8_t *new_buf; ++ ++ if (ctx->host_call_resp_capacity >= capacity) ++ return 0; ++ ++ new_buf = js_realloc_rt(ctx->rt, ctx->host_call_resp_buf, capacity); ++ if (!new_buf) { ++ JS_ThrowOutOfMemory(ctx); ++ return -1; ++ } ++ ++ ctx->host_call_resp_buf = new_buf; ++ ctx->host_call_resp_capacity = capacity; ++ return 0; ++} ++ ++int JS_HostCall(JSContext *ctx, ++ uint32_t fn_id, ++ const uint8_t *req_bytes, ++ size_t req_len, ++ uint32_t max_request_bytes, ++ uint32_t max_response_bytes, ++ JSHostCallResult *out_result) ++{ ++ JSRuntime *rt; ++ uint32_t resp_len, resp_capacity, req_len32; ++ uint32_t dv_limit; ++ const uint8_t *req_ptr; ++ ++ if (!ctx || !out_result) ++ return -1; ++ ++ out_result->data = NULL; ++ out_result->length = 0; ++ ++ rt = ctx->rt; ++ dv_limit = JS_DV_LIMIT_DEFAULTS.max_encoded_bytes; ++ ++ if (!rt->host_call_func) { ++ JS_ThrowTypeError(ctx, "host_call dispatcher is not configured"); ++ return -1; ++ } ++ ++ if (fn_id == 0) { ++ JS_ThrowTypeError(ctx, "host_call fn_id must be >= 1"); ++ return -1; ++ } ++ ++ if (max_request_bytes == 0) { ++ JS_ThrowTypeError(ctx, "host_call max_request_bytes must be > 0"); ++ return -1; ++ } ++ ++ if (max_request_bytes > dv_limit) { ++ JS_ThrowTypeError(ctx, "host_call max_request_bytes exceeds DV limit"); ++ return -1; ++ } ++ ++ if (max_response_bytes == 0) { ++ JS_ThrowTypeError(ctx, "host_call max_response_bytes must be > 0"); ++ return -1; ++ } ++ ++ if (max_response_bytes > dv_limit) { ++ JS_ThrowTypeError(ctx, "host_call max_response_bytes exceeds DV limit"); ++ return -1; ++ } ++ ++ if (req_len > (size_t)max_request_bytes) { ++ JS_ThrowTypeError(ctx, "host_call request exceeds max_request_bytes"); ++ return -1; ++ } ++ ++ if (req_len > (size_t)dv_limit) { ++ JS_ThrowTypeError(ctx, "host_call request exceeds DV limit"); ++ return -1; ++ } ++ ++ if (req_len > UINT32_MAX) { ++ JS_ThrowTypeError(ctx, "host_call request length overflow"); ++ return -1; ++ } ++ ++ if (req_len > 0 && !req_bytes) { ++ JS_ThrowTypeError(ctx, "host_call request pointer is null"); ++ return -1; ++ } ++ ++ if (rt->in_host_call) { ++ JS_ThrowTypeError(ctx, "host_call is already in progress"); ++ return -1; ++ } ++ ++ resp_capacity = max_response_bytes; ++ if (js_reserve_host_response_buffer(ctx, resp_capacity)) ++ return -1; ++ ++ rt->in_host_call = TRUE; ++ req_len32 = (uint32_t)req_len; ++ req_ptr = req_bytes ? req_bytes : NULL; ++ resp_len = rt->host_call_func(ctx, fn_id, req_ptr, req_len32, ++ ctx->host_call_resp_buf, resp_capacity, ++ rt->host_call_opaque); ++ rt->in_host_call = FALSE; ++ ++ if (JS_HasException(ctx)) ++ return -1; ++ ++ if (resp_len == JS_HOST_CALL_TRANSPORT_ERROR || resp_len > resp_capacity) { ++ JS_ThrowTypeError(ctx, "host_call transport failed"); ++ return -1; ++ } ++ ++ out_result->data = ctx->host_call_resp_buf; ++ out_result->length = resp_len; ++ return 0; ++} ++ + void *JS_GetContextOpaque(JSContext *ctx) + { + return ctx->user_opaque; +@@ -3419,6 +3582,8 @@ void JS_FreeContext(JSContext *ctx) + js_free_rt(ctx->rt, ctx->abi_manifest_bytes); + if (ctx->deterministic_context_blob) + js_free_rt(ctx->rt, ctx->deterministic_context_blob); ++ if (ctx->host_call_resp_buf) ++ js_free_rt(ctx->rt, ctx->host_call_resp_buf); + + list_del(&ctx->link); + remove_gc_object(&ctx->header); +diff --git a/quickjs.h b/quickjs.h +index 6fbafed..5c817d8 100644 +--- a/quickjs.h ++++ b/quickjs.h +@@ -424,6 +424,31 @@ int JS_ResetGasTrace(JSContext *ctx); + int JS_ReadGasTrace(JSContext *ctx, JSGasTrace *out_trace); + int JS_UseGas(JSContext *ctx, uint64_t amount); + ++#define JS_HOST_CALL_TRANSPORT_ERROR UINT32_C(0xffffffff) ++ ++typedef struct JSHostCallResult { ++ uint8_t *data; ++ uint32_t length; ++} JSHostCallResult; ++/* data points to an internal scratch buffer owned by the context; valid until the next JS_HostCall or context free */ ++ ++typedef uint32_t JSHostCallFunc(JSContext *ctx, ++ uint32_t fn_id, ++ const uint8_t *req_ptr, ++ uint32_t req_len, ++ uint8_t *resp_ptr, ++ uint32_t resp_capacity, ++ void *opaque); ++ ++int JS_SetHostCallDispatcher(JSRuntime *rt, JSHostCallFunc *func, void *opaque); ++int JS_HostCall(JSContext *ctx, ++ uint32_t fn_id, ++ const uint8_t *req_bytes, ++ size_t req_len, ++ uint32_t max_request_bytes, ++ uint32_t max_response_bytes, ++ JSHostCallResult *out_result); ++ + typedef struct JSDvLimits { + uint32_t max_depth; + uint32_t max_encoded_bytes; diff --git a/vendor/quickjs-patches/series/0016-feat-quickjs-host-add-hosterror-host-response-envelo.patch b/vendor/quickjs-patches/series/0016-feat-quickjs-host-add-hosterror-host-response-envelo.patch new file mode 100644 index 0000000..a4af0d5 --- /dev/null +++ b/vendor/quickjs-patches/series/0016-feat-quickjs-host-add-hosterror-host-response-envelo.patch @@ -0,0 +1,507 @@ +From dc368adab17e1d696baee86c1a73e0ec51bf6b60 Mon Sep 17 00:00:00 2001 +From: Mateusz Jonak +Date: Tue, 16 Dec 2025 19:30:30 +0100 +Subject: [PATCH 16/51] feat(quickjs-host): add HostError + host response + envelope helpers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add `quickjs-host.{c,h}` implementing `HostError` construction and host response envelope parsing (T-039), including DV decode, strict envelope validation, units bounds checks, and whitelisted error code→tag mapping. + +- Wire `quickjs-host.o` into `QJS_LIB_OBJS` +- Use `JS_ThrowHostTransportError()` instead of a generic `TypeError` on transport failure + +Refs: T-039 +--- + Makefile | 2 +- + quickjs-host.c | 401 +++++++++++++++++++++++++++++++++++++++++++++++++ + quickjs-host.h | 36 +++++ + quickjs.c | 3 +- + 4 files changed, 440 insertions(+), 2 deletions(-) + create mode 100644 quickjs-host.c + create mode 100644 quickjs-host.h + +diff --git a/Makefile b/Makefile +index 47e5ac1..f6092cd 100644 +--- a/Makefile ++++ b/Makefile +@@ -243,7 +243,7 @@ endif + + all: $(OBJDIR) $(OBJDIR)/quickjs.check.o $(OBJDIR)/qjs.check.o $(PROGS) + +-QJS_LIB_OBJS=$(OBJDIR)/quickjs.o $(OBJDIR)/quickjs-dv.o $(OBJDIR)/quickjs-sha256.o $(OBJDIR)/dtoa.o $(OBJDIR)/libregexp.o $(OBJDIR)/libunicode.o $(OBJDIR)/cutils.o $(OBJDIR)/quickjs-libc.o ++QJS_LIB_OBJS=$(OBJDIR)/quickjs.o $(OBJDIR)/quickjs-host.o $(OBJDIR)/quickjs-dv.o $(OBJDIR)/quickjs-sha256.o $(OBJDIR)/dtoa.o $(OBJDIR)/libregexp.o $(OBJDIR)/libunicode.o $(OBJDIR)/cutils.o $(OBJDIR)/quickjs-libc.o + + QJS_OBJS=$(OBJDIR)/qjs.o $(OBJDIR)/repl.o $(QJS_LIB_OBJS) + +diff --git a/quickjs-host.c b/quickjs-host.c +new file mode 100644 +index 0000000..d2295fe +--- /dev/null ++++ b/quickjs-host.c +@@ -0,0 +1,401 @@ ++#include "cutils.h" ++#include "quickjs-host.h" ++#include "quickjs-internal.h" ++#include ++#include ++ ++#define JS_HOST_ERROR_CODE_TRANSPORT "HOST_TRANSPORT" ++#define JS_HOST_ERROR_TAG_TRANSPORT "host/transport" ++#define JS_HOST_ERROR_CODE_ENVELOPE_INVALID "HOST_ENVELOPE_INVALID" ++#define JS_HOST_ERROR_TAG_ENVELOPE_INVALID "host/envelope_invalid" ++ ++static JSValue js_throw_host_error_str(JSContext *ctx, const char *code, const char *tag, JSValueConst details) ++{ ++ JSValue ret; ++ JSAtom code_atom = JS_NewAtom(ctx, code); ++ JSAtom tag_atom = JS_NewAtom(ctx, tag); ++ ++ if (code_atom == JS_ATOM_NULL || tag_atom == JS_ATOM_NULL) { ++ if (code_atom != JS_ATOM_NULL) ++ JS_FreeAtom(ctx, code_atom); ++ if (tag_atom != JS_ATOM_NULL) ++ JS_FreeAtom(ctx, tag_atom); ++ return JS_EXCEPTION; ++ } ++ ++ ret = JS_ThrowHostError(ctx, code_atom, tag_atom, details); ++ JS_FreeAtom(ctx, code_atom); ++ JS_FreeAtom(ctx, tag_atom); ++ return ret; ++} ++ ++JSValue JS_ThrowHostError(JSContext *ctx, JSAtom code_atom, JSAtom tag_atom, JSValueConst details) ++{ ++ JSValue obj, name, msg, code_val, tag_val, details_val; ++ ++ obj = JS_NewError(ctx); ++ if (JS_IsException(obj)) ++ return JS_EXCEPTION; ++ ++ name = JS_NewString(ctx, "HostError"); ++ msg = JS_AtomToString(ctx, tag_atom); ++ code_val = JS_AtomToString(ctx, code_atom); ++ tag_val = JS_DupValue(ctx, msg); ++ details_val = JS_DupValue(ctx, details); ++ ++ if (JS_IsException(name) || JS_IsException(msg) || JS_IsException(code_val) || ++ JS_IsException(tag_val) || JS_IsException(details_val)) { ++ if (!JS_IsException(name)) ++ JS_FreeValue(ctx, name); ++ if (!JS_IsException(msg)) ++ JS_FreeValue(ctx, msg); ++ if (!JS_IsException(code_val)) ++ JS_FreeValue(ctx, code_val); ++ if (!JS_IsException(tag_val)) ++ JS_FreeValue(ctx, tag_val); ++ if (!JS_IsException(details_val)) ++ JS_FreeValue(ctx, details_val); ++ JS_FreeValue(ctx, obj); ++ return JS_EXCEPTION; ++ } ++ ++ JS_DefinePropertyValueStr(ctx, obj, "name", name, ++ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); ++ JS_DefinePropertyValueStr(ctx, obj, "message", msg, ++ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); ++ JS_DefinePropertyValueStr(ctx, obj, "code", code_val, ++ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); ++ JS_DefinePropertyValueStr(ctx, obj, "tag", tag_val, ++ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); ++ JS_DefinePropertyValueStr(ctx, obj, "details", details_val, ++ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); ++ JS_Throw(ctx, obj); ++ return JS_EXCEPTION; ++} ++ ++JSValue JS_ThrowHostTransportError(JSContext *ctx) ++{ ++ return js_throw_host_error_str(ctx, ++ JS_HOST_ERROR_CODE_TRANSPORT, ++ JS_HOST_ERROR_TAG_TRANSPORT, ++ JS_UNDEFINED); ++} ++ ++static JSValue js_throw_host_envelope_invalid(JSContext *ctx) ++{ ++ return js_throw_host_error_str(ctx, ++ JS_HOST_ERROR_CODE_ENVELOPE_INVALID, ++ JS_HOST_ERROR_TAG_ENVELOPE_INVALID, ++ JS_UNDEFINED); ++} ++ ++void JS_FreeHostResponse(JSContext *ctx, JSHostResponse *resp) ++{ ++ if (!ctx || !resp) ++ return; ++ ++ if (!JS_IsUndefined(resp->ok)) ++ JS_FreeValue(ctx, resp->ok); ++ if (!JS_IsUndefined(resp->err_details)) ++ JS_FreeValue(ctx, resp->err_details); ++ if (resp->err_code_atom != JS_ATOM_NULL) ++ JS_FreeAtom(ctx, resp->err_code_atom); ++ if (resp->err_tag_atom != JS_ATOM_NULL) ++ JS_FreeAtom(ctx, resp->err_tag_atom); ++ ++ resp->is_error = 0; ++ resp->units = 0; ++ resp->ok = JS_UNDEFINED; ++ resp->err_details = JS_UNDEFINED; ++ resp->err_code_atom = JS_ATOM_NULL; ++ resp->err_tag_atom = JS_ATOM_NULL; ++} ++ ++int JS_ParseHostResponse(JSContext *ctx, ++ const uint8_t *data, ++ size_t length, ++ const JSHostResponseValidation *validation, ++ JSHostResponse *out) ++{ ++ JSHostResponse tmp; ++ JSValue envelope = JS_UNDEFINED; ++ JSValue ok_val = JS_UNDEFINED; ++ JSValue err_val = JS_UNDEFINED; ++ JSValue units_val = JS_UNDEFINED; ++ JSValue err_code_val = JS_UNDEFINED; ++ JSValue err_details_val = JS_UNDEFINED; ++ JSPropertyEnum *props = NULL; ++ JSPropertyEnum *err_props = NULL; ++ uint32_t props_len = 0; ++ uint32_t err_props_len = 0; ++ JSAtom ok_atom = JS_ATOM_NULL; ++ JSAtom err_atom = JS_ATOM_NULL; ++ JSAtom units_atom = JS_ATOM_NULL; ++ JSAtom code_atom = JS_ATOM_NULL; ++ JSAtom details_atom = JS_ATOM_NULL; ++ BOOL has_pending_exception = FALSE; ++ int ret = -1; ++ ++ if (!ctx || !validation || !out) ++ return -1; ++ ++ if (validation->error_count > 0 && !validation->errors) { ++ JS_ThrowTypeError(ctx, "host response errors table is required"); ++ return -1; ++ } ++ ++ tmp.is_error = 0; ++ tmp.units = 0; ++ tmp.ok = JS_UNDEFINED; ++ tmp.err_code_atom = JS_ATOM_NULL; ++ tmp.err_tag_atom = JS_ATOM_NULL; ++ tmp.err_details = JS_UNDEFINED; ++ ++ if (!data && length > 0) { ++ js_throw_host_envelope_invalid(ctx); ++ return -1; ++ } ++ ++ if (length > JS_DV_LIMIT_DEFAULTS.max_encoded_bytes) { ++ js_throw_host_envelope_invalid(ctx); ++ return -1; ++ } ++ ++ envelope = JS_DecodeDV(ctx, data, length, &JS_DV_LIMIT_DEFAULTS); ++ if (JS_IsException(envelope)) { ++ has_pending_exception = TRUE; ++ goto envelope_invalid; ++ } ++ ++ if (!JS_IsObject(envelope)) ++ goto envelope_invalid; ++ ++ ok_atom = JS_NewAtom(ctx, "ok"); ++ err_atom = JS_NewAtom(ctx, "err"); ++ units_atom = JS_NewAtom(ctx, "units"); ++ code_atom = JS_NewAtom(ctx, "code"); ++ details_atom = JS_NewAtom(ctx, "details"); ++ if (ok_atom == JS_ATOM_NULL || err_atom == JS_ATOM_NULL || units_atom == JS_ATOM_NULL || ++ code_atom == JS_ATOM_NULL || details_atom == JS_ATOM_NULL) { ++ has_pending_exception = TRUE; ++ goto envelope_invalid; ++ } ++ ++ if (JS_GetOwnPropertyNames(ctx, &props, &props_len, envelope, ++ JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY) < 0) { ++ has_pending_exception = TRUE; ++ goto envelope_invalid; ++ } ++ ++ for (uint32_t i = 0; i < props_len; i++) { ++ JSAtom atom = props[i].atom; ++ if (atom != ok_atom && atom != err_atom && atom != units_atom) { ++ goto envelope_invalid; ++ } ++ } ++ ++ ok_val = JS_GetProperty(ctx, envelope, ok_atom); ++ if (JS_IsException(ok_val)) { ++ has_pending_exception = TRUE; ++ goto envelope_invalid; ++ } ++ ++ err_val = JS_GetProperty(ctx, envelope, err_atom); ++ if (JS_IsException(err_val)) { ++ has_pending_exception = TRUE; ++ goto envelope_invalid; ++ } ++ ++ units_val = JS_GetProperty(ctx, envelope, units_atom); ++ if (JS_IsException(units_val)) { ++ has_pending_exception = TRUE; ++ goto envelope_invalid; ++ } ++ ++ BOOL has_ok = !JS_IsUndefined(ok_val); ++ BOOL has_err = !JS_IsUndefined(err_val); ++ ++ if ((has_ok && has_err) || (!has_ok && !has_err)) ++ goto envelope_invalid; ++ ++ if (JS_IsUndefined(units_val)) ++ goto envelope_invalid; ++ ++ if (!JS_IsNumber(units_val)) ++ goto envelope_invalid; ++ ++ double units_d; ++ if (JS_ToFloat64(ctx, &units_d, units_val)) { ++ has_pending_exception = TRUE; ++ goto envelope_invalid; ++ } ++ ++ if (!isfinite(units_d)) ++ goto envelope_invalid; ++ ++ if ((units_d == 0.0 && signbit(units_d)) || units_d < 0.0 || ++ units_d > (double)UINT32_MAX || units_d > (double)validation->max_units) ++ goto envelope_invalid; ++ ++ if (floor(units_d) != units_d) ++ goto envelope_invalid; ++ ++ tmp.units = (uint32_t)units_d; ++ ++ if (has_ok) { ++ tmp.is_error = 0; ++ tmp.ok = ok_val; ++ ok_val = JS_UNDEFINED; ++ } else { ++ if (!JS_IsObject(err_val)) ++ goto envelope_invalid; ++ ++ if (JS_GetOwnPropertyNames(ctx, &err_props, &err_props_len, err_val, ++ JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY) < 0) { ++ has_pending_exception = TRUE; ++ goto envelope_invalid; ++ } ++ ++ for (uint32_t i = 0; i < err_props_len; i++) { ++ JSAtom atom = err_props[i].atom; ++ if (atom != code_atom && atom != details_atom) { ++ goto envelope_invalid; ++ } ++ } ++ ++ err_code_val = JS_GetProperty(ctx, err_val, code_atom); ++ if (JS_IsException(err_code_val)) { ++ has_pending_exception = TRUE; ++ goto envelope_invalid; ++ } ++ ++ if (JS_IsUndefined(err_code_val)) ++ goto envelope_invalid; ++ ++ if (!JS_IsString(err_code_val)) ++ goto envelope_invalid; ++ ++ const char *code_str = JS_ToCString(ctx, err_code_val); ++ if (!code_str) { ++ has_pending_exception = TRUE; ++ goto envelope_invalid; ++ } ++ ++ JSAtom code_atom_val = JS_NewAtom(ctx, code_str); ++ JS_FreeCString(ctx, code_str); ++ if (code_atom_val == JS_ATOM_NULL) { ++ has_pending_exception = TRUE; ++ goto envelope_invalid; ++ } ++ ++ JSAtom tag_atom_val = JS_ATOM_NULL; ++ for (size_t i = 0; i < validation->error_count; i++) { ++ if (validation->errors[i].code_atom == code_atom_val) { ++ tag_atom_val = validation->errors[i].tag_atom; ++ break; ++ } ++ } ++ ++ if (tag_atom_val == JS_ATOM_NULL) { ++ JS_FreeAtom(ctx, code_atom_val); ++ goto envelope_invalid; ++ } ++ ++ tmp.is_error = 1; ++ tmp.err_code_atom = code_atom_val; ++ tmp.err_tag_atom = JS_DupAtom(ctx, tag_atom_val); ++ if (tmp.err_tag_atom == JS_ATOM_NULL) { ++ has_pending_exception = TRUE; ++ goto envelope_invalid; ++ } ++ ++ err_details_val = JS_GetProperty(ctx, err_val, details_atom); ++ if (JS_IsException(err_details_val)) { ++ has_pending_exception = TRUE; ++ goto envelope_invalid; ++ } ++ ++ if (!JS_IsUndefined(err_details_val)) { ++ tmp.err_details = err_details_val; ++ err_details_val = JS_UNDEFINED; ++ } ++ JS_FreeValue(ctx, err_code_val); ++ err_code_val = JS_UNDEFINED; ++ } ++ ++ ret = 0; ++ *out = tmp; ++ tmp.ok = JS_UNDEFINED; ++ tmp.err_details = JS_UNDEFINED; ++ tmp.err_code_atom = JS_ATOM_NULL; ++ tmp.err_tag_atom = JS_ATOM_NULL; ++ goto done; ++ ++envelope_invalid: ++ if (has_pending_exception) { ++ JSValue pending = JS_GetException(ctx); ++ if (!JS_IsException(pending)) { ++ BOOL is_out_of_gas = FALSE; ++ ++ if (JS_IsError(ctx, pending)) { ++ JSValue code_val = JS_GetPropertyStr(ctx, pending, "code"); ++ if (JS_IsException(code_val)) { ++ JSValue exc2 = JS_GetException(ctx); ++ if (!JS_IsException(exc2)) ++ JS_FreeValue(ctx, exc2); ++ JS_FreeValue(ctx, code_val); ++ } else { ++ const char *code_str = JS_ToCString(ctx, code_val); ++ if (code_str) { ++ if (strcmp(code_str, "OOG") == 0) ++ is_out_of_gas = TRUE; ++ JS_FreeCString(ctx, code_str); ++ } ++ JS_FreeValue(ctx, code_val); ++ } ++ } ++ ++ if (is_out_of_gas) { ++ JS_Throw(ctx, pending); ++ JS_SetUncatchableException(ctx, TRUE); ++ ret = -1; ++ JS_FreeHostResponse(ctx, &tmp); ++ goto done; ++ } ++ JS_FreeValue(ctx, pending); ++ } ++ } ++ ++ js_throw_host_envelope_invalid(ctx); ++ ret = -1; ++ JS_FreeHostResponse(ctx, &tmp); ++ ++done: ++ if (props) ++ JS_FreePropertyEnum(ctx, props, props_len); ++ if (err_props) ++ JS_FreePropertyEnum(ctx, err_props, err_props_len); ++ if (ok_atom != JS_ATOM_NULL) ++ JS_FreeAtom(ctx, ok_atom); ++ if (err_atom != JS_ATOM_NULL) ++ JS_FreeAtom(ctx, err_atom); ++ if (units_atom != JS_ATOM_NULL) ++ JS_FreeAtom(ctx, units_atom); ++ if (code_atom != JS_ATOM_NULL) ++ JS_FreeAtom(ctx, code_atom); ++ if (details_atom != JS_ATOM_NULL) ++ JS_FreeAtom(ctx, details_atom); ++ if (!JS_IsUndefined(envelope)) ++ JS_FreeValue(ctx, envelope); ++ if (!JS_IsUndefined(ok_val)) ++ JS_FreeValue(ctx, ok_val); ++ if (!JS_IsUndefined(err_val)) ++ JS_FreeValue(ctx, err_val); ++ if (!JS_IsUndefined(units_val)) ++ JS_FreeValue(ctx, units_val); ++ if (!JS_IsUndefined(err_code_val)) ++ JS_FreeValue(ctx, err_code_val); ++ if (!JS_IsUndefined(err_details_val)) ++ JS_FreeValue(ctx, err_details_val); ++ return ret; ++} +diff --git a/quickjs-host.h b/quickjs-host.h +new file mode 100644 +index 0000000..3ab2cbe +--- /dev/null ++++ b/quickjs-host.h +@@ -0,0 +1,36 @@ ++#ifndef QUICKJS_HOST_H ++#define QUICKJS_HOST_H ++ ++#include "quickjs.h" ++ ++typedef struct JSHostErrorEntry { ++ JSAtom code_atom; ++ JSAtom tag_atom; ++} JSHostErrorEntry; ++ ++typedef struct JSHostResponseValidation { ++ uint32_t max_units; ++ const JSHostErrorEntry *errors; ++ size_t error_count; ++} JSHostResponseValidation; ++ ++typedef struct JSHostResponse { ++ int is_error; ++ uint32_t units; ++ JSValue ok; ++ JSAtom err_code_atom; ++ JSAtom err_tag_atom; ++ JSValue err_details; ++} JSHostResponse; ++ ++/* Host response envelope helpers (T-039). */ ++JSValue JS_ThrowHostError(JSContext *ctx, JSAtom code_atom, JSAtom tag_atom, JSValueConst details); ++JSValue JS_ThrowHostTransportError(JSContext *ctx); ++int JS_ParseHostResponse(JSContext *ctx, ++ const uint8_t *data, ++ size_t length, ++ const JSHostResponseValidation *validation, ++ JSHostResponse *out); ++void JS_FreeHostResponse(JSContext *ctx, JSHostResponse *resp); ++ ++#endif /* QUICKJS_HOST_H */ +diff --git a/quickjs.c b/quickjs.c +index e54a2fc..3cc7d35 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -44,6 +44,7 @@ + #include "list.h" + #include "quickjs-internal.h" + #include "quickjs.h" ++#include "quickjs-host.h" + #include "libregexp.h" + #include "libunicode.h" + #include "dtoa.h" +@@ -3248,7 +3249,7 @@ int JS_HostCall(JSContext *ctx, + return -1; + + if (resp_len == JS_HOST_CALL_TRANSPORT_ERROR || resp_len > resp_capacity) { +- JS_ThrowTypeError(ctx, "host_call transport failed"); ++ JS_ThrowHostTransportError(ctx); + return -1; + } + diff --git a/vendor/quickjs-patches/series/0017-feat-quickjs-host-parse-host.v1-manifest-and-install.patch b/vendor/quickjs-patches/series/0017-feat-quickjs-host-parse-host.v1-manifest-and-install.patch new file mode 100644 index 0000000..1a9b53c --- /dev/null +++ b/vendor/quickjs-patches/series/0017-feat-quickjs-host-parse-host.v1-manifest-and-install.patch @@ -0,0 +1,1511 @@ +From e4fbc8fade5c3bd9305bd517723df5418b8b7a0e Mon Sep 17 00:00:00 2001 +From: Mateusz Jonak +Date: Tue, 16 Dec 2025 21:42:40 +0100 +Subject: [PATCH 17/51] feat(quickjs-host): parse Host.v1 manifest and install + deterministic host bindings (T-040) + +- add DV manifest parser + validation (sorted fn_id, js_path collision checks, reserved error codes) +- generate/install Host.v1 namespaces + per-function CFunction wrappers with pre/post gas charging +- validate args/return types (string/null/dv) and enforce per-arg utf8 limits +- expose host lifecycle API: JS_InitHostFromManifest / JS_FreeHostManifest +- init deterministic contexts from manifest and free manifest state on JS_FreeContext +- prevent extensions on Host namespaces created from the manifest + +Refs: T-040 +--- + quickjs-host.c | 1419 ++++++++++++++++++++++++++++++++++++++++++++++++ + quickjs-host.h | 4 + + quickjs.c | 11 +- + 3 files changed, 1431 insertions(+), 3 deletions(-) + +diff --git a/quickjs-host.c b/quickjs-host.c +index d2295fe..0deeaa9 100644 +--- a/quickjs-host.c ++++ b/quickjs-host.c +@@ -2,6 +2,7 @@ + #include "quickjs-host.h" + #include "quickjs-internal.h" + #include ++#include + #include + + #define JS_HOST_ERROR_CODE_TRANSPORT "HOST_TRANSPORT" +@@ -399,3 +400,1421 @@ done: + JS_FreeValue(ctx, err_details_val); + return ret; + } ++ ++/* ------------------------------------------------------------------------- */ ++/* Host manifest parsing and Host.v1 generation (T-040) */ ++ ++extern void *js_malloc(JSContext *ctx, size_t size); ++extern void js_free(JSContext *ctx, void *ptr); ++extern void *js_realloc(JSContext *ctx, void *ptr, size_t size); ++ ++typedef enum { ++ JS_HOST_SCHEMA_STRING, ++ JS_HOST_SCHEMA_DV, ++ JS_HOST_SCHEMA_NULL, ++} JSHostSchemaType; ++ ++typedef enum { ++ JS_HOST_EFFECT_READ, ++ JS_HOST_EFFECT_EMIT, ++ JS_HOST_EFFECT_MUTATE, ++} JSHostEffect; ++ ++typedef struct { ++ JSHostSchemaType type; ++ uint32_t utf8_max; /* 0 when not provided */ ++} JSHostArgDef; ++ ++typedef struct { ++ uint32_t fn_id; ++ size_t path_len; ++ char **path_segments; ++ char *name; ++ uint32_t arity; ++ JSHostEffect effect; ++ JSHostArgDef *args; ++ JSHostSchemaType return_type; ++ uint32_t gas_base; ++ uint32_t gas_k_arg_bytes; ++ uint32_t gas_k_ret_bytes; ++ uint32_t gas_k_units; ++ char *gas_schedule_id; ++ uint32_t max_request_bytes; ++ uint32_t max_response_bytes; ++ uint32_t max_units; ++ JSHostErrorEntry *errors; ++ size_t error_count; ++} JSHostFunctionDef; ++ ++struct JSHostManifest { ++ JSHostFunctionDef *functions; ++ size_t function_count; ++}; ++ ++typedef struct JSHostManifestNode { ++ JSContext *ctx; ++ JSHostManifest manifest; ++ struct JSHostManifestNode *next; ++} JSHostManifestNode; ++ ++static JSHostManifestNode *js_host_manifest_list = NULL; ++ ++static JSHostManifest *js_host_find_manifest(JSContext *ctx) ++{ ++ JSHostManifestNode *node = js_host_manifest_list; ++ while (node) { ++ if (node->ctx == ctx) ++ return &node->manifest; ++ node = node->next; ++ } ++ return NULL; ++} ++ ++static void js_host_free_function(JSContext *ctx, JSHostFunctionDef *fn) ++{ ++ if (!fn) ++ return; ++ ++ if (fn->path_segments) { ++ for (size_t i = 0; i < fn->path_len; i++) { ++ if (fn->path_segments[i]) ++ js_free(ctx, fn->path_segments[i]); ++ } ++ js_free(ctx, fn->path_segments); ++ } ++ ++ if (fn->args) ++ js_free(ctx, fn->args); ++ ++ if (fn->errors) { ++ for (size_t i = 0; i < fn->error_count; i++) { ++ if (fn->errors[i].code_atom != JS_ATOM_NULL) ++ JS_FreeAtom(ctx, fn->errors[i].code_atom); ++ if (fn->errors[i].tag_atom != JS_ATOM_NULL) ++ JS_FreeAtom(ctx, fn->errors[i].tag_atom); ++ } ++ js_free(ctx, fn->errors); ++ } ++ ++ if (fn->gas_schedule_id) ++ js_free(ctx, fn->gas_schedule_id); ++ ++ if (fn->name) ++ js_free(ctx, fn->name); ++ ++ memset(fn, 0, sizeof(*fn)); ++} ++ ++static void js_host_manifest_clear(JSContext *ctx, JSHostManifest *manifest) ++{ ++ if (!manifest) ++ return; ++ ++ if (manifest->functions) { ++ for (size_t i = 0; i < manifest->function_count; i++) ++ js_host_free_function(ctx, &manifest->functions[i]); ++ js_free(ctx, manifest->functions); ++ } ++ manifest->functions = NULL; ++ manifest->function_count = 0; ++} ++ ++void JS_FreeHostManifest(JSContext *ctx) ++{ ++ JSHostManifestNode *prev = NULL; ++ JSHostManifestNode *node = js_host_manifest_list; ++ ++ while (node) { ++ if (node->ctx == ctx) { ++ if (prev) ++ prev->next = node->next; ++ else ++ js_host_manifest_list = node->next; ++ ++ js_host_manifest_clear(ctx, &node->manifest); ++ js_free(ctx, node); ++ return; ++ } ++ prev = node; ++ node = node->next; ++ } ++} ++ ++static int js_host_manifest_error(JSContext *ctx, const char *path, const char *message) ++{ ++ if (path && message) ++ JS_ThrowTypeError(ctx, "abi manifest invalid: %s (%s)", message, path); ++ else if (message) ++ JS_ThrowTypeError(ctx, "abi manifest invalid: %s", message); ++ else ++ JS_ThrowTypeError(ctx, "abi manifest invalid"); ++ return -1; ++} ++ ++static int js_host_expect_object(JSContext *ctx, JSValueConst val, const char *path) ++{ ++ if (!JS_IsObject(val) || JS_IsArray(ctx, val)) ++ return js_host_manifest_error(ctx, path, "expected object"); ++ return 0; ++} ++ ++static int js_host_check_keys(JSContext *ctx, ++ JSValueConst obj, ++ const char **required, ++ size_t required_len, ++ const char **optional, ++ size_t optional_len, ++ const char *path) ++{ ++ JSPropertyEnum *props = NULL; ++ uint32_t props_len = 0; ++ uint8_t *seen = NULL; ++ int ret = -1; ++ ++ if (JS_GetOwnPropertyNames(ctx, &props, &props_len, obj, ++ JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY) < 0) ++ return -1; ++ ++ if (required_len > 0) { ++ seen = js_malloc(ctx, required_len); ++ if (!seen) { ++ JS_FreePropertyEnum(ctx, props, props_len); ++ return -1; ++ } ++ memset(seen, 0, required_len); ++ } ++ ++ for (uint32_t i = 0; i < props_len; i++) { ++ const char *name = JS_AtomToCString(ctx, props[i].atom); ++ BOOL allowed = FALSE; ++ ++ if (!name) ++ goto cleanup; ++ ++ for (size_t j = 0; j < required_len; j++) { ++ if (strcmp(name, required[j]) == 0) { ++ allowed = TRUE; ++ if (seen) ++ seen[j] = 1; ++ break; ++ } ++ } ++ ++ if (!allowed) { ++ for (size_t j = 0; j < optional_len; j++) { ++ if (strcmp(name, optional[j]) == 0) { ++ allowed = TRUE; ++ break; ++ } ++ } ++ } ++ ++ JS_FreeCString(ctx, name); ++ ++ if (!allowed) { ++ js_host_manifest_error(ctx, path, "unknown field"); ++ goto cleanup; ++ } ++ } ++ ++ for (size_t j = 0; j < required_len; j++) { ++ if (seen && !seen[j]) { ++ js_host_manifest_error(ctx, path, "missing required field"); ++ goto cleanup; ++ } ++ } ++ ++ ret = 0; ++ ++cleanup: ++ if (props) ++ JS_FreePropertyEnum(ctx, props, props_len); ++ if (seen) ++ js_free(ctx, seen); ++ return ret; ++} ++ ++static int js_host_copy_non_empty_string(JSContext *ctx, ++ JSValueConst val, ++ const char *path, ++ char **out) ++{ ++ const char *tmp; ++ char *copy; ++ ++ if (!JS_IsString(val)) ++ return js_host_manifest_error(ctx, path, "expected string"); ++ ++ tmp = JS_ToCString(ctx, val); ++ if (!tmp) ++ return -1; ++ ++ if (tmp[0] == '\0') { ++ JS_FreeCString(ctx, tmp); ++ return js_host_manifest_error(ctx, path, "string must be non-empty"); ++ } ++ ++ copy = js_malloc(ctx, strlen(tmp) + 1); ++ if (!copy) { ++ JS_FreeCString(ctx, tmp); ++ return -1; ++ } ++ ++ strcpy(copy, tmp); ++ JS_FreeCString(ctx, tmp); ++ *out = copy; ++ return 0; ++} ++ ++static int js_host_validate_uint32(JSContext *ctx, ++ JSValueConst val, ++ const char *path, ++ uint32_t min, ++ uint32_t max, ++ uint32_t *out) ++{ ++ double d; ++ ++ if (!JS_IsNumber(val)) ++ return js_host_manifest_error(ctx, path, "expected integer"); ++ ++ if (JS_ToFloat64(ctx, &d, val)) ++ return -1; ++ ++ if (!isfinite(d) || floor(d) != d || (d == 0.0 && signbit(d)) || d < (double)min || d > (double)max) ++ return js_host_manifest_error(ctx, path, "value out of range"); ++ ++ *out = (uint32_t)d; ++ return 0; ++} ++ ++static int js_host_array_length(JSContext *ctx, JSValueConst arr, size_t *out_len) ++{ ++ JSValue len_val = JS_UNDEFINED; ++ uint32_t len32 = 0; ++ int ret = -1; ++ ++ len_val = JS_GetPropertyStr(ctx, arr, "length"); ++ if (JS_IsException(len_val)) ++ return -1; ++ ++ if (JS_ToUint32(ctx, &len32, len_val)) { ++ JS_FreeValue(ctx, len_val); ++ return -1; ++ } ++ ++ JS_FreeValue(ctx, len_val); ++ *out_len = (size_t)len32; ++ ret = 0; ++ return ret; ++} ++ ++static int js_host_validate_schema(JSContext *ctx, ++ JSValueConst schema_val, ++ const char *path, ++ JSHostSchemaType *out) ++{ ++ const char *required[] = {"type"}; ++ JSValue type_val = JS_UNDEFINED; ++ const char *type_str; ++ int ret = -1; ++ ++ if (js_host_expect_object(ctx, schema_val, path)) ++ return -1; ++ ++ if (js_host_check_keys(ctx, schema_val, required, 1, NULL, 0, path)) ++ return -1; ++ ++ type_val = JS_GetPropertyStr(ctx, schema_val, "type"); ++ if (JS_IsException(type_val)) ++ goto done; ++ ++ if (!JS_IsString(type_val)) { ++ js_host_manifest_error(ctx, path, "schema.type must be a string"); ++ goto done; ++ } ++ ++ type_str = JS_ToCString(ctx, type_val); ++ if (!type_str) ++ goto done; ++ ++ if (strcmp(type_str, "string") == 0) { ++ *out = JS_HOST_SCHEMA_STRING; ++ } else if (strcmp(type_str, "dv") == 0) { ++ *out = JS_HOST_SCHEMA_DV; ++ } else if (strcmp(type_str, "null") == 0) { ++ *out = JS_HOST_SCHEMA_NULL; ++ } else { ++ js_host_manifest_error(ctx, path, "unsupported schema type"); ++ JS_FreeCString(ctx, type_str); ++ goto done; ++ } ++ ++ JS_FreeCString(ctx, type_str); ++ ret = 0; ++ ++done: ++ if (!JS_IsUndefined(type_val)) ++ JS_FreeValue(ctx, type_val); ++ return ret; ++} ++ ++static int js_host_validate_js_path(JSContext *ctx, ++ JSValueConst path_val, ++ const char *path_desc, ++ JSHostFunctionDef *out_fn) ++{ ++ size_t len = 0; ++ char **segments = NULL; ++ JSValue entry = JS_UNDEFINED; ++ int ret = -1; ++ ++ if (!JS_IsArray(ctx, path_val)) ++ return js_host_manifest_error(ctx, path_desc, "js_path must be an array"); ++ ++ if (js_host_array_length(ctx, path_val, &len)) ++ return -1; ++ ++ if (len == 0) ++ return js_host_manifest_error(ctx, path_desc, "js_path must contain at least one segment"); ++ ++ segments = js_malloc(ctx, sizeof(char *) * len); ++ if (!segments) ++ return -1; ++ memset(segments, 0, sizeof(char *) * len); ++ ++ for (size_t i = 0; i < len; i++) { ++ char key_buf[64]; ++ snprintf(key_buf, sizeof(key_buf), "%s[%zu]", path_desc, i); ++ ++ entry = JS_GetPropertyUint32(ctx, path_val, (uint32_t)i); ++ if (JS_IsException(entry)) ++ goto cleanup; ++ ++ if (js_host_copy_non_empty_string(ctx, entry, key_buf, &segments[i])) ++ goto cleanup; ++ ++ JS_FreeValue(ctx, entry); ++ entry = JS_UNDEFINED; ++ ++ const char *seg = segments[i]; ++ for (const char *p = seg; *p; p++) { ++ char c = *p; ++ if (!((c >= 'A' && c <= 'Z') || ++ (c >= 'a' && c <= 'z') || ++ (c >= '0' && c <= '9') || ++ c == '_' || c == '-')) { ++ js_host_manifest_error(ctx, key_buf, "js_path segment must match [A-Za-z0-9_-]+"); ++ goto cleanup; ++ } ++ } ++ ++ if (strcmp(seg, "__proto__") == 0 || strcmp(seg, "prototype") == 0 || strcmp(seg, "constructor") == 0) { ++ js_host_manifest_error(ctx, key_buf, "js_path segment is forbidden"); ++ goto cleanup; ++ } ++ } ++ ++ out_fn->path_segments = segments; ++ out_fn->path_len = len; ++ ret = 0; ++ ++cleanup: ++ if (ret != 0 && segments) { ++ for (size_t i = 0; i < len; i++) { ++ if (segments[i]) ++ js_free(ctx, segments[i]); ++ } ++ js_free(ctx, segments); ++ } ++ if (!JS_IsUndefined(entry)) ++ JS_FreeValue(ctx, entry); ++ return ret; ++} ++ ++static int js_host_validate_error_codes(JSContext *ctx, ++ JSValueConst errors_val, ++ const char *path, ++ JSHostFunctionDef *out_fn) ++{ ++ JSValue entry = JS_UNDEFINED; ++ JSValue code_val = JS_UNDEFINED; ++ JSValue tag_val = JS_UNDEFINED; ++ char *code_str = NULL; ++ char *tag_str = NULL; ++ int ret = -1; ++ ++ if (!JS_IsArray(ctx, errors_val)) ++ return js_host_manifest_error(ctx, path, "error_codes must be an array"); ++ ++ if (js_host_array_length(ctx, errors_val, &out_fn->error_count)) ++ return -1; ++ ++ if (out_fn->error_count == 0) { ++ out_fn->errors = NULL; ++ return 0; ++ } ++ ++ out_fn->errors = js_malloc(ctx, sizeof(JSHostErrorEntry) * out_fn->error_count); ++ if (!out_fn->errors) ++ return -1; ++ memset(out_fn->errors, 0, sizeof(JSHostErrorEntry) * out_fn->error_count); ++ ++ for (size_t i = 0; i < out_fn->error_count; i++) { ++ char entry_path[96]; ++ snprintf(entry_path, sizeof(entry_path), "%s[%zu]", path, i); ++ ++ entry = JS_GetPropertyUint32(ctx, errors_val, (uint32_t)i); ++ if (JS_IsException(entry)) ++ goto cleanup; ++ ++ const char *required[] = {"code", "tag"}; ++ if (js_host_expect_object(ctx, entry, entry_path) || ++ js_host_check_keys(ctx, entry, required, 2, NULL, 0, entry_path)) ++ goto cleanup; ++ ++ code_val = JS_GetPropertyStr(ctx, entry, "code"); ++ if (JS_IsException(code_val)) ++ goto cleanup; ++ if (js_host_copy_non_empty_string(ctx, code_val, entry_path, &code_str)) ++ goto cleanup; ++ ++ tag_val = JS_GetPropertyStr(ctx, entry, "tag"); ++ if (JS_IsException(tag_val)) ++ goto cleanup; ++ if (js_host_copy_non_empty_string(ctx, tag_val, entry_path, &tag_str)) ++ goto cleanup; ++ ++ if (strcmp(code_str, JS_HOST_ERROR_CODE_TRANSPORT) == 0 || ++ strcmp(code_str, JS_HOST_ERROR_CODE_ENVELOPE_INVALID) == 0) { ++ js_host_manifest_error(ctx, entry_path, "reserved error code"); ++ goto cleanup; ++ } ++ ++ if (i > 0) { ++ JSAtom prev_atom = out_fn->errors[i - 1].code_atom; ++ const char *prev = JS_AtomToCString(ctx, prev_atom); ++ if (!prev) ++ goto cleanup; ++ int cmp = strcmp(prev, code_str); ++ JS_FreeCString(ctx, prev); ++ if (cmp >= 0) { ++ js_host_manifest_error(ctx, path, "error_codes must be sorted and unique"); ++ goto cleanup; ++ } ++ } ++ ++ out_fn->errors[i].code_atom = JS_NewAtom(ctx, code_str); ++ out_fn->errors[i].tag_atom = JS_NewAtom(ctx, tag_str); ++ if (out_fn->errors[i].code_atom == JS_ATOM_NULL || ++ out_fn->errors[i].tag_atom == JS_ATOM_NULL) ++ goto cleanup; ++ ++ js_free(ctx, code_str); ++ js_free(ctx, tag_str); ++ code_str = NULL; ++ tag_str = NULL; ++ ++ JS_FreeValue(ctx, entry); ++ JS_FreeValue(ctx, code_val); ++ JS_FreeValue(ctx, tag_val); ++ entry = code_val = tag_val = JS_UNDEFINED; ++ } ++ ++ ret = 0; ++ ++cleanup: ++ if (code_str) ++ js_free(ctx, code_str); ++ if (tag_str) ++ js_free(ctx, tag_str); ++ if (!JS_IsUndefined(entry)) ++ JS_FreeValue(ctx, entry); ++ if (!JS_IsUndefined(code_val)) ++ JS_FreeValue(ctx, code_val); ++ if (!JS_IsUndefined(tag_val)) ++ JS_FreeValue(ctx, tag_val); ++ if (ret != 0 && out_fn->errors) { ++ for (size_t i = 0; i < out_fn->error_count; i++) { ++ if (out_fn->errors[i].code_atom != JS_ATOM_NULL) ++ JS_FreeAtom(ctx, out_fn->errors[i].code_atom); ++ if (out_fn->errors[i].tag_atom != JS_ATOM_NULL) ++ JS_FreeAtom(ctx, out_fn->errors[i].tag_atom); ++ } ++ js_free(ctx, out_fn->errors); ++ out_fn->errors = NULL; ++ } ++ return ret; ++} ++ ++static int js_host_validate_limits(JSContext *ctx, ++ JSValueConst limits_val, ++ const char *path, ++ JSHostFunctionDef *out_fn) ++{ ++ const char *required[] = {"max_request_bytes", "max_response_bytes", "max_units"}; ++ const char *optional[] = {"arg_utf8_max"}; ++ JSValue max_req = JS_UNDEFINED; ++ JSValue max_resp = JS_UNDEFINED; ++ JSValue max_units = JS_UNDEFINED; ++ JSValue arg_utf8 = JS_UNDEFINED; ++ int ret = -1; ++ ++ if (js_host_expect_object(ctx, limits_val, path)) ++ return -1; ++ ++ if (js_host_check_keys(ctx, limits_val, required, 3, optional, 1, path)) ++ return -1; ++ ++ max_req = JS_GetPropertyStr(ctx, limits_val, "max_request_bytes"); ++ if (JS_IsException(max_req)) ++ goto done; ++ if (js_host_validate_uint32(ctx, max_req, path, 1, JS_DV_LIMIT_DEFAULTS.max_encoded_bytes, &out_fn->max_request_bytes)) ++ goto done; ++ ++ max_resp = JS_GetPropertyStr(ctx, limits_val, "max_response_bytes"); ++ if (JS_IsException(max_resp)) ++ goto done; ++ if (js_host_validate_uint32(ctx, max_resp, path, 1, JS_DV_LIMIT_DEFAULTS.max_encoded_bytes, &out_fn->max_response_bytes)) ++ goto done; ++ ++ max_units = JS_GetPropertyStr(ctx, limits_val, "max_units"); ++ if (JS_IsException(max_units)) ++ goto done; ++ if (js_host_validate_uint32(ctx, max_units, path, 0, UINT32_MAX, &out_fn->max_units)) ++ goto done; ++ ++ arg_utf8 = JS_GetPropertyStr(ctx, limits_val, "arg_utf8_max"); ++ if (JS_IsException(arg_utf8)) ++ goto done; ++ ++ if (!JS_IsUndefined(arg_utf8)) { ++ size_t len = 0; ++ if (!JS_IsArray(ctx, arg_utf8)) { ++ js_host_manifest_error(ctx, path, "arg_utf8_max must be an array when present"); ++ goto done; ++ } ++ if (js_host_array_length(ctx, arg_utf8, &len)) ++ goto done; ++ if (len != out_fn->arity) { ++ js_host_manifest_error(ctx, path, "arg_utf8_max length must equal arity"); ++ goto done; ++ } ++ ++ for (size_t i = 0; i < out_fn->arity; i++) { ++ JSValue limit_val = JS_GetPropertyUint32(ctx, arg_utf8, (uint32_t)i); ++ if (JS_IsException(limit_val)) ++ goto done; ++ uint32_t utf8_limit = 0; ++ char idx_path[96]; ++ snprintf(idx_path, sizeof(idx_path), "%s[%zu]", path, i); ++ ++ if (js_host_validate_uint32(ctx, ++ limit_val, ++ idx_path, ++ 1, ++ JS_DV_LIMIT_DEFAULTS.max_string_bytes, ++ &utf8_limit)) { ++ JS_FreeValue(ctx, limit_val); ++ goto done; ++ } ++ ++ JS_FreeValue(ctx, limit_val); ++ ++ if (out_fn->args[i].type != JS_HOST_SCHEMA_STRING) { ++ js_host_manifest_error(ctx, path, "arg_utf8_max may only be used with string arguments"); ++ goto done; ++ } ++ out_fn->args[i].utf8_max = utf8_limit; ++ } ++ } ++ ++ ret = 0; ++ ++done: ++ if (!JS_IsUndefined(max_req)) ++ JS_FreeValue(ctx, max_req); ++ if (!JS_IsUndefined(max_resp)) ++ JS_FreeValue(ctx, max_resp); ++ if (!JS_IsUndefined(max_units)) ++ JS_FreeValue(ctx, max_units); ++ if (!JS_IsUndefined(arg_utf8)) ++ JS_FreeValue(ctx, arg_utf8); ++ return ret; ++} ++ ++static int js_host_build_function_name(JSContext *ctx, JSHostFunctionDef *fn) ++{ ++ const char *prefix = "Host.v1"; ++ size_t total = strlen(prefix) + 1; /* null terminator */ ++ ++ for (size_t i = 0; i < fn->path_len; i++) ++ total += 1 + strlen(fn->path_segments[i]); /* dot + segment */ ++ ++ fn->name = js_malloc(ctx, total); ++ if (!fn->name) ++ return -1; ++ ++ strcpy(fn->name, prefix); ++ for (size_t i = 0; i < fn->path_len; i++) { ++ strcat(fn->name, "."); ++ strcat(fn->name, fn->path_segments[i]); ++ } ++ return 0; ++} ++ ++static int js_host_validate_function(JSContext *ctx, ++ JSValueConst fn_val, ++ const char *path, ++ JSHostFunctionDef *out_fn) ++{ ++ const char *required[] = {"fn_id", "js_path", "effect", "arity", "arg_schema", "return_schema", "gas", "limits", "error_codes"}; ++ JSValue fn_id = JS_UNDEFINED; ++ JSValue js_path = JS_UNDEFINED; ++ JSValue effect = JS_UNDEFINED; ++ JSValue arity = JS_UNDEFINED; ++ JSValue arg_schema = JS_UNDEFINED; ++ JSValue return_schema = JS_UNDEFINED; ++ JSValue gas = JS_UNDEFINED; ++ JSValue limits = JS_UNDEFINED; ++ JSValue error_codes = JS_UNDEFINED; ++ const char *eff_str = NULL; ++ char *schedule_id_str = NULL; ++ int ret = -1; ++ ++ if (js_host_expect_object(ctx, fn_val, path)) ++ return -1; ++ ++ if (js_host_check_keys(ctx, fn_val, required, sizeof(required) / sizeof(required[0]), NULL, 0, path)) ++ return -1; ++ ++ fn_id = JS_GetPropertyStr(ctx, fn_val, "fn_id"); ++ if (JS_IsException(fn_id)) ++ goto done; ++ if (js_host_validate_uint32(ctx, fn_id, path, 1, UINT32_MAX, &out_fn->fn_id)) ++ goto done; ++ ++ js_path = JS_GetPropertyStr(ctx, fn_val, "js_path"); ++ if (JS_IsException(js_path)) ++ goto done; ++ if (js_host_validate_js_path(ctx, js_path, "js_path", out_fn)) ++ goto done; ++ ++ effect = JS_GetPropertyStr(ctx, fn_val, "effect"); ++ if (JS_IsException(effect)) ++ goto done; ++ if (!JS_IsString(effect)) { ++ js_host_manifest_error(ctx, path, "effect must be a string"); ++ goto done; ++ } ++ eff_str = JS_ToCString(ctx, effect); ++ if (!eff_str) ++ goto done; ++ if (strcmp(eff_str, "READ") == 0) { ++ out_fn->effect = JS_HOST_EFFECT_READ; ++ } else if (strcmp(eff_str, "EMIT") == 0) { ++ out_fn->effect = JS_HOST_EFFECT_EMIT; ++ } else if (strcmp(eff_str, "MUTATE") == 0) { ++ out_fn->effect = JS_HOST_EFFECT_MUTATE; ++ } else { ++ js_host_manifest_error(ctx, path, "unsupported effect"); ++ goto done; ++ } ++ JS_FreeCString(ctx, eff_str); ++ eff_str = NULL; ++ ++ arity = JS_GetPropertyStr(ctx, fn_val, "arity"); ++ if (JS_IsException(arity)) ++ goto done; ++ if (js_host_validate_uint32(ctx, arity, path, 0, UINT32_MAX, &out_fn->arity)) ++ goto done; ++ ++ arg_schema = JS_GetPropertyStr(ctx, fn_val, "arg_schema"); ++ if (JS_IsException(arg_schema)) ++ goto done; ++ if (!JS_IsArray(ctx, arg_schema)) { ++ js_host_manifest_error(ctx, path, "arg_schema must be an array"); ++ goto done; ++ } ++ ++ size_t arg_len = 0; ++ if (js_host_array_length(ctx, arg_schema, &arg_len)) ++ goto done; ++ if (arg_len != out_fn->arity) { ++ js_host_manifest_error(ctx, path, "arg_schema length must equal arity"); ++ goto done; ++ } ++ ++ if (out_fn->arity > 0) { ++ out_fn->args = js_malloc(ctx, sizeof(JSHostArgDef) * out_fn->arity); ++ if (!out_fn->args) ++ goto done; ++ memset(out_fn->args, 0, sizeof(JSHostArgDef) * out_fn->arity); ++ } ++ ++ for (size_t i = 0; i < out_fn->arity; i++) { ++ JSValue schema_entry = JS_GetPropertyUint32(ctx, arg_schema, (uint32_t)i); ++ if (JS_IsException(schema_entry)) ++ goto done; ++ char schema_path[96]; ++ snprintf(schema_path, sizeof(schema_path), "arg_schema[%zu]", i); ++ if (js_host_validate_schema(ctx, schema_entry, schema_path, &out_fn->args[i].type)) { ++ JS_FreeValue(ctx, schema_entry); ++ goto done; ++ } ++ JS_FreeValue(ctx, schema_entry); ++ } ++ ++ return_schema = JS_GetPropertyStr(ctx, fn_val, "return_schema"); ++ if (JS_IsException(return_schema)) ++ goto done; ++ if (js_host_validate_schema(ctx, return_schema, "return_schema", &out_fn->return_type)) ++ goto done; ++ ++ gas = JS_GetPropertyStr(ctx, fn_val, "gas"); ++ if (JS_IsException(gas)) ++ goto done; ++ const char *gas_required[] = {"schedule_id", "base", "k_arg_bytes", "k_ret_bytes", "k_units"}; ++ if (js_host_expect_object(ctx, gas, "gas") || ++ js_host_check_keys(ctx, gas, gas_required, 5, NULL, 0, "gas")) ++ goto done; ++ ++ JSValue base = JS_GetPropertyStr(ctx, gas, "base"); ++ JSValue k_arg = JS_GetPropertyStr(ctx, gas, "k_arg_bytes"); ++ JSValue k_ret = JS_GetPropertyStr(ctx, gas, "k_ret_bytes"); ++ JSValue k_units = JS_GetPropertyStr(ctx, gas, "k_units"); ++ JSValue schedule_id = JS_GetPropertyStr(ctx, gas, "schedule_id"); ++ if (JS_IsException(base) || JS_IsException(k_arg) || JS_IsException(k_ret) || ++ JS_IsException(k_units) || JS_IsException(schedule_id)) { ++ JS_FreeValue(ctx, base); ++ JS_FreeValue(ctx, k_arg); ++ JS_FreeValue(ctx, k_ret); ++ JS_FreeValue(ctx, k_units); ++ JS_FreeValue(ctx, schedule_id); ++ goto done; ++ } ++ ++ if (js_host_validate_uint32(ctx, base, "gas.base", 0, UINT32_MAX, &out_fn->gas_base) || ++ js_host_validate_uint32(ctx, k_arg, "gas.k_arg_bytes", 0, UINT32_MAX, &out_fn->gas_k_arg_bytes) || ++ js_host_validate_uint32(ctx, k_ret, "gas.k_ret_bytes", 0, UINT32_MAX, &out_fn->gas_k_ret_bytes) || ++ js_host_validate_uint32(ctx, k_units, "gas.k_units", 0, UINT32_MAX, &out_fn->gas_k_units) || ++ js_host_copy_non_empty_string(ctx, schedule_id, "gas.schedule_id", &schedule_id_str)) { ++ JS_FreeValue(ctx, base); ++ JS_FreeValue(ctx, k_arg); ++ JS_FreeValue(ctx, k_ret); ++ JS_FreeValue(ctx, k_units); ++ JS_FreeValue(ctx, schedule_id); ++ goto done; ++ } ++ out_fn->gas_schedule_id = schedule_id_str; ++ schedule_id_str = NULL; ++ ++ JS_FreeValue(ctx, base); ++ JS_FreeValue(ctx, k_arg); ++ JS_FreeValue(ctx, k_ret); ++ JS_FreeValue(ctx, k_units); ++ JS_FreeValue(ctx, schedule_id); ++ ++ limits = JS_GetPropertyStr(ctx, fn_val, "limits"); ++ if (JS_IsException(limits)) ++ goto done; ++ if (js_host_validate_limits(ctx, limits, "limits", out_fn)) ++ goto done; ++ ++ error_codes = JS_GetPropertyStr(ctx, fn_val, "error_codes"); ++ if (JS_IsException(error_codes)) ++ goto done; ++ if (js_host_validate_error_codes(ctx, error_codes, "error_codes", out_fn)) ++ goto done; ++ ++ /* Gas overflow guard: base + (req * k_arg) + (resp * k_ret) + (units * k_units) */ ++ { ++ uint64_t total = out_fn->gas_base; ++ uint64_t arg_part = (uint64_t)out_fn->gas_k_arg_bytes * (uint64_t)out_fn->max_request_bytes; ++ uint64_t ret_part = (uint64_t)out_fn->gas_k_ret_bytes * (uint64_t)out_fn->max_response_bytes; ++ uint64_t unit_part = (uint64_t)out_fn->gas_k_units * (uint64_t)out_fn->max_units; ++ ++ if (arg_part > UINT64_MAX - total || ++ ret_part > UINT64_MAX - total - arg_part || ++ unit_part > UINT64_MAX - total - arg_part - ret_part) { ++ js_host_manifest_error(ctx, "gas", "gas charges overflow uint64 bounds"); ++ goto done; ++ } ++ } ++ ++ if (js_host_build_function_name(ctx, out_fn)) ++ goto done; ++ ++ ret = 0; ++ ++done: ++ if (!JS_IsUndefined(fn_id)) ++ JS_FreeValue(ctx, fn_id); ++ if (!JS_IsUndefined(js_path)) ++ JS_FreeValue(ctx, js_path); ++ if (!JS_IsUndefined(effect)) ++ JS_FreeValue(ctx, effect); ++ if (!JS_IsUndefined(arity)) ++ JS_FreeValue(ctx, arity); ++ if (!JS_IsUndefined(arg_schema)) ++ JS_FreeValue(ctx, arg_schema); ++ if (!JS_IsUndefined(return_schema)) ++ JS_FreeValue(ctx, return_schema); ++ if (!JS_IsUndefined(gas)) ++ JS_FreeValue(ctx, gas); ++ if (!JS_IsUndefined(limits)) ++ JS_FreeValue(ctx, limits); ++ if (!JS_IsUndefined(error_codes)) ++ JS_FreeValue(ctx, error_codes); ++ if (eff_str) ++ JS_FreeCString(ctx, eff_str); ++ if (schedule_id_str) ++ js_free(ctx, schedule_id_str); ++ ++ if (ret != 0) { ++ if (out_fn->name) { ++ js_free(ctx, out_fn->name); ++ out_fn->name = NULL; ++ } ++ } ++ return ret; ++} ++ ++static BOOL js_host_paths_conflict(const JSHostFunctionDef *a, const JSHostFunctionDef *b) ++{ ++ size_t len = a->path_len < b->path_len ? a->path_len : b->path_len; ++ for (size_t i = 0; i < len; i++) { ++ if (strcmp(a->path_segments[i], b->path_segments[i]) != 0) ++ return FALSE; ++ } ++ return TRUE; ++} ++ ++static int js_host_validate_manifest(JSContext *ctx, JSValueConst manifest_val, JSHostManifest *out_manifest) ++{ ++ const char *required[] = {"abi_id", "abi_version", "functions"}; ++ JSValue abi_id = JS_UNDEFINED; ++ JSValue abi_version = JS_UNDEFINED; ++ JSValue functions = JS_UNDEFINED; ++ char *abi_id_str = NULL; ++ int ret = -1; ++ ++ if (js_host_expect_object(ctx, manifest_val, "manifest")) ++ return -1; ++ ++ if (js_host_check_keys(ctx, manifest_val, required, 3, NULL, 0, "manifest")) ++ return -1; ++ ++ abi_id = JS_GetPropertyStr(ctx, manifest_val, "abi_id"); ++ if (JS_IsException(abi_id)) ++ goto done; ++ if (js_host_copy_non_empty_string(ctx, abi_id, "manifest.abi_id", &abi_id_str)) ++ goto done; ++ if (strcmp(abi_id_str, "Host.v1") != 0) { ++ js_host_manifest_error(ctx, "manifest.abi_id", "unsupported abi_id (expected Host.v1)"); ++ goto done; ++ } ++ ++ abi_version = JS_GetPropertyStr(ctx, manifest_val, "abi_version"); ++ if (JS_IsException(abi_version)) ++ goto done; ++ uint32_t version = 0; ++ if (js_host_validate_uint32(ctx, abi_version, "manifest.abi_version", 1, UINT32_MAX, &version)) ++ goto done; ++ if (version != 1) { ++ js_host_manifest_error(ctx, "manifest.abi_version", "unsupported abi_version (expected 1)"); ++ goto done; ++ } ++ ++ functions = JS_GetPropertyStr(ctx, manifest_val, "functions"); ++ if (JS_IsException(functions)) ++ goto done; ++ if (!JS_IsArray(ctx, functions)) { ++ js_host_manifest_error(ctx, "manifest.functions", "functions must be an array"); ++ goto done; ++ } ++ ++ if (js_host_array_length(ctx, functions, &out_manifest->function_count)) ++ goto done; ++ if (out_manifest->function_count == 0) { ++ js_host_manifest_error(ctx, "manifest.functions", "functions must contain at least one entry"); ++ goto done; ++ } ++ ++ out_manifest->functions = js_malloc(ctx, sizeof(JSHostFunctionDef) * out_manifest->function_count); ++ if (!out_manifest->functions) ++ goto done; ++ memset(out_manifest->functions, 0, sizeof(JSHostFunctionDef) * out_manifest->function_count); ++ ++ uint32_t prev_fn_id = 0; ++ for (size_t i = 0; i < out_manifest->function_count; i++) { ++ JSValue fn_val = JS_GetPropertyUint32(ctx, functions, (uint32_t)i); ++ if (JS_IsException(fn_val)) ++ goto done; ++ ++ char fn_path[96]; ++ snprintf(fn_path, sizeof(fn_path), "manifest.functions[%zu]", i); ++ ++ if (js_host_validate_function(ctx, fn_val, fn_path, &out_manifest->functions[i])) { ++ JS_FreeValue(ctx, fn_val); ++ goto done; ++ } ++ ++ JS_FreeValue(ctx, fn_val); ++ ++ if (i > 0 && out_manifest->functions[i].fn_id <= prev_fn_id) { ++ js_host_manifest_error(ctx, "manifest.functions", "functions must be sorted by ascending fn_id"); ++ goto done; ++ } ++ prev_fn_id = out_manifest->functions[i].fn_id; ++ } ++ ++ for (size_t i = 0; i < out_manifest->function_count; i++) { ++ for (size_t j = i + 1; j < out_manifest->function_count; j++) { ++ if (js_host_paths_conflict(&out_manifest->functions[i], &out_manifest->functions[j])) { ++ js_host_manifest_error(ctx, "manifest.functions", "js_path collision detected"); ++ goto done; ++ } ++ } ++ } ++ ++ ret = 0; ++ ++done: ++ if (abi_id_str) ++ js_free(ctx, abi_id_str); ++ if (!JS_IsUndefined(abi_id)) ++ JS_FreeValue(ctx, abi_id); ++ if (!JS_IsUndefined(abi_version)) ++ JS_FreeValue(ctx, abi_version); ++ if (!JS_IsUndefined(functions)) ++ JS_FreeValue(ctx, functions); ++ ++ if (ret != 0) ++ js_host_manifest_clear(ctx, out_manifest); ++ return ret; ++} ++ ++static int js_host_namespace_push(JSContext *ctx, ++ JSValue ns, ++ JSValue **out, ++ size_t *count, ++ size_t *capacity) ++{ ++ void *ptr = JS_VALUE_GET_PTR(ns); ++ for (size_t i = 0; i < *count; i++) { ++ if (JS_VALUE_GET_PTR((*out)[i]) == ptr) ++ return 0; ++ } ++ ++ if (*count >= *capacity) { ++ size_t new_cap = (*capacity == 0) ? 8 : (*capacity * 2); ++ JSValue *resized = js_realloc(ctx, *out, sizeof(JSValue) * new_cap); ++ if (!resized) ++ return -1; ++ *out = resized; ++ *capacity = new_cap; ++ } ++ ++ (*out)[*count] = JS_DupValue(ctx, ns); ++ (*count)++; ++ return 0; ++} ++ ++static int js_host_get_or_create_child(JSContext *ctx, ++ JSValue parent, ++ const char *name, ++ JSValue *out_child, ++ JSValue **namespaces, ++ size_t *ns_count, ++ size_t *ns_capacity) ++{ ++ JSValue child = JS_UNDEFINED; ++ JSAtom atom = JS_NewAtom(ctx, name); ++ int ret = -1; ++ ++ if (atom == JS_ATOM_NULL) ++ return -1; ++ ++ child = JS_GetProperty(ctx, parent, atom); ++ if (JS_IsException(child)) ++ goto done; ++ ++ if (JS_IsUndefined(child)) { ++ child = JS_NewObjectProto(ctx, JS_NULL); ++ if (JS_IsException(child)) ++ goto done; ++ if (JS_DefinePropertyValue(ctx, ++ parent, ++ atom, ++ JS_DupValue(ctx, child), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE) < 0) ++ goto done; ++ } else if (!JS_IsObject(child)) { ++ js_host_manifest_error(ctx, name, "Host namespace collision"); ++ goto done; ++ } ++ ++ if (js_host_namespace_push(ctx, child, namespaces, ns_count, ns_capacity)) ++ goto done; ++ ++ *out_child = child; ++ child = JS_UNDEFINED; ++ ret = 0; ++ ++done: ++ if (atom != JS_ATOM_NULL) ++ JS_FreeAtom(ctx, atom); ++ if (!JS_IsUndefined(child)) ++ JS_FreeValue(ctx, child); ++ return ret; ++} ++ ++static int js_host_charge_pre(JSContext *ctx, const JSHostFunctionDef *fn, size_t req_len) ++{ ++ uint64_t charge = fn->gas_base; ++ uint64_t arg_part = (uint64_t)fn->gas_k_arg_bytes * (uint64_t)req_len; ++ ++ if (arg_part > UINT64_MAX - charge) { ++ JS_ThrowTypeError(ctx, "host_call gas overflow"); ++ return -1; ++ } ++ ++ charge += arg_part; ++ return JS_UseGas(ctx, charge); ++} ++ ++static int js_host_charge_post(JSContext *ctx, const JSHostFunctionDef *fn, size_t resp_len, uint32_t units) ++{ ++ uint64_t charge = 0; ++ uint64_t resp_part = (uint64_t)fn->gas_k_ret_bytes * (uint64_t)resp_len; ++ uint64_t unit_part = (uint64_t)fn->gas_k_units * (uint64_t)units; ++ ++ if (resp_part > UINT64_MAX - charge || unit_part > UINT64_MAX - charge - resp_part) { ++ JS_ThrowTypeError(ctx, "host_call gas overflow"); ++ return -1; ++ } ++ ++ charge += resp_part + unit_part; ++ return JS_UseGas(ctx, charge); ++} ++ ++static JSValue js_host_call_wrapper(JSContext *ctx, ++ JSValueConst this_val, ++ int argc, ++ JSValueConst *argv, ++ int magic) ++{ ++ JSHostManifest *manifest = js_host_find_manifest(ctx); ++ JSDvBuffer req_buf = {0}; ++ JSValue args_array = JS_UNDEFINED; ++ JSHostResponse resp; ++ JSHostCallResult result = {0}; ++ JSValue ret = JS_EXCEPTION; ++ ++ if (!manifest) { ++ JS_ThrowTypeError(ctx, "host manifest is not initialized"); ++ return JS_EXCEPTION; ++ } ++ ++ if (magic < 0 || (size_t)magic >= manifest->function_count) { ++ JS_ThrowTypeError(ctx, "invalid host function binding"); ++ return JS_EXCEPTION; ++ } ++ ++ const JSHostFunctionDef *fn = &manifest->functions[magic]; ++ ++ if (argc != (int)fn->arity) { ++ JS_ThrowTypeError(ctx, "%s expects %u arguments", fn->name ? fn->name : "Host function", fn->arity); ++ return JS_EXCEPTION; ++ } ++ ++ for (size_t i = 0; i < fn->arity; i++) { ++ const JSHostArgDef *arg = &fn->args[i]; ++ JSValueConst val = argv[i]; ++ ++ switch (arg->type) { ++ case JS_HOST_SCHEMA_STRING: { ++ if (!JS_IsString(val)) { ++ JS_ThrowTypeError(ctx, "%s argument %zu must be a string", fn->name ? fn->name : "Host function", i + 1); ++ return JS_EXCEPTION; ++ } ++ if (arg->utf8_max > 0) { ++ size_t utf8_len = 0; ++ const char *str = JS_ToCStringLen2(ctx, &utf8_len, val, 0); ++ if (!str) ++ return JS_EXCEPTION; ++ JS_FreeCString(ctx, str); ++ if (utf8_len > arg->utf8_max) { ++ JS_ThrowTypeError(ctx, ++ "%s argument %zu exceeds utf8 limit (%zu > %u)", ++ fn->name ? fn->name : "Host function", ++ i + 1, ++ utf8_len, ++ arg->utf8_max); ++ return JS_EXCEPTION; ++ } ++ } ++ break; ++ } ++ case JS_HOST_SCHEMA_DV: ++ break; ++ case JS_HOST_SCHEMA_NULL: ++ if (!JS_IsNull(val)) { ++ JS_ThrowTypeError(ctx, "%s argument %zu must be null", fn->name ? fn->name : "Host function", i + 1); ++ return JS_EXCEPTION; ++ } ++ break; ++ } ++ } ++ ++ if (JS_RunGCCheckpoint(ctx)) ++ return JS_EXCEPTION; ++ ++ args_array = JS_NewArray(ctx); ++ if (JS_IsException(args_array)) ++ return JS_EXCEPTION; ++ ++ for (size_t i = 0; i < fn->arity; i++) { ++ if (JS_SetPropertyUint32(ctx, args_array, (uint32_t)i, JS_DupValue(ctx, argv[i])) < 0) { ++ JS_FreeValue(ctx, args_array); ++ return JS_EXCEPTION; ++ } ++ } ++ ++ JSDvLimits dv_limits = JS_DV_LIMIT_DEFAULTS; ++ dv_limits.max_encoded_bytes = fn->max_request_bytes; ++ ++ if (JS_EncodeDV(ctx, args_array, &dv_limits, &req_buf)) { ++ JS_FreeValue(ctx, args_array); ++ JS_FreeDVBuffer(ctx, &req_buf); ++ return JS_EXCEPTION; ++ } ++ ++ JS_FreeValue(ctx, args_array); ++ args_array = JS_UNDEFINED; ++ ++ if (js_host_charge_pre(ctx, fn, req_buf.length)) { ++ JS_FreeDVBuffer(ctx, &req_buf); ++ return JS_EXCEPTION; ++ } ++ ++ if (JS_RunGCCheckpoint(ctx)) { ++ JS_FreeDVBuffer(ctx, &req_buf); ++ return JS_EXCEPTION; ++ } ++ ++ if (JS_HostCall(ctx, ++ fn->fn_id, ++ req_buf.data, ++ req_buf.length, ++ fn->max_request_bytes, ++ fn->max_response_bytes, ++ &result)) { ++ JS_FreeDVBuffer(ctx, &req_buf); ++ return JS_EXCEPTION; ++ } ++ ++ JS_FreeDVBuffer(ctx, &req_buf); ++ ++ JSHostResponseValidation validation = { ++ .max_units = fn->max_units, ++ .errors = fn->errors, ++ .error_count = fn->error_count, ++ }; ++ ++ if (JS_ParseHostResponse(ctx, result.data, result.length, &validation, &resp)) ++ return JS_EXCEPTION; ++ ++ if (js_host_charge_post(ctx, fn, result.length, resp.units)) { ++ JS_FreeHostResponse(ctx, &resp); ++ return JS_EXCEPTION; ++ } ++ ++ if (JS_RunGCCheckpoint(ctx)) { ++ JS_FreeHostResponse(ctx, &resp); ++ return JS_EXCEPTION; ++ } ++ ++ if (resp.is_error) { ++ ret = JS_ThrowHostError(ctx, resp.err_code_atom, resp.err_tag_atom, resp.err_details); ++ JS_FreeHostResponse(ctx, &resp); ++ return ret; ++ } ++ ++ switch (fn->return_type) { ++ case JS_HOST_SCHEMA_STRING: ++ if (!JS_IsString(resp.ok)) { ++ JS_FreeHostResponse(ctx, &resp); ++ return js_throw_host_envelope_invalid(ctx); ++ } ++ break; ++ case JS_HOST_SCHEMA_NULL: ++ if (!JS_IsNull(resp.ok)) { ++ JS_FreeHostResponse(ctx, &resp); ++ return js_throw_host_envelope_invalid(ctx); ++ } ++ break; ++ case JS_HOST_SCHEMA_DV: ++ break; ++ } ++ ++ ret = resp.ok; ++ resp.ok = JS_UNDEFINED; ++ JS_FreeHostResponse(ctx, &resp); ++ return ret; ++} ++ ++static int js_host_install_functions(JSContext *ctx, JSHostManifest *manifest) ++{ ++ JSValue global = JS_UNDEFINED; ++ JSValue host = JS_UNDEFINED; ++ JSValue host_v1 = JS_UNDEFINED; ++ JSValue *namespaces = NULL; ++ size_t ns_count = 0; ++ size_t ns_capacity = 0; ++ int ret = -1; ++ ++ global = JS_GetGlobalObject(ctx); ++ if (JS_IsException(global)) ++ goto done; ++ ++ if (js_host_get_or_create_child(ctx, global, "Host", &host, &namespaces, &ns_count, &ns_capacity)) ++ goto done; ++ ++ if (js_host_get_or_create_child(ctx, host, "v1", &host_v1, &namespaces, &ns_count, &ns_capacity)) ++ goto done; ++ ++ for (size_t i = 0; i < manifest->function_count; i++) { ++ JSValue current = JS_DupValue(ctx, host_v1); ++ if (JS_IsException(current)) ++ goto done; ++ ++ JSValue next = JS_UNDEFINED; ++ JSHostFunctionDef *fn = &manifest->functions[i]; ++ ++ for (size_t j = 0; j + 1 < fn->path_len; j++) { ++ if (js_host_get_or_create_child(ctx, ++ current, ++ fn->path_segments[j], ++ &next, ++ &namespaces, ++ &ns_count, ++ &ns_capacity)) { ++ JS_FreeValue(ctx, current); ++ goto done; ++ } ++ JS_FreeValue(ctx, current); ++ current = next; ++ next = JS_UNDEFINED; ++ } ++ ++ JSAtom fn_atom = JS_NewAtom(ctx, fn->path_segments[fn->path_len - 1]); ++ if (fn_atom == JS_ATOM_NULL) { ++ JS_FreeValue(ctx, current); ++ goto done; ++ } ++ ++ JSValue cfunc = JS_NewCFunctionMagic(ctx, ++ js_host_call_wrapper, ++ fn->path_segments[fn->path_len - 1], ++ fn->arity, ++ JS_CFUNC_generic_magic, ++ (int)i); ++ if (JS_IsException(cfunc)) { ++ JS_FreeAtom(ctx, fn_atom); ++ JS_FreeValue(ctx, current); ++ goto done; ++ } ++ ++ if (JS_DefinePropertyValue(ctx, ++ current, ++ fn_atom, ++ cfunc, ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE) < 0) { ++ JS_FreeAtom(ctx, fn_atom); ++ JS_FreeValue(ctx, current); ++ goto done; ++ } ++ ++ JS_FreeAtom(ctx, fn_atom); ++ JS_FreeValue(ctx, current); ++ } ++ ++ for (size_t i = 0; i < ns_count; i++) { ++ if (JS_PreventExtensions(ctx, namespaces[i]) < 0) ++ goto done; ++ } ++ ++ ret = 0; ++ ++done: ++ if (namespaces) { ++ for (size_t i = 0; i < ns_count; i++) ++ JS_FreeValue(ctx, namespaces[i]); ++ js_free(ctx, namespaces); ++ } ++ if (!JS_IsUndefined(host_v1)) ++ JS_FreeValue(ctx, host_v1); ++ if (!JS_IsUndefined(host)) ++ JS_FreeValue(ctx, host); ++ if (!JS_IsUndefined(global)) ++ JS_FreeValue(ctx, global); ++ return ret; ++} ++ ++int JS_InitHostFromManifest(JSContext *ctx, const uint8_t *manifest_bytes, size_t manifest_size) ++{ ++ JSValue manifest_val = JS_UNDEFINED; ++ JSHostManifest manifest = {0}; ++ JSHostManifestNode *node = NULL; ++ int ret = -1; ++ ++ if (!ctx || !manifest_bytes || manifest_size == 0) { ++ JS_ThrowTypeError(ctx, "abi manifest is required"); ++ return -1; ++ } ++ ++ if (js_host_find_manifest(ctx)) { ++ JS_ThrowTypeError(ctx, "abi manifest is already initialized"); ++ return -1; ++ } ++ ++ manifest_val = JS_DecodeDV(ctx, manifest_bytes, manifest_size, &JS_DV_LIMIT_DEFAULTS); ++ if (JS_IsException(manifest_val)) ++ return -1; ++ ++ if (js_host_validate_manifest(ctx, manifest_val, &manifest)) ++ goto done; ++ ++ node = js_malloc(ctx, sizeof(JSHostManifestNode)); ++ if (!node) ++ goto done; ++ ++ node->ctx = ctx; ++ node->manifest = manifest; ++ node->next = NULL; ++ memset(&manifest, 0, sizeof(manifest)); /* ownership moved */ ++ ++ if (js_host_install_functions(ctx, &node->manifest)) ++ goto done; ++ ++ node->next = js_host_manifest_list; ++ js_host_manifest_list = node; ++ node = NULL; ++ ++ ret = 0; ++ ++done: ++ if (!JS_IsUndefined(manifest_val)) ++ JS_FreeValue(ctx, manifest_val); ++ if (node) { ++ js_host_manifest_clear(ctx, &node->manifest); ++ js_free(ctx, node); ++ } else if (ret != 0) { ++ js_host_manifest_clear(ctx, &manifest); ++ } ++ return ret; ++} +diff --git a/quickjs-host.h b/quickjs-host.h +index 3ab2cbe..1f51f59 100644 +--- a/quickjs-host.h ++++ b/quickjs-host.h +@@ -23,6 +23,8 @@ typedef struct JSHostResponse { + JSValue err_details; + } JSHostResponse; + ++typedef struct JSHostManifest JSHostManifest; ++ + /* Host response envelope helpers (T-039). */ + JSValue JS_ThrowHostError(JSContext *ctx, JSAtom code_atom, JSAtom tag_atom, JSValueConst details); + JSValue JS_ThrowHostTransportError(JSContext *ctx); +@@ -32,5 +34,7 @@ int JS_ParseHostResponse(JSContext *ctx, + const JSHostResponseValidation *validation, + JSHostResponse *out); + void JS_FreeHostResponse(JSContext *ctx, JSHostResponse *resp); ++int JS_InitHostFromManifest(JSContext *ctx, const uint8_t *manifest_bytes, size_t manifest_size); ++void JS_FreeHostManifest(JSContext *ctx); + + #endif /* QUICKJS_HOST_H */ +diff --git a/quickjs.c b/quickjs.c +index 3cc7d35..8e44131 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -2889,9 +2889,6 @@ static int js_deterministic_init_host(JSContext *ctx) + if (ret < 0) + goto fail; + +- if (JS_PreventExtensions(ctx, host_v1) < 0 || JS_PreventExtensions(ctx, host_ns) < 0) +- goto fail; +- + JS_FreeValue(ctx, host_ns); + JS_FreeValue(ctx, host_v1); + +@@ -3127,6 +3124,13 @@ int JS_InitDeterministicContext(JSContext *ctx, const JSDeterministicInitOptions + memcpy(context_copy, options->context_blob, options->context_blob_size); + } + ++ if (JS_InitHostFromManifest(ctx, manifest_copy, options->manifest_size) != 0) { ++ js_free_rt(ctx->rt, manifest_copy); ++ if (context_copy) ++ js_free_rt(ctx->rt, context_copy); ++ return -1; ++ } ++ + memcpy(ctx->abi_manifest_hash, computed_hash, sizeof(computed_hash)); + js_sha256_to_hex(computed_hash, ctx->abi_manifest_hash_hex); + ctx->abi_manifest_bytes = manifest_copy; +@@ -3549,6 +3553,7 @@ void JS_FreeContext(JSContext *ctx) + } + #endif + ++ JS_FreeHostManifest(ctx); + js_free_modules(ctx, JS_FREE_MODULE_ALL); + + JS_FreeValue(ctx, ctx->global_obj); diff --git a/vendor/quickjs-patches/series/0018-feat-ergonomics-add-document-canon-event-globals-fro.patch b/vendor/quickjs-patches/series/0018-feat-ergonomics-add-document-canon-event-globals-fro.patch new file mode 100644 index 0000000..ce428a7 --- /dev/null +++ b/vendor/quickjs-patches/series/0018-feat-ergonomics-add-document-canon-event-globals-fro.patch @@ -0,0 +1,665 @@ +From b1a47dfde5b7d0195b393e3200c14890c6c15510 Mon Sep 17 00:00:00 2001 +From: Mateusz Jonak +Date: Tue, 16 Dec 2025 23:26:42 +0100 +Subject: [PATCH 18/51] feat(ergonomics): add document/canon/event globals from + Host.v1 + context blob (T-041) + +- add JS_InitErgonomicGlobals() to install: + - global document() wrapper + document.canonical() backed by Host.v1.document.{get,getCanonical} + - global canon.{unwrap,at} for canonical DV clone+freeze and safe path lookup + - global event/eventCanonical/steps decoded from context blob (deep-frozen) +- implement deep freeze utilities and canonical clone via DV roundtrip +- wire ergonomic globals init into JS_InitDeterministicContext when a context blob is provided + +Refs: T-041 +--- + quickjs-host.c | 605 +++++++++++++++++++++++++++++++++++++++++++++++++ + quickjs-host.h | 1 + + quickjs.c | 9 + + 3 files changed, 615 insertions(+) + +diff --git a/quickjs-host.c b/quickjs-host.c +index 0deeaa9..528e9c3 100644 +--- a/quickjs-host.c ++++ b/quickjs-host.c +@@ -1818,3 +1818,608 @@ done: + } + return ret; + } ++ ++/* Ergonomic globals (T-041) */ ++ ++static int js_freeze_value(JSContext *ctx, JSValueConst val) ++{ ++ JSPropertyEnum *props = NULL; ++ uint32_t props_len = 0; ++ int ret = -1; ++ ++ if (!JS_IsObject(val)) ++ return 0; ++ ++ if (JS_GetOwnPropertyNames(ctx, &props, &props_len, val, ++ JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY) < 0) ++ return -1; ++ ++ for (uint32_t i = 0; i < props_len; i++) { ++ JSAtom atom = props[i].atom; ++ JSValue prop_val = JS_GetProperty(ctx, val, atom); ++ int flags; ++ ++ if (JS_IsException(prop_val)) ++ goto done; ++ ++ if (js_freeze_value(ctx, prop_val)) { ++ JS_FreeValue(ctx, prop_val); ++ goto done; ++ } ++ ++ flags = JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_ENUMERABLE; ++ if (props[i].is_enumerable) ++ flags |= JS_PROP_ENUMERABLE; ++ ++ if (JS_DefinePropertyValue(ctx, val, atom, JS_DupValue(ctx, prop_val), flags) < 0) { ++ JS_FreeValue(ctx, prop_val); ++ goto done; ++ } ++ ++ JS_FreeValue(ctx, prop_val); ++ } ++ ++ if (JS_IsArray(ctx, val)) { ++ JSAtom length_atom = JS_NewAtom(ctx, "length"); ++ JSValue length_val = JS_UNDEFINED; ++ ++ if (length_atom == JS_ATOM_NULL) ++ goto done; ++ ++ length_val = JS_GetProperty(ctx, val, length_atom); ++ if (JS_IsException(length_val)) { ++ JS_FreeAtom(ctx, length_atom); ++ goto done; ++ } ++ ++ if (JS_DefinePropertyValue(ctx, ++ val, ++ length_atom, ++ JS_DupValue(ctx, length_val), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_ENUMERABLE) < 0) { ++ JS_FreeAtom(ctx, length_atom); ++ JS_FreeValue(ctx, length_val); ++ goto done; ++ } ++ ++ JS_FreeAtom(ctx, length_atom); ++ JS_FreeValue(ctx, length_val); ++ } ++ ++ if (JS_PreventExtensions(ctx, val) < 0) ++ goto done; ++ ++ ret = 0; ++ ++done: ++ if (props) ++ JS_FreePropertyEnum(ctx, props, props_len); ++ return ret; ++} ++ ++static int js_canon_clone_and_freeze(JSContext *ctx, JSValueConst input, JSValue *out) ++{ ++ JSDvBuffer buf = {0}; ++ JSDvLimits limits = JS_DV_LIMIT_DEFAULTS; ++ JSValue decoded = JS_UNDEFINED; ++ ++ if (!out) ++ return -1; ++ ++ if (JS_RunGCCheckpoint(ctx)) ++ return -1; ++ ++ if (JS_EncodeDV(ctx, input, &limits, &buf)) ++ return -1; ++ ++ decoded = JS_DecodeDV(ctx, buf.data, buf.length, &limits); ++ JS_FreeDVBuffer(ctx, &buf); ++ if (JS_IsException(decoded)) ++ return -1; ++ ++ if (js_freeze_value(ctx, decoded)) { ++ JS_FreeValue(ctx, decoded); ++ return -1; ++ } ++ ++ *out = decoded; ++ return 0; ++} ++ ++static int js_context_copy_and_freeze(JSContext *ctx, ++ JSValueConst source, ++ JSAtom atom, ++ JSValue *out) ++{ ++ JSValue tmp = JS_UNDEFINED; ++ JSValue dup = JS_UNDEFINED; ++ ++ if (!out) ++ return -1; ++ ++ tmp = JS_GetProperty(ctx, source, atom); ++ if (JS_IsException(tmp)) ++ return -1; ++ ++ if (!JS_IsUndefined(tmp)) { ++ dup = JS_DupValue(ctx, tmp); ++ if (js_freeze_value(ctx, dup)) { ++ JS_FreeValue(ctx, dup); ++ JS_FreeValue(ctx, tmp); ++ return -1; ++ } ++ *out = dup; ++ } ++ ++ JS_FreeValue(ctx, tmp); ++ return 0; ++} ++ ++static int js_decode_context_blob(JSContext *ctx, ++ const uint8_t *context_blob, ++ size_t context_blob_size, ++ JSValue *out_event, ++ JSValue *out_event_canonical, ++ JSValue *out_steps) ++{ ++ JSValue decoded = JS_UNDEFINED; ++ JSAtom event_atom = JS_ATOM_NULL; ++ JSAtom event_canonical_atom = JS_ATOM_NULL; ++ JSAtom steps_atom = JS_ATOM_NULL; ++ int ret = -1; ++ ++ if (!out_event || !out_event_canonical || !out_steps) ++ return -1; ++ ++ *out_event = JS_NULL; ++ *out_event_canonical = JS_NULL; ++ *out_steps = JS_NULL; ++ ++ if (!context_blob || context_blob_size == 0) ++ return 0; ++ ++ decoded = JS_DecodeDV(ctx, context_blob, context_blob_size, &JS_DV_LIMIT_DEFAULTS); ++ if (JS_IsException(decoded)) ++ return -1; ++ ++ if (!JS_IsObject(decoded) || JS_IsArray(ctx, decoded)) { ++ JS_FreeValue(ctx, decoded); ++ JS_ThrowTypeError(ctx, "context blob must decode to an object"); ++ return -1; ++ } ++ ++ event_atom = JS_NewAtom(ctx, "event"); ++ event_canonical_atom = JS_NewAtom(ctx, "eventCanonical"); ++ steps_atom = JS_NewAtom(ctx, "steps"); ++ if (event_atom == JS_ATOM_NULL || event_canonical_atom == JS_ATOM_NULL || steps_atom == JS_ATOM_NULL) ++ goto done; ++ ++ if (js_context_copy_and_freeze(ctx, decoded, event_atom, out_event)) ++ goto done; ++ if (js_context_copy_and_freeze(ctx, decoded, event_canonical_atom, out_event_canonical)) ++ goto done; ++ if (js_context_copy_and_freeze(ctx, decoded, steps_atom, out_steps)) ++ goto done; ++ ++ ret = 0; ++ ++done: ++ if (event_atom != JS_ATOM_NULL) ++ JS_FreeAtom(ctx, event_atom); ++ if (event_canonical_atom != JS_ATOM_NULL) ++ JS_FreeAtom(ctx, event_canonical_atom); ++ if (steps_atom != JS_ATOM_NULL) ++ JS_FreeAtom(ctx, steps_atom); ++ if (!JS_IsUndefined(decoded)) ++ JS_FreeValue(ctx, decoded); ++ return ret; ++} ++ ++static JSValue js_document_wrapper(JSContext *ctx, ++ JSValueConst this_val, ++ int argc, ++ JSValueConst *argv, ++ int magic, ++ JSValue *func_data) ++{ ++ (void)this_val; ++ (void)magic; ++ ++ if (!func_data || !JS_IsFunction(ctx, func_data[0])) { ++ JS_ThrowTypeError(ctx, "Host.v1.document binding is missing"); ++ return JS_EXCEPTION; ++ } ++ ++ return JS_Call(ctx, func_data[0], JS_UNDEFINED, argc, argv); ++} ++ ++static JSValue js_canon_unwrap(JSContext *ctx, ++ JSValueConst this_val, ++ int argc, ++ JSValueConst *argv) ++{ ++ JSValue clone = JS_UNDEFINED; ++ ++ (void)this_val; ++ ++ if (argc != 1) { ++ JS_ThrowTypeError(ctx, "canon.unwrap expects 1 argument"); ++ return JS_EXCEPTION; ++ } ++ ++ if (js_canon_clone_and_freeze(ctx, argv[0], &clone)) ++ return JS_EXCEPTION; ++ ++ return clone; ++} ++ ++static JSValue js_canon_at(JSContext *ctx, ++ JSValueConst this_val, ++ int argc, ++ JSValueConst *argv) ++{ ++ JSValue canonical = JS_UNDEFINED; ++ JSValue current = JS_UNDEFINED; ++ JSValue ret = JS_UNDEFINED; ++ uint32_t path_len = 0; ++ BOOL missing = FALSE; ++ ++ (void)this_val; ++ ++ if (argc < 2) { ++ JS_ThrowTypeError(ctx, "canon.at expects a value and a path array"); ++ return JS_EXCEPTION; ++ } ++ ++ if (!JS_IsArray(ctx, argv[1])) { ++ JS_ThrowTypeError(ctx, "canon.at path must be an array"); ++ return JS_EXCEPTION; ++ } ++ ++ if (js_canon_clone_and_freeze(ctx, argv[0], &canonical)) ++ return JS_EXCEPTION; ++ ++ { ++ JSValue len_val = JS_GetPropertyStr(ctx, argv[1], "length"); ++ if (JS_IsException(len_val)) { ++ JS_FreeValue(ctx, canonical); ++ return JS_EXCEPTION; ++ } ++ if (JS_ToUint32(ctx, &path_len, len_val)) { ++ JS_FreeValue(ctx, len_val); ++ JS_FreeValue(ctx, canonical); ++ return JS_EXCEPTION; ++ } ++ JS_FreeValue(ctx, len_val); ++ } ++ ++ current = JS_DupValue(ctx, canonical); ++ ++ for (uint32_t i = 0; i < path_len; i++) { ++ JSValue segment = JS_GetPropertyUint32(ctx, argv[1], i); ++ ++ if (JS_IsException(segment)) { ++ JS_FreeValue(ctx, current); ++ JS_FreeValue(ctx, canonical); ++ return JS_EXCEPTION; ++ } ++ ++ if (!JS_IsObject(current)) { ++ JS_FreeValue(ctx, segment); ++ missing = TRUE; ++ break; ++ } ++ ++ if (JS_IsString(segment)) { ++ size_t utf8_len = 0; ++ const char *prop = JS_ToCStringLen2(ctx, &utf8_len, segment, 0); ++ JSValue next = JS_UNDEFINED; ++ ++ if (!prop) { ++ JS_FreeValue(ctx, segment); ++ JS_FreeValue(ctx, current); ++ JS_FreeValue(ctx, canonical); ++ return JS_EXCEPTION; ++ } ++ ++ if (utf8_len > JS_DV_LIMIT_DEFAULTS.max_string_bytes) { ++ JS_FreeCString(ctx, prop); ++ JS_FreeValue(ctx, segment); ++ JS_FreeValue(ctx, current); ++ JS_FreeValue(ctx, canonical); ++ JS_ThrowTypeError(ctx, "canon.at path segment exceeds string limit"); ++ return JS_EXCEPTION; ++ } ++ ++ next = JS_GetPropertyStr(ctx, current, prop); ++ JS_FreeCString(ctx, prop); ++ JS_FreeValue(ctx, segment); ++ ++ if (JS_IsException(next)) { ++ JS_FreeValue(ctx, current); ++ JS_FreeValue(ctx, canonical); ++ return JS_EXCEPTION; ++ } ++ ++ if (JS_IsUndefined(next)) { ++ JS_FreeValue(ctx, next); ++ missing = TRUE; ++ break; ++ } ++ ++ JS_FreeValue(ctx, current); ++ current = next; ++ } else { ++ BOOL is_number = JS_IsNumber(segment); ++ BOOL is_bigint = JS_IsBigInt(ctx, segment); ++ double idx_d = 0; ++ int64_t index = 0; ++ JSValue next = JS_UNDEFINED; ++ ++ if (!is_number && !is_bigint) { ++ JS_FreeValue(ctx, segment); ++ JS_FreeValue(ctx, current); ++ JS_FreeValue(ctx, canonical); ++ JS_ThrowTypeError(ctx, "canon.at path elements must be strings or integers"); ++ return JS_EXCEPTION; ++ } ++ ++ if (is_number) { ++ if (JS_ToFloat64(ctx, &idx_d, segment)) { ++ JS_FreeValue(ctx, segment); ++ JS_FreeValue(ctx, current); ++ JS_FreeValue(ctx, canonical); ++ return JS_EXCEPTION; ++ } ++ ++ if (!isfinite(idx_d) || floor(idx_d) != idx_d || (idx_d == 0.0 && signbit(idx_d))) { ++ JS_FreeValue(ctx, segment); ++ JS_FreeValue(ctx, current); ++ JS_FreeValue(ctx, canonical); ++ JS_ThrowTypeError(ctx, "canon.at path elements must be strings or integers"); ++ return JS_EXCEPTION; ++ } ++ ++ index = (int64_t)idx_d; ++ } else { ++ if (JS_ToInt64Ext(ctx, &index, segment)) { ++ JS_FreeValue(ctx, segment); ++ JS_FreeValue(ctx, current); ++ JS_FreeValue(ctx, canonical); ++ JS_ThrowTypeError(ctx, "canon.at path elements must be strings or integers"); ++ return JS_EXCEPTION; ++ } ++ } ++ ++ JS_FreeValue(ctx, segment); ++ ++ if (index < 0 || (uint64_t)index >= JS_DV_LIMIT_DEFAULTS.max_array_length) { ++ JS_FreeValue(ctx, current); ++ JS_FreeValue(ctx, canonical); ++ JS_ThrowTypeError(ctx, "canon.at path index is out of range"); ++ return JS_EXCEPTION; ++ } ++ ++ if (!JS_IsArray(ctx, current)) { ++ missing = TRUE; ++ break; ++ } ++ ++ next = JS_GetPropertyUint32(ctx, current, (uint32_t)index); ++ if (JS_IsException(next)) { ++ JS_FreeValue(ctx, current); ++ JS_FreeValue(ctx, canonical); ++ return JS_EXCEPTION; ++ } ++ ++ if (JS_IsUndefined(next)) { ++ JS_FreeValue(ctx, next); ++ missing = TRUE; ++ break; ++ } ++ ++ JS_FreeValue(ctx, current); ++ current = next; ++ } ++ } ++ ++ if (missing) { ++ JS_FreeValue(ctx, current); ++ current = JS_UNDEFINED; ++ ret = JS_UNDEFINED; ++ } else { ++ ret = current; ++ current = JS_UNDEFINED; ++ } ++ ++ JS_FreeValue(ctx, canonical); ++ if (!JS_IsUndefined(current)) ++ JS_FreeValue(ctx, current); ++ return ret; ++} ++ ++int JS_InitErgonomicGlobals(JSContext *ctx, const uint8_t *context_blob, size_t context_blob_size) ++{ ++ JSValue global = JS_UNDEFINED; ++ JSValue host = JS_UNDEFINED; ++ JSValue host_v1 = JS_UNDEFINED; ++ JSValue document_ns = JS_UNDEFINED; ++ JSValue document_get = JS_UNDEFINED; ++ JSValue document_get_canonical = JS_UNDEFINED; ++ JSValue document_fn = JS_UNDEFINED; ++ JSValue document_canonical_fn = JS_UNDEFINED; ++ JSValue canon_obj = JS_UNDEFINED; ++ JSValue canon_unwrap_fn = JS_UNDEFINED; ++ JSValue canon_at_fn = JS_UNDEFINED; ++ JSValue event_val = JS_NULL; ++ JSValue event_canonical_val = JS_NULL; ++ JSValue steps_val = JS_NULL; ++ JSValueConst doc_funcs[1]; ++ int ret = -1; ++ ++ if (!ctx) ++ return -1; ++ ++ if (!js_host_find_manifest(ctx)) { ++ JS_ThrowTypeError(ctx, "abi manifest must be initialized before installing ergonomic globals"); ++ return -1; ++ } ++ ++ if (js_decode_context_blob(ctx, context_blob, context_blob_size, &event_val, &event_canonical_val, &steps_val)) ++ goto done; ++ ++ global = JS_GetGlobalObject(ctx); ++ if (JS_IsException(global)) ++ goto done; ++ ++ host = JS_GetPropertyStr(ctx, global, "Host"); ++ if (JS_IsException(host)) ++ goto done; ++ ++ host_v1 = JS_GetPropertyStr(ctx, host, "v1"); ++ if (JS_IsException(host_v1)) ++ goto done; ++ ++ document_ns = JS_GetPropertyStr(ctx, host_v1, "document"); ++ if (JS_IsException(document_ns)) ++ goto done; ++ ++ document_get = JS_GetPropertyStr(ctx, document_ns, "get"); ++ if (JS_IsException(document_get)) ++ goto done; ++ ++ document_get_canonical = JS_GetPropertyStr(ctx, document_ns, "getCanonical"); ++ if (JS_IsException(document_get_canonical)) ++ goto done; ++ ++ if (!JS_IsFunction(ctx, document_get) || !JS_IsFunction(ctx, document_get_canonical)) { ++ JS_ThrowTypeError(ctx, "Host.v1.document bindings are missing"); ++ goto done; ++ } ++ ++ doc_funcs[0] = JS_DupValue(ctx, document_get); ++ document_fn = JS_NewCFunctionData(ctx, js_document_wrapper, 1, 0, 1, doc_funcs); ++ JS_FreeValue(ctx, (JSValue)doc_funcs[0]); ++ if (JS_IsException(document_fn)) ++ goto done; ++ ++ doc_funcs[0] = JS_DupValue(ctx, document_get_canonical); ++ document_canonical_fn = JS_NewCFunctionData(ctx, js_document_wrapper, 1, 0, 1, doc_funcs); ++ JS_FreeValue(ctx, (JSValue)doc_funcs[0]); ++ if (JS_IsException(document_canonical_fn)) ++ goto done; ++ ++ if (JS_DefinePropertyValueStr(ctx, ++ global, ++ "document", ++ JS_DupValue(ctx, document_fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_CONFIGURABLE) < 0) ++ goto done; ++ ++ if (JS_DefinePropertyValueStr(ctx, ++ document_fn, ++ "canonical", ++ JS_DupValue(ctx, document_canonical_fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_CONFIGURABLE) < 0) ++ goto done; ++ ++ if (JS_PreventExtensions(ctx, document_fn) < 0) ++ goto done; ++ if (JS_PreventExtensions(ctx, document_canonical_fn) < 0) ++ goto done; ++ ++ canon_obj = JS_NewObjectProto(ctx, JS_NULL); ++ if (JS_IsException(canon_obj)) ++ goto done; ++ ++ canon_unwrap_fn = JS_NewCFunction(ctx, js_canon_unwrap, "unwrap", 1); ++ if (JS_IsException(canon_unwrap_fn)) ++ goto done; ++ ++ canon_at_fn = JS_NewCFunction(ctx, js_canon_at, "at", 2); ++ if (JS_IsException(canon_at_fn)) ++ goto done; ++ ++ if (JS_DefinePropertyValueStr(ctx, ++ canon_obj, ++ "unwrap", ++ JS_DupValue(ctx, canon_unwrap_fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_CONFIGURABLE) < 0) ++ goto done; ++ ++ if (JS_DefinePropertyValueStr(ctx, ++ canon_obj, ++ "at", ++ JS_DupValue(ctx, canon_at_fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_CONFIGURABLE) < 0) ++ goto done; ++ ++ if (JS_PreventExtensions(ctx, canon_unwrap_fn) < 0) ++ goto done; ++ if (JS_PreventExtensions(ctx, canon_at_fn) < 0) ++ goto done; ++ if (JS_PreventExtensions(ctx, canon_obj) < 0) ++ goto done; ++ ++ if (JS_DefinePropertyValueStr(ctx, ++ global, ++ "canon", ++ JS_DupValue(ctx, canon_obj), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_CONFIGURABLE) < 0) ++ goto done; ++ ++ if (JS_DefinePropertyValueStr(ctx, ++ global, ++ "event", ++ JS_DupValue(ctx, event_val), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_CONFIGURABLE) < 0) ++ goto done; ++ ++ if (JS_DefinePropertyValueStr(ctx, ++ global, ++ "eventCanonical", ++ JS_DupValue(ctx, event_canonical_val), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_CONFIGURABLE) < 0) ++ goto done; ++ ++ if (JS_DefinePropertyValueStr(ctx, ++ global, ++ "steps", ++ JS_DupValue(ctx, steps_val), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_CONFIGURABLE) < 0) ++ goto done; ++ ++ ret = 0; ++ ++done: ++ if (!JS_IsUndefined(host_v1)) ++ JS_FreeValue(ctx, host_v1); ++ if (!JS_IsUndefined(host)) ++ JS_FreeValue(ctx, host); ++ if (!JS_IsUndefined(global)) ++ JS_FreeValue(ctx, global); ++ if (!JS_IsUndefined(document_ns)) ++ JS_FreeValue(ctx, document_ns); ++ if (!JS_IsUndefined(document_get)) ++ JS_FreeValue(ctx, document_get); ++ if (!JS_IsUndefined(document_get_canonical)) ++ JS_FreeValue(ctx, document_get_canonical); ++ if (!JS_IsUndefined(document_fn)) ++ JS_FreeValue(ctx, document_fn); ++ if (!JS_IsUndefined(document_canonical_fn)) ++ JS_FreeValue(ctx, document_canonical_fn); ++ if (!JS_IsUndefined(canon_obj)) ++ JS_FreeValue(ctx, canon_obj); ++ if (!JS_IsUndefined(canon_unwrap_fn)) ++ JS_FreeValue(ctx, canon_unwrap_fn); ++ if (!JS_IsUndefined(canon_at_fn)) ++ JS_FreeValue(ctx, canon_at_fn); ++ if (!JS_IsUndefined(event_val)) ++ JS_FreeValue(ctx, event_val); ++ if (!JS_IsUndefined(event_canonical_val)) ++ JS_FreeValue(ctx, event_canonical_val); ++ if (!JS_IsUndefined(steps_val)) ++ JS_FreeValue(ctx, steps_val); ++ return ret; ++} +diff --git a/quickjs-host.h b/quickjs-host.h +index 1f51f59..7d1fcf4 100644 +--- a/quickjs-host.h ++++ b/quickjs-host.h +@@ -35,6 +35,7 @@ int JS_ParseHostResponse(JSContext *ctx, + JSHostResponse *out); + void JS_FreeHostResponse(JSContext *ctx, JSHostResponse *resp); + int JS_InitHostFromManifest(JSContext *ctx, const uint8_t *manifest_bytes, size_t manifest_size); ++int JS_InitErgonomicGlobals(JSContext *ctx, const uint8_t *context_blob, size_t context_blob_size); + void JS_FreeHostManifest(JSContext *ctx); + + #endif /* QUICKJS_HOST_H */ +diff --git a/quickjs.c b/quickjs.c +index 8e44131..2d13d34 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -3131,6 +3131,15 @@ int JS_InitDeterministicContext(JSContext *ctx, const JSDeterministicInitOptions + return -1; + } + ++ if (context_copy && options->context_blob_size > 0) { ++ if (JS_InitErgonomicGlobals(ctx, context_copy, options->context_blob_size) != 0) { ++ JS_FreeHostManifest(ctx); ++ js_free_rt(ctx->rt, manifest_copy); ++ js_free_rt(ctx->rt, context_copy); ++ return -1; ++ } ++ } ++ + memcpy(ctx->abi_manifest_hash, computed_hash, sizeof(computed_hash)); + js_sha256_to_hex(computed_hash, ctx->abi_manifest_hash_hex); + ctx->abi_manifest_bytes = manifest_copy; diff --git a/vendor/quickjs-patches/series/0019-feat-host-tape-add-optional-host-call-tape-ring-buff.patch b/vendor/quickjs-patches/series/0019-feat-host-tape-add-optional-host-call-tape-ring-buff.patch new file mode 100644 index 0000000..64803ee --- /dev/null +++ b/vendor/quickjs-patches/series/0019-feat-host-tape-add-optional-host-call-tape-ring-buff.patch @@ -0,0 +1,361 @@ +From 872a0f56f630351d638385b1a32db2d30e5afaac Mon Sep 17 00:00:00 2001 +From: Mateusz Jonak +Date: Wed, 17 Dec 2025 09:46:26 +0100 +Subject: [PATCH 19/51] feat(host-tape): add optional host-call tape ring + buffer for tracing (T-043) + +- quickjs-host: store per-context tape state alongside the loaded host manifest +- add tape API: JS_EnableHostTape / JS_ResetHostTape / JS_GetHostTapeLength / JS_ReadHostTape +- record Host.v1 call metadata (fn_id, req/resp lengths, units, is_error, charge_failed) +- hash request/response bytes (sha256) and record computed pre/post gas charges +- ensure tape memory is freed with JS_FreeHostManifest + +Refs: T-043 +--- + quickjs-host.c | 231 ++++++++++++++++++++++++++++++++++++++++++++++++- + quickjs-host.h | 21 +++++ + 2 files changed, 250 insertions(+), 2 deletions(-) + +diff --git a/quickjs-host.c b/quickjs-host.c +index 528e9c3..b46b69f 100644 +--- a/quickjs-host.c ++++ b/quickjs-host.c +@@ -451,9 +451,17 @@ struct JSHostManifest { + size_t function_count; + }; + ++typedef struct { ++ JSHostTapeRecord *records; ++ size_t capacity; ++ size_t count; ++ size_t head; ++} JSHostTapeState; ++ + typedef struct JSHostManifestNode { + JSContext *ctx; + JSHostManifest manifest; ++ JSHostTapeState tape; + struct JSHostManifestNode *next; + } JSHostManifestNode; + +@@ -470,6 +478,25 @@ static JSHostManifest *js_host_find_manifest(JSContext *ctx) + return NULL; + } + ++static JSHostManifestNode *js_host_find_manifest_node(JSContext *ctx) ++{ ++ JSHostManifestNode *node = js_host_manifest_list; ++ while (node) { ++ if (node->ctx == ctx) ++ return node; ++ node = node->next; ++ } ++ return NULL; ++} ++ ++static JSHostTapeState *js_host_get_tape(JSContext *ctx) ++{ ++ JSHostManifestNode *node = js_host_find_manifest_node(ctx); ++ if (!node) ++ return NULL; ++ return &node->tape; ++} ++ + static void js_host_free_function(JSContext *ctx, JSHostFunctionDef *fn) + { + if (!fn) +@@ -519,6 +546,67 @@ static void js_host_manifest_clear(JSContext *ctx, JSHostManifest *manifest) + manifest->function_count = 0; + } + ++static void js_host_tape_free(JSContext *ctx, JSHostTapeState *tape) ++{ ++ if (!tape) ++ return; ++ ++ if (tape->records) ++ js_free(ctx, tape->records); ++ ++ tape->records = NULL; ++ tape->capacity = 0; ++ tape->count = 0; ++ tape->head = 0; ++} ++ ++static int js_host_calc_gas_charges(const JSHostFunctionDef *fn, ++ size_t req_len, ++ size_t resp_len, ++ uint32_t units, ++ uint64_t *out_pre, ++ uint64_t *out_post) ++{ ++ uint64_t pre = 0; ++ uint64_t post = 0; ++ uint64_t arg_part = 0; ++ uint64_t resp_part = 0; ++ uint64_t unit_part = 0; ++ ++ if (!fn) ++ return -1; ++ ++ pre = fn->gas_base; ++ arg_part = (uint64_t)fn->gas_k_arg_bytes * (uint64_t)req_len; ++ if (arg_part > UINT64_MAX - pre) ++ return -1; ++ pre += arg_part; ++ ++ resp_part = (uint64_t)fn->gas_k_ret_bytes * (uint64_t)resp_len; ++ unit_part = (uint64_t)fn->gas_k_units * (uint64_t)units; ++ if (resp_part > UINT64_MAX - unit_part) ++ return -1; ++ post = resp_part + unit_part; ++ ++ if (out_pre) ++ *out_pre = pre; ++ if (out_post) ++ *out_post = post; ++ return 0; ++} ++ ++static void js_host_tape_append(JSHostTapeState *tape, const JSHostTapeRecord *record) ++{ ++ if (!tape || !record || tape->capacity == 0 || !tape->records) ++ return; ++ ++ size_t idx = tape->head; ++ tape->records[idx] = *record; ++ if (tape->count < tape->capacity) ++ tape->count++; ++ tape->head = (tape->head + 1) % tape->capacity; ++} ++ + void JS_FreeHostManifest(JSContext *ctx) + { + JSHostManifestNode *prev = NULL; +@@ -532,6 +620,7 @@ void JS_FreeHostManifest(JSContext *ctx) + js_host_manifest_list = node->next; + + js_host_manifest_clear(ctx, &node->manifest); ++ js_host_tape_free(ctx, &node->tape); + js_free(ctx, node); + return; + } +@@ -540,6 +629,98 @@ void JS_FreeHostManifest(JSContext *ctx) + } + } + ++int JS_EnableHostTape(JSContext *ctx, size_t capacity) ++{ ++ JSHostTapeState *tape = js_host_get_tape(ctx); ++ JSHostTapeRecord *records = NULL; ++ ++ if (!ctx) ++ return -1; ++ ++ if (!tape) { ++ JS_ThrowTypeError(ctx, "host manifest is not initialized"); ++ return -1; ++ } ++ ++ if (capacity > JS_HOST_TAPE_MAX_CAPACITY) { ++ JS_ThrowTypeError(ctx, "tape capacity exceeds max (%u)", JS_HOST_TAPE_MAX_CAPACITY); ++ return -1; ++ } ++ ++ if (capacity == 0) { ++ js_host_tape_free(ctx, tape); ++ return 0; ++ } ++ ++ records = js_mallocz(ctx, sizeof(JSHostTapeRecord) * capacity); ++ if (!records) ++ return -1; ++ ++ js_host_tape_free(ctx, tape); ++ tape->records = records; ++ tape->capacity = capacity; ++ tape->count = 0; ++ tape->head = 0; ++ return 0; ++} ++ ++int JS_ResetHostTape(JSContext *ctx) ++{ ++ JSHostTapeState *tape = js_host_get_tape(ctx); ++ ++ if (!ctx) ++ return -1; ++ ++ if (!tape) { ++ JS_ThrowTypeError(ctx, "host manifest is not initialized"); ++ return -1; ++ } ++ ++ if (tape->records && tape->capacity > 0) ++ memset(tape->records, 0, sizeof(JSHostTapeRecord) * tape->capacity); ++ ++ tape->count = 0; ++ tape->head = 0; ++ return 0; ++} ++ ++size_t JS_GetHostTapeLength(JSContext *ctx) ++{ ++ JSHostTapeState *tape = js_host_get_tape(ctx); ++ if (!tape) ++ return 0; ++ return tape->count; ++} ++ ++int JS_ReadHostTape(JSContext *ctx, JSHostTapeRecord *out_records, size_t max_records, size_t *out_count) ++{ ++ JSHostTapeState *tape = js_host_get_tape(ctx); ++ size_t to_copy = 0; ++ ++ if (!ctx) ++ return -1; ++ ++ if (!tape) { ++ JS_ThrowTypeError(ctx, "host manifest is not initialized"); ++ return -1; ++ } ++ ++ if (out_count) ++ *out_count = tape->count; ++ ++ if (!out_records || max_records == 0 || tape->count == 0 || tape->capacity == 0 || !tape->records) ++ return 0; ++ ++ to_copy = tape->count < max_records ? tape->count : max_records; ++ size_t start = (tape->head + tape->capacity - tape->count) % tape->capacity; ++ for (size_t i = 0; i < to_copy; i++) { ++ size_t idx = (start + i) % tape->capacity; ++ out_records[i] = tape->records[idx]; ++ } ++ ++ return 0; ++} ++ + static int js_host_manifest_error(JSContext *ctx, const char *path, const char *message) + { + if (path && message) +@@ -1512,6 +1693,15 @@ static JSValue js_host_call_wrapper(JSContext *ctx, + JSHostResponse resp; + JSHostCallResult result = {0}; + JSValue ret = JS_EXCEPTION; ++ JSHostTapeState *tape_state = js_host_get_tape(ctx); ++ int tape_enabled = tape_state && tape_state->capacity > 0 && tape_state->records; ++ uint8_t tape_req_hash[32]; ++ uint8_t tape_resp_hash[32]; ++ uint32_t tape_req_len = 0; ++ uint32_t tape_resp_len = 0; ++ uint64_t tape_gas_pre = 0; ++ uint64_t tape_gas_post = 0; ++ int tape_charge_failed = 0; + + if (!manifest) { + JS_ThrowTypeError(ctx, "host manifest is not initialized"); +@@ -1592,6 +1782,15 @@ static JSValue js_host_call_wrapper(JSContext *ctx, + return JS_EXCEPTION; + } + ++ if (tape_enabled) { ++ memset(tape_req_hash, 0, sizeof(tape_req_hash)); ++ memset(tape_resp_hash, 0, sizeof(tape_resp_hash)); ++ tape_req_len = (uint32_t)req_buf.length; ++ if (js_host_calc_gas_charges(fn, req_buf.length, 0, 0, &tape_gas_pre, NULL)) ++ tape_gas_pre = 0; ++ js_sha256(req_buf.data, req_buf.length, tape_req_hash); ++ } ++ + JS_FreeValue(ctx, args_array); + args_array = JS_UNDEFINED; + +@@ -1618,6 +1817,11 @@ static JSValue js_host_call_wrapper(JSContext *ctx, + + JS_FreeDVBuffer(ctx, &req_buf); + ++ if (tape_enabled) { ++ tape_resp_len = (uint32_t)result.length; ++ js_sha256(result.data, result.length, tape_resp_hash); ++ } ++ + JSHostResponseValidation validation = { + .max_units = fn->max_units, + .errors = fn->errors, +@@ -1627,7 +1831,29 @@ static JSValue js_host_call_wrapper(JSContext *ctx, + if (JS_ParseHostResponse(ctx, result.data, result.length, &validation, &resp)) + return JS_EXCEPTION; + +- if (js_host_charge_post(ctx, fn, result.length, resp.units)) { ++ if (tape_enabled) { ++ if (js_host_calc_gas_charges(fn, tape_req_len, tape_resp_len, resp.units, NULL, &tape_gas_post)) ++ tape_gas_post = 0; ++ } ++ ++ tape_charge_failed = js_host_charge_post(ctx, fn, result.length, resp.units); ++ ++ if (tape_enabled) { ++ JSHostTapeRecord rec = {0}; ++ rec.fn_id = fn->fn_id; ++ rec.req_len = tape_req_len; ++ rec.resp_len = tape_resp_len; ++ rec.units = resp.units; ++ rec.gas_pre = tape_gas_pre; ++ rec.gas_post = tape_gas_post; ++ rec.is_error = resp.is_error; ++ rec.charge_failed = tape_charge_failed; ++ memcpy(rec.req_hash, tape_req_hash, sizeof(rec.req_hash)); ++ memcpy(rec.resp_hash, tape_resp_hash, sizeof(rec.resp_hash)); ++ js_host_tape_append(tape_state, &rec); ++ } ++ ++ if (tape_charge_failed) { + JS_FreeHostResponse(ctx, &resp); + return JS_EXCEPTION; + } +@@ -1789,12 +2015,13 @@ int JS_InitHostFromManifest(JSContext *ctx, const uint8_t *manifest_bytes, size_ + if (js_host_validate_manifest(ctx, manifest_val, &manifest)) + goto done; + +- node = js_malloc(ctx, sizeof(JSHostManifestNode)); ++ node = js_mallocz(ctx, sizeof(JSHostManifestNode)); + if (!node) + goto done; + + node->ctx = ctx; + node->manifest = manifest; ++ node->tape = (JSHostTapeState){0}; + node->next = NULL; + memset(&manifest, 0, sizeof(manifest)); /* ownership moved */ + +diff --git a/quickjs-host.h b/quickjs-host.h +index 7d1fcf4..1b67157 100644 +--- a/quickjs-host.h ++++ b/quickjs-host.h +@@ -38,4 +38,25 @@ int JS_InitHostFromManifest(JSContext *ctx, const uint8_t *manifest_bytes, size_ + int JS_InitErgonomicGlobals(JSContext *ctx, const uint8_t *context_blob, size_t context_blob_size); + void JS_FreeHostManifest(JSContext *ctx); + ++/* Optional host-call tape (T-043). */ ++#define JS_HOST_TAPE_MAX_CAPACITY 1024 ++ ++typedef struct JSHostTapeRecord { ++ uint32_t fn_id; ++ uint32_t req_len; ++ uint32_t resp_len; ++ uint32_t units; ++ uint64_t gas_pre; ++ uint64_t gas_post; ++ int is_error; ++ int charge_failed; ++ uint8_t req_hash[32]; ++ uint8_t resp_hash[32]; ++} JSHostTapeRecord; ++ ++int JS_EnableHostTape(JSContext *ctx, size_t capacity); ++int JS_ResetHostTape(JSContext *ctx); ++size_t JS_GetHostTapeLength(JSContext *ctx); ++int JS_ReadHostTape(JSContext *ctx, JSHostTapeRecord *out_records, size_t max_records, size_t *out_count); ++ + #endif /* QUICKJS_HOST_H */ diff --git a/vendor/quickjs-patches/series/0020-quickjs-host-change-canon.at-to-accept-json-pointer-.patch b/vendor/quickjs-patches/series/0020-quickjs-host-change-canon.at-to-accept-json-pointer-.patch new file mode 100644 index 0000000..f9a478a --- /dev/null +++ b/vendor/quickjs-patches/series/0020-quickjs-host-change-canon.at-to-accept-json-pointer-.patch @@ -0,0 +1,318 @@ +From b63e7eb0837d6458af7edd32314408c695afdc61 Mon Sep 17 00:00:00 2001 +From: Mateusz Jonak +Date: Wed, 7 Jan 2026 11:36:00 +0100 +Subject: [PATCH 20/51] quickjs-host: change canon.at to accept JSON Pointer + strings + +`canon.at` now takes a **JSON Pointer string** instead of an array path. The implementation clones+freezes the input, parses RFC 6901-style pointer segments (handling `~0`/`~1`), and walks objects/arrays accordingly. + +- Rejects legacy array paths and non-string paths +- Disallows fragment form (`#...`) and array index `-` +- Treats numeric tokens as array indices (with bounds checks against `max_array_length`) +- Enforces per-segment `max_string_bytes` limit +- Cleans up allocated token buffer / C string on all exit paths +--- + quickjs-host.c | 248 ++++++++++++++++++++++++------------------------- + 1 file changed, 124 insertions(+), 124 deletions(-) + +diff --git a/quickjs-host.c b/quickjs-host.c +index b46b69f..38585de 100644 +--- a/quickjs-host.c ++++ b/quickjs-host.c +@@ -2289,165 +2289,160 @@ static JSValue js_canon_at(JSContext *ctx, + JSValue canonical = JS_UNDEFINED; + JSValue current = JS_UNDEFINED; + JSValue ret = JS_UNDEFINED; +- uint32_t path_len = 0; ++ const char *pointer = NULL; ++ size_t pointer_len = 0; ++ char *token = NULL; + BOOL missing = FALSE; + + (void)this_val; + + if (argc < 2) { +- JS_ThrowTypeError(ctx, "canon.at expects a value and a path array"); ++ JS_ThrowTypeError(ctx, "canon.at expects a value and a JSON Pointer string"); + return JS_EXCEPTION; + } + +- if (!JS_IsArray(ctx, argv[1])) { +- JS_ThrowTypeError(ctx, "canon.at path must be an array"); ++ if (JS_IsArray(ctx, argv[1])) { ++ JS_ThrowTypeError(ctx, "canon.at path must be a JSON Pointer string (array paths are no longer supported)"); ++ return JS_EXCEPTION; ++ } ++ ++ if (!JS_IsString(argv[1])) { ++ JS_ThrowTypeError(ctx, "canon.at path must be a JSON Pointer string"); + return JS_EXCEPTION; + } + + if (js_canon_clone_and_freeze(ctx, argv[0], &canonical)) + return JS_EXCEPTION; + +- { +- JSValue len_val = JS_GetPropertyStr(ctx, argv[1], "length"); +- if (JS_IsException(len_val)) { +- JS_FreeValue(ctx, canonical); +- return JS_EXCEPTION; +- } +- if (JS_ToUint32(ctx, &path_len, len_val)) { +- JS_FreeValue(ctx, len_val); +- JS_FreeValue(ctx, canonical); +- return JS_EXCEPTION; +- } +- JS_FreeValue(ctx, len_val); ++ pointer = JS_ToCStringLen2(ctx, &pointer_len, argv[1], 0); ++ if (!pointer) { ++ JS_FreeValue(ctx, canonical); ++ return JS_EXCEPTION; ++ } ++ ++ if (pointer_len == 0) { ++ ret = JS_DupValue(ctx, canonical); ++ goto done; ++ } ++ ++ if (pointer[0] == '#') { ++ JS_ThrowTypeError(ctx, "canon.at JSON Pointer fragment form is not supported"); ++ ret = JS_EXCEPTION; ++ goto done; ++ } ++ ++ if (pointer[0] != '/') { ++ JS_ThrowTypeError(ctx, "canon.at path must be a JSON Pointer string"); ++ ret = JS_EXCEPTION; ++ goto done; ++ } ++ ++ token = js_malloc(ctx, pointer_len + 1); ++ if (!token) { ++ ret = JS_EXCEPTION; ++ goto done; + } + + current = JS_DupValue(ctx, canonical); + +- for (uint32_t i = 0; i < path_len; i++) { +- JSValue segment = JS_GetPropertyUint32(ctx, argv[1], i); +- +- if (JS_IsException(segment)) { +- JS_FreeValue(ctx, current); +- JS_FreeValue(ctx, canonical); +- return JS_EXCEPTION; +- } ++ for (size_t pos = 1; pos <= pointer_len;) { ++ size_t token_len = 0; ++ JSValue next = JS_UNDEFINED; ++ BOOL is_array = FALSE; ++ BOOL is_index = FALSE; ++ uint64_t index = 0; + + if (!JS_IsObject(current)) { +- JS_FreeValue(ctx, segment); + missing = TRUE; + break; + } + +- if (JS_IsString(segment)) { +- size_t utf8_len = 0; +- const char *prop = JS_ToCStringLen2(ctx, &utf8_len, segment, 0); +- JSValue next = JS_UNDEFINED; ++ while (pos < pointer_len && pointer[pos] != '/') { ++ char ch = pointer[pos]; + +- if (!prop) { +- JS_FreeValue(ctx, segment); +- JS_FreeValue(ctx, current); +- JS_FreeValue(ctx, canonical); +- return JS_EXCEPTION; +- } +- +- if (utf8_len > JS_DV_LIMIT_DEFAULTS.max_string_bytes) { +- JS_FreeCString(ctx, prop); +- JS_FreeValue(ctx, segment); +- JS_FreeValue(ctx, current); +- JS_FreeValue(ctx, canonical); +- JS_ThrowTypeError(ctx, "canon.at path segment exceeds string limit"); +- return JS_EXCEPTION; +- } +- +- next = JS_GetPropertyStr(ctx, current, prop); +- JS_FreeCString(ctx, prop); +- JS_FreeValue(ctx, segment); +- +- if (JS_IsException(next)) { +- JS_FreeValue(ctx, current); +- JS_FreeValue(ctx, canonical); +- return JS_EXCEPTION; +- } +- +- if (JS_IsUndefined(next)) { +- JS_FreeValue(ctx, next); +- missing = TRUE; +- break; +- } +- +- JS_FreeValue(ctx, current); +- current = next; +- } else { +- BOOL is_number = JS_IsNumber(segment); +- BOOL is_bigint = JS_IsBigInt(ctx, segment); +- double idx_d = 0; +- int64_t index = 0; +- JSValue next = JS_UNDEFINED; +- +- if (!is_number && !is_bigint) { +- JS_FreeValue(ctx, segment); +- JS_FreeValue(ctx, current); +- JS_FreeValue(ctx, canonical); +- JS_ThrowTypeError(ctx, "canon.at path elements must be strings or integers"); +- return JS_EXCEPTION; +- } +- +- if (is_number) { +- if (JS_ToFloat64(ctx, &idx_d, segment)) { +- JS_FreeValue(ctx, segment); +- JS_FreeValue(ctx, current); +- JS_FreeValue(ctx, canonical); +- return JS_EXCEPTION; ++ if (ch == '~') { ++ if (pos + 1 >= pointer_len) { ++ JS_ThrowTypeError(ctx, "canon.at JSON Pointer contains invalid escape sequence"); ++ ret = JS_EXCEPTION; ++ goto done; + } +- +- if (!isfinite(idx_d) || floor(idx_d) != idx_d || (idx_d == 0.0 && signbit(idx_d))) { +- JS_FreeValue(ctx, segment); +- JS_FreeValue(ctx, current); +- JS_FreeValue(ctx, canonical); +- JS_ThrowTypeError(ctx, "canon.at path elements must be strings or integers"); +- return JS_EXCEPTION; ++ char esc = pointer[pos + 1]; ++ if (esc == '0') { ++ token[token_len++] = '~'; ++ } else if (esc == '1') { ++ token[token_len++] = '/'; ++ } else { ++ JS_ThrowTypeError(ctx, "canon.at JSON Pointer contains invalid escape sequence"); ++ ret = JS_EXCEPTION; ++ goto done; + } ++ pos += 2; ++ continue; ++ } + +- index = (int64_t)idx_d; +- } else { +- if (JS_ToInt64Ext(ctx, &index, segment)) { +- JS_FreeValue(ctx, segment); +- JS_FreeValue(ctx, current); +- JS_FreeValue(ctx, canonical); +- JS_ThrowTypeError(ctx, "canon.at path elements must be strings or integers"); +- return JS_EXCEPTION; ++ token[token_len++] = ch; ++ pos++; ++ } ++ ++ token[token_len] = '\0'; ++ is_array = JS_IsArray(ctx, current); ++ ++ if (is_array) { ++ if (token_len == 1 && token[0] == '-') { ++ JS_ThrowTypeError(ctx, "canon.at path index '-' is not allowed"); ++ ret = JS_EXCEPTION; ++ goto done; ++ } ++ ++ if (token_len > 0 && token[0] >= '0' && token[0] <= '9' && ++ !(token_len > 1 && token[0] == '0')) { ++ is_index = TRUE; ++ for (size_t i = 0; i < token_len; i++) { ++ char digit = token[i]; ++ if (digit < '0' || digit > '9') { ++ is_index = FALSE; ++ index = 0; ++ break; ++ } ++ index = (index * 10) + (uint64_t)(digit - '0'); ++ if (index >= JS_DV_LIMIT_DEFAULTS.max_array_length) { ++ JS_ThrowTypeError(ctx, "canon.at path index is out of range"); ++ ret = JS_EXCEPTION; ++ goto done; ++ } + } + } ++ } + +- JS_FreeValue(ctx, segment); +- +- if (index < 0 || (uint64_t)index >= JS_DV_LIMIT_DEFAULTS.max_array_length) { +- JS_FreeValue(ctx, current); +- JS_FreeValue(ctx, canonical); +- JS_ThrowTypeError(ctx, "canon.at path index is out of range"); +- return JS_EXCEPTION; +- } +- +- if (!JS_IsArray(ctx, current)) { +- missing = TRUE; +- break; +- } +- ++ if (is_array && is_index) { + next = JS_GetPropertyUint32(ctx, current, (uint32_t)index); +- if (JS_IsException(next)) { +- JS_FreeValue(ctx, current); +- JS_FreeValue(ctx, canonical); +- return JS_EXCEPTION; ++ } else { ++ if (token_len > JS_DV_LIMIT_DEFAULTS.max_string_bytes) { ++ JS_ThrowTypeError(ctx, "canon.at path segment exceeds string limit"); ++ ret = JS_EXCEPTION; ++ goto done; + } ++ next = JS_GetPropertyStr(ctx, current, token); ++ } + +- if (JS_IsUndefined(next)) { +- JS_FreeValue(ctx, next); +- missing = TRUE; +- break; +- } ++ if (JS_IsException(next)) { ++ ret = JS_EXCEPTION; ++ goto done; ++ } + +- JS_FreeValue(ctx, current); +- current = next; ++ if (JS_IsUndefined(next)) { ++ JS_FreeValue(ctx, next); ++ missing = TRUE; ++ break; ++ } ++ ++ JS_FreeValue(ctx, current); ++ current = next; ++ ++ if (pos < pointer_len && pointer[pos] == '/') { ++ pos++; ++ } else if (pos == pointer_len) { ++ pos++; + } + } + +@@ -2460,6 +2455,11 @@ static JSValue js_canon_at(JSContext *ctx, + current = JS_UNDEFINED; + } + ++done: ++ if (token) ++ js_free(ctx, token); ++ if (pointer) ++ JS_FreeCString(ctx, pointer); + JS_FreeValue(ctx, canonical); + if (!JS_IsUndefined(current)) + JS_FreeValue(ctx, current); diff --git a/vendor/quickjs-patches/series/0021-quickjs-host-add-depth-limited-freezing-and-optional.patch b/vendor/quickjs-patches/series/0021-quickjs-host-add-depth-limited-freezing-and-optional.patch new file mode 100644 index 0000000..30e72a0 --- /dev/null +++ b/vendor/quickjs-patches/series/0021-quickjs-host-add-depth-limited-freezing-and-optional.patch @@ -0,0 +1,291 @@ +From ff420e0eb9637dce4c87b201f1fe44dda4e3b0c2 Mon Sep 17 00:00:00 2001 +From: Mateusz Jonak +Date: Wed, 7 Jan 2026 12:17:18 +0100 +Subject: [PATCH 21/51] quickjs-host: add depth-limited freezing and optional + shallow `canon.unwrap` + +Refactor `js_freeze_value` to take a recursion `depth`, enabling bounded / non-recursive freezing when needed. Add `js_canon_clone_depth` + `js_canon_clone_and_freeze_depth` to support cloning while preserving canonical shape but limiting how deep values are DV-cloned/frozen. + +- `canon.unwrap(value, deep?)` now accepts an optional boolean: + - `deep=true` (default): existing behavior (full DV clone + deep freeze) + - `deep=false`: shallow clone/freeze at depth 0 (top-level only) +- Update ergonomic globals to expose `unwrap` with arity 2 +--- + quickjs-host.c | 209 ++++++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 198 insertions(+), 11 deletions(-) + +diff --git a/quickjs-host.c b/quickjs-host.c +index 38585de..daf6795 100644 +--- a/quickjs-host.c ++++ b/quickjs-host.c +@@ -2048,7 +2048,7 @@ done: + + /* Ergonomic globals (T-041) */ + +-static int js_freeze_value(JSContext *ctx, JSValueConst val) ++static int js_freeze_value(JSContext *ctx, JSValueConst val, uint32_t depth) + { + JSPropertyEnum *props = NULL; + uint32_t props_len = 0; +@@ -2069,9 +2069,11 @@ static int js_freeze_value(JSContext *ctx, JSValueConst val) + if (JS_IsException(prop_val)) + goto done; + +- if (js_freeze_value(ctx, prop_val)) { +- JS_FreeValue(ctx, prop_val); +- goto done; ++ if (depth > 0) { ++ if (js_freeze_value(ctx, prop_val, depth - 1)) { ++ JS_FreeValue(ctx, prop_val); ++ goto done; ++ } + } + + flags = JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_ENUMERABLE; +@@ -2125,6 +2127,137 @@ done: + return ret; + } + ++static int js_canon_clone_depth(JSContext *ctx, ++ JSValueConst input, ++ JSValueConst canonical, ++ uint32_t depth, ++ JSValue *out) ++{ ++ JSValue clone = JS_UNDEFINED; ++ JSPropertyEnum *props = NULL; ++ uint32_t props_len = 0; ++ int is_array = 0; ++ int ret = -1; ++ ++ if (!out) ++ return -1; ++ ++ if (!JS_IsObject(canonical)) { ++ *out = JS_DupValue(ctx, canonical); ++ return 0; ++ } ++ ++ is_array = JS_IsArray(ctx, canonical); ++ if (is_array < 0) ++ return -1; ++ ++ if (is_array) { ++ JSValue length_val = JS_UNDEFINED; ++ uint64_t length64 = 0; ++ ++ clone = JS_NewArray(ctx); ++ if (JS_IsException(clone)) ++ return -1; ++ ++ length_val = JS_GetPropertyStr(ctx, canonical, "length"); ++ if (JS_IsException(length_val)) ++ goto done; ++ ++ if (JS_ToIndex(ctx, &length64, length_val) < 0) { ++ JS_FreeValue(ctx, length_val); ++ goto done; ++ } ++ ++ JS_FreeValue(ctx, length_val); ++ length_val = JS_UNDEFINED; ++ ++ for (uint32_t i = 0; i < (uint32_t)length64; i++) { ++ JSValue input_val = JS_GetPropertyUint32(ctx, input, i); ++ JSValue next = JS_UNDEFINED; ++ ++ if (JS_IsException(input_val)) ++ goto done; ++ ++ if (depth == 0) { ++ next = input_val; ++ } else { ++ JSValue canonical_val = JS_GetPropertyUint32(ctx, canonical, i); ++ if (JS_IsException(canonical_val)) { ++ JS_FreeValue(ctx, input_val); ++ goto done; ++ } ++ ++ if (js_canon_clone_depth(ctx, input_val, canonical_val, depth - 1, &next)) { ++ JS_FreeValue(ctx, input_val); ++ JS_FreeValue(ctx, canonical_val); ++ goto done; ++ } ++ ++ JS_FreeValue(ctx, input_val); ++ JS_FreeValue(ctx, canonical_val); ++ } ++ ++ if (JS_SetPropertyUint32(ctx, clone, i, next) < 0) { ++ goto done; ++ } ++ } ++ ++ *out = clone; ++ return 0; ++ } ++ ++ clone = JS_NewObjectProto(ctx, JS_NULL); ++ if (JS_IsException(clone)) ++ return -1; ++ ++ if (JS_GetOwnPropertyNames(ctx, &props, &props_len, canonical, ++ JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY) < 0) ++ goto done; ++ ++ for (uint32_t i = 0; i < props_len; i++) { ++ JSAtom atom = props[i].atom; ++ JSValue input_val = JS_GetProperty(ctx, input, atom); ++ JSValue next = JS_UNDEFINED; ++ ++ if (JS_IsException(input_val)) ++ goto done; ++ ++ if (depth == 0) { ++ next = input_val; ++ } else { ++ JSValue canonical_val = JS_GetProperty(ctx, canonical, atom); ++ if (JS_IsException(canonical_val)) { ++ JS_FreeValue(ctx, input_val); ++ goto done; ++ } ++ ++ if (js_canon_clone_depth(ctx, input_val, canonical_val, depth - 1, &next)) { ++ JS_FreeValue(ctx, input_val); ++ JS_FreeValue(ctx, canonical_val); ++ goto done; ++ } ++ ++ JS_FreeValue(ctx, input_val); ++ JS_FreeValue(ctx, canonical_val); ++ } ++ ++ if (JS_DefinePropertyValue(ctx, clone, atom, next, JS_PROP_C_W_E) < 0) { ++ goto done; ++ } ++ } ++ ++ *out = clone; ++ clone = JS_UNDEFINED; ++ ret = 0; ++ ++done: ++ if (props) ++ JS_FreePropertyEnum(ctx, props, props_len); ++ if (!JS_IsUndefined(clone)) ++ JS_FreeValue(ctx, clone); ++ return ret; ++} ++ + static int js_canon_clone_and_freeze(JSContext *ctx, JSValueConst input, JSValue *out) + { + JSDvBuffer buf = {0}; +@@ -2145,7 +2278,7 @@ static int js_canon_clone_and_freeze(JSContext *ctx, JSValueConst input, JSValue + if (JS_IsException(decoded)) + return -1; + +- if (js_freeze_value(ctx, decoded)) { ++ if (js_freeze_value(ctx, decoded, UINT32_MAX)) { + JS_FreeValue(ctx, decoded); + return -1; + } +@@ -2154,6 +2287,46 @@ static int js_canon_clone_and_freeze(JSContext *ctx, JSValueConst input, JSValue + return 0; + } + ++static int js_canon_clone_and_freeze_depth(JSContext *ctx, ++ JSValueConst input, ++ uint32_t depth, ++ JSValue *out) ++{ ++ JSDvBuffer buf = {0}; ++ JSDvLimits limits = JS_DV_LIMIT_DEFAULTS; ++ JSValue decoded = JS_UNDEFINED; ++ JSValue clone = JS_UNDEFINED; ++ ++ if (!out) ++ return -1; ++ ++ if (JS_RunGCCheckpoint(ctx)) ++ return -1; ++ ++ if (JS_EncodeDV(ctx, input, &limits, &buf)) ++ return -1; ++ ++ decoded = JS_DecodeDV(ctx, buf.data, buf.length, &limits); ++ JS_FreeDVBuffer(ctx, &buf); ++ if (JS_IsException(decoded)) ++ return -1; ++ ++ if (js_canon_clone_depth(ctx, input, decoded, depth, &clone)) { ++ JS_FreeValue(ctx, decoded); ++ return -1; ++ } ++ ++ JS_FreeValue(ctx, decoded); ++ ++ if (js_freeze_value(ctx, clone, depth)) { ++ JS_FreeValue(ctx, clone); ++ return -1; ++ } ++ ++ *out = clone; ++ return 0; ++} ++ + static int js_context_copy_and_freeze(JSContext *ctx, + JSValueConst source, + JSAtom atom, +@@ -2171,7 +2344,7 @@ static int js_context_copy_and_freeze(JSContext *ctx, + + if (!JS_IsUndefined(tmp)) { + dup = JS_DupValue(ctx, tmp); +- if (js_freeze_value(ctx, dup)) { ++ if (js_freeze_value(ctx, dup, UINT32_MAX)) { + JS_FreeValue(ctx, dup); + JS_FreeValue(ctx, tmp); + return -1; +@@ -2267,16 +2440,30 @@ static JSValue js_canon_unwrap(JSContext *ctx, + JSValueConst *argv) + { + JSValue clone = JS_UNDEFINED; ++ BOOL deep = TRUE; + + (void)this_val; + +- if (argc != 1) { +- JS_ThrowTypeError(ctx, "canon.unwrap expects 1 argument"); ++ if (argc < 1 || argc > 2) { ++ JS_ThrowTypeError(ctx, "canon.unwrap expects 1 or 2 arguments"); + return JS_EXCEPTION; + } + +- if (js_canon_clone_and_freeze(ctx, argv[0], &clone)) +- return JS_EXCEPTION; ++ if (argc >= 2 && !JS_IsUndefined(argv[1])) { ++ if (!JS_IsBool(argv[1])) { ++ JS_ThrowTypeError(ctx, "canon.unwrap deep must be a boolean"); ++ return JS_EXCEPTION; ++ } ++ deep = JS_ToBool(ctx, argv[1]); ++ } ++ ++ if (deep) { ++ if (js_canon_clone_and_freeze(ctx, argv[0], &clone)) ++ return JS_EXCEPTION; ++ } else { ++ if (js_canon_clone_and_freeze_depth(ctx, argv[0], 0, &clone)) ++ return JS_EXCEPTION; ++ } + + return clone; + } +@@ -2560,7 +2747,7 @@ int JS_InitErgonomicGlobals(JSContext *ctx, const uint8_t *context_blob, size_t + if (JS_IsException(canon_obj)) + goto done; + +- canon_unwrap_fn = JS_NewCFunction(ctx, js_canon_unwrap, "unwrap", 1); ++ canon_unwrap_fn = JS_NewCFunction(ctx, js_canon_unwrap, "unwrap", 2); + if (JS_IsException(canon_unwrap_fn)) + goto done; + diff --git a/vendor/quickjs-patches/series/0022-feat-quickjs-host-rework-canon-unwrap-freezing.patch b/vendor/quickjs-patches/series/0022-feat-quickjs-host-rework-canon-unwrap-freezing.patch new file mode 100644 index 0000000..8a2e8e3 --- /dev/null +++ b/vendor/quickjs-patches/series/0022-feat-quickjs-host-rework-canon-unwrap-freezing.patch @@ -0,0 +1,426 @@ +From ba7e0cd427ac3aaff42270e04aedbfc07800b4af Mon Sep 17 00:00:00 2001 +From: Mateusz Jonak +Date: Wed, 7 Jan 2026 16:42:03 +0100 +Subject: [PATCH 22/51] feat(quickjs-host): rework canon unwrap + freezing + +- Replace depth-based clone logic with a DV round-trip decode + unwrap +- Add recursive unwrapping for `value` and `items` wrappers (arrays + objects) +- Freeze shallow results at depth 0 and deep results fully (UINT32_MAX) +- Improve atom lifecycle management and error-path cleanup +--- + quickjs-host.c | 376 +++++++++++++++++++++++++++++-------------------- + 1 file changed, 220 insertions(+), 156 deletions(-) + +diff --git a/quickjs-host.c b/quickjs-host.c +index daf6795..37a1f41 100644 +--- a/quickjs-host.c ++++ b/quickjs-host.c +@@ -2127,137 +2127,6 @@ done: + return ret; + } + +-static int js_canon_clone_depth(JSContext *ctx, +- JSValueConst input, +- JSValueConst canonical, +- uint32_t depth, +- JSValue *out) +-{ +- JSValue clone = JS_UNDEFINED; +- JSPropertyEnum *props = NULL; +- uint32_t props_len = 0; +- int is_array = 0; +- int ret = -1; +- +- if (!out) +- return -1; +- +- if (!JS_IsObject(canonical)) { +- *out = JS_DupValue(ctx, canonical); +- return 0; +- } +- +- is_array = JS_IsArray(ctx, canonical); +- if (is_array < 0) +- return -1; +- +- if (is_array) { +- JSValue length_val = JS_UNDEFINED; +- uint64_t length64 = 0; +- +- clone = JS_NewArray(ctx); +- if (JS_IsException(clone)) +- return -1; +- +- length_val = JS_GetPropertyStr(ctx, canonical, "length"); +- if (JS_IsException(length_val)) +- goto done; +- +- if (JS_ToIndex(ctx, &length64, length_val) < 0) { +- JS_FreeValue(ctx, length_val); +- goto done; +- } +- +- JS_FreeValue(ctx, length_val); +- length_val = JS_UNDEFINED; +- +- for (uint32_t i = 0; i < (uint32_t)length64; i++) { +- JSValue input_val = JS_GetPropertyUint32(ctx, input, i); +- JSValue next = JS_UNDEFINED; +- +- if (JS_IsException(input_val)) +- goto done; +- +- if (depth == 0) { +- next = input_val; +- } else { +- JSValue canonical_val = JS_GetPropertyUint32(ctx, canonical, i); +- if (JS_IsException(canonical_val)) { +- JS_FreeValue(ctx, input_val); +- goto done; +- } +- +- if (js_canon_clone_depth(ctx, input_val, canonical_val, depth - 1, &next)) { +- JS_FreeValue(ctx, input_val); +- JS_FreeValue(ctx, canonical_val); +- goto done; +- } +- +- JS_FreeValue(ctx, input_val); +- JS_FreeValue(ctx, canonical_val); +- } +- +- if (JS_SetPropertyUint32(ctx, clone, i, next) < 0) { +- goto done; +- } +- } +- +- *out = clone; +- return 0; +- } +- +- clone = JS_NewObjectProto(ctx, JS_NULL); +- if (JS_IsException(clone)) +- return -1; +- +- if (JS_GetOwnPropertyNames(ctx, &props, &props_len, canonical, +- JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY) < 0) +- goto done; +- +- for (uint32_t i = 0; i < props_len; i++) { +- JSAtom atom = props[i].atom; +- JSValue input_val = JS_GetProperty(ctx, input, atom); +- JSValue next = JS_UNDEFINED; +- +- if (JS_IsException(input_val)) +- goto done; +- +- if (depth == 0) { +- next = input_val; +- } else { +- JSValue canonical_val = JS_GetProperty(ctx, canonical, atom); +- if (JS_IsException(canonical_val)) { +- JS_FreeValue(ctx, input_val); +- goto done; +- } +- +- if (js_canon_clone_depth(ctx, input_val, canonical_val, depth - 1, &next)) { +- JS_FreeValue(ctx, input_val); +- JS_FreeValue(ctx, canonical_val); +- goto done; +- } +- +- JS_FreeValue(ctx, input_val); +- JS_FreeValue(ctx, canonical_val); +- } +- +- if (JS_DefinePropertyValue(ctx, clone, atom, next, JS_PROP_C_W_E) < 0) { +- goto done; +- } +- } +- +- *out = clone; +- clone = JS_UNDEFINED; +- ret = 0; +- +-done: +- if (props) +- JS_FreePropertyEnum(ctx, props, props_len); +- if (!JS_IsUndefined(clone)) +- JS_FreeValue(ctx, clone); +- return ret; +-} +- + static int js_canon_clone_and_freeze(JSContext *ctx, JSValueConst input, JSValue *out) + { + JSDvBuffer buf = {0}; +@@ -2287,15 +2156,204 @@ static int js_canon_clone_and_freeze(JSContext *ctx, JSValueConst input, JSValue + return 0; + } + +-static int js_canon_clone_and_freeze_depth(JSContext *ctx, +- JSValueConst input, +- uint32_t depth, +- JSValue *out) ++typedef struct { ++ JSAtom value_atom; ++ JSAtom items_atom; ++} CanonUnwrapAtoms; ++ ++static int js_has_own_property(JSContext *ctx, JSValueConst obj, JSAtom prop) ++{ ++ return JS_GetOwnProperty(ctx, NULL, obj, prop); ++} ++ ++static int js_canon_unwrap_value(JSContext *ctx, ++ JSValueConst value, ++ BOOL deep, ++ const CanonUnwrapAtoms *atoms, ++ JSValue *out); ++ ++static int js_canon_unwrap_array(JSContext *ctx, ++ JSValueConst value, ++ BOOL deep, ++ const CanonUnwrapAtoms *atoms, ++ JSValue *out) ++{ ++ JSValue clone = JS_UNDEFINED; ++ JSValue length_val = JS_UNDEFINED; ++ uint64_t length64 = 0; ++ ++ if (!out) ++ return -1; ++ ++ clone = JS_NewArray(ctx); ++ if (JS_IsException(clone)) ++ return -1; ++ ++ length_val = JS_GetPropertyStr(ctx, value, "length"); ++ if (JS_IsException(length_val)) ++ goto done; ++ ++ if (JS_ToIndex(ctx, &length64, length_val) < 0) { ++ JS_FreeValue(ctx, length_val); ++ goto done; ++ } ++ ++ JS_FreeValue(ctx, length_val); ++ length_val = JS_UNDEFINED; ++ ++ for (uint32_t i = 0; i < (uint32_t)length64; i++) { ++ JSValue element = JS_GetPropertyUint32(ctx, value, i); ++ JSValue next = JS_UNDEFINED; ++ ++ if (JS_IsException(element)) ++ goto done; ++ ++ if (!deep) { ++ next = element; ++ } else { ++ if (js_canon_unwrap_value(ctx, element, TRUE, atoms, &next)) { ++ JS_FreeValue(ctx, element); ++ goto done; ++ } ++ JS_FreeValue(ctx, element); ++ } ++ ++ if (JS_SetPropertyUint32(ctx, clone, i, next) < 0) { ++ JS_FreeValue(ctx, next); ++ goto done; ++ } ++ } ++ ++ *out = clone; ++ return 0; ++ ++done: ++ if (!JS_IsUndefined(clone)) ++ JS_FreeValue(ctx, clone); ++ return -1; ++} ++ ++static int js_canon_unwrap_value(JSContext *ctx, ++ JSValueConst value, ++ BOOL deep, ++ const CanonUnwrapAtoms *atoms, ++ JSValue *out) ++{ ++ JSValue items = JS_UNDEFINED; ++ JSValue clone = JS_UNDEFINED; ++ JSPropertyEnum *props = NULL; ++ uint32_t props_len = 0; ++ int is_array = 0; ++ int ret = -1; ++ ++ if (!out) ++ return -1; ++ ++ is_array = JS_IsArray(ctx, value); ++ if (is_array < 0) ++ return -1; ++ ++ if (is_array) ++ return js_canon_unwrap_array(ctx, value, deep, atoms, out); ++ ++ if (!JS_IsObject(value)) { ++ *out = JS_DupValue(ctx, value); ++ return 0; ++ } ++ ++ int has_value = js_has_own_property(ctx, value, atoms->value_atom); ++ if (has_value < 0) ++ return -1; ++ ++ if (has_value) { ++ JSValue nested = JS_GetProperty(ctx, value, atoms->value_atom); ++ if (JS_IsException(nested)) ++ return -1; ++ ++ if (!deep) { ++ *out = nested; ++ return 0; ++ } ++ ++ ret = js_canon_unwrap_value(ctx, nested, TRUE, atoms, out); ++ JS_FreeValue(ctx, nested); ++ return ret; ++ } ++ ++ items = JS_GetProperty(ctx, value, atoms->items_atom); ++ if (JS_IsException(items)) ++ return -1; ++ ++ is_array = JS_IsArray(ctx, items); ++ if (is_array < 0) { ++ JS_FreeValue(ctx, items); ++ return -1; ++ } ++ ++ if (is_array) { ++ ret = js_canon_unwrap_array(ctx, items, deep, atoms, out); ++ JS_FreeValue(ctx, items); ++ return ret; ++ } ++ ++ JS_FreeValue(ctx, items); ++ items = JS_UNDEFINED; ++ ++ clone = JS_NewObject(ctx); ++ if (JS_IsException(clone)) ++ return -1; ++ ++ if (JS_GetOwnPropertyNames(ctx, &props, &props_len, value, ++ JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY) < 0) ++ goto done; ++ ++ for (uint32_t i = 0; i < props_len; i++) { ++ JSAtom atom = props[i].atom; ++ JSValue child = JS_GetProperty(ctx, value, atom); ++ JSValue next = JS_UNDEFINED; ++ ++ if (JS_IsException(child)) ++ goto done; ++ ++ if (!deep) { ++ next = child; ++ } else { ++ if (js_canon_unwrap_value(ctx, child, TRUE, atoms, &next)) { ++ JS_FreeValue(ctx, child); ++ goto done; ++ } ++ JS_FreeValue(ctx, child); ++ } ++ ++ if (JS_DefinePropertyValue(ctx, clone, atom, next, JS_PROP_C_W_E) < 0) { ++ JS_FreeValue(ctx, next); ++ goto done; ++ } ++ } ++ ++ *out = clone; ++ clone = JS_UNDEFINED; ++ ret = 0; ++ ++done: ++ if (props) ++ JS_FreePropertyEnum(ctx, props, props_len); ++ if (!JS_IsUndefined(clone)) ++ JS_FreeValue(ctx, clone); ++ return ret; ++} ++ ++static int js_canon_unwrap_and_freeze(JSContext *ctx, ++ JSValueConst input, ++ BOOL deep, ++ JSValue *out) + { + JSDvBuffer buf = {0}; + JSDvLimits limits = JS_DV_LIMIT_DEFAULTS; + JSValue decoded = JS_UNDEFINED; +- JSValue clone = JS_UNDEFINED; ++ JSValue unwrapped = JS_UNDEFINED; ++ CanonUnwrapAtoms atoms = {JS_ATOM_NULL, JS_ATOM_NULL}; ++ int ret = -1; + + if (!out) + return -1; +@@ -2311,20 +2369,31 @@ static int js_canon_clone_and_freeze_depth(JSContext *ctx, + if (JS_IsException(decoded)) + return -1; + +- if (js_canon_clone_depth(ctx, input, decoded, depth, &clone)) { ++ atoms.value_atom = JS_NewAtom(ctx, "value"); ++ atoms.items_atom = JS_NewAtom(ctx, "items"); ++ if (atoms.value_atom == JS_ATOM_NULL || atoms.items_atom == JS_ATOM_NULL) ++ goto done; ++ ++ if (js_canon_unwrap_value(ctx, decoded, deep, &atoms, &unwrapped)) ++ goto done; ++ ++ if (js_freeze_value(ctx, unwrapped, deep ? UINT32_MAX : 0)) ++ goto done; ++ ++ *out = unwrapped; ++ unwrapped = JS_UNDEFINED; ++ ret = 0; ++ ++done: ++ if (atoms.value_atom != JS_ATOM_NULL) ++ JS_FreeAtom(ctx, atoms.value_atom); ++ if (atoms.items_atom != JS_ATOM_NULL) ++ JS_FreeAtom(ctx, atoms.items_atom); ++ if (!JS_IsUndefined(decoded)) + JS_FreeValue(ctx, decoded); +- return -1; +- } +- +- JS_FreeValue(ctx, decoded); +- +- if (js_freeze_value(ctx, clone, depth)) { +- JS_FreeValue(ctx, clone); +- return -1; +- } +- +- *out = clone; +- return 0; ++ if (!JS_IsUndefined(unwrapped)) ++ JS_FreeValue(ctx, unwrapped); ++ return ret; + } + + static int js_context_copy_and_freeze(JSContext *ctx, +@@ -2457,13 +2526,8 @@ static JSValue js_canon_unwrap(JSContext *ctx, + deep = JS_ToBool(ctx, argv[1]); + } + +- if (deep) { +- if (js_canon_clone_and_freeze(ctx, argv[0], &clone)) +- return JS_EXCEPTION; +- } else { +- if (js_canon_clone_and_freeze_depth(ctx, argv[0], 0, &clone)) +- return JS_EXCEPTION; +- } ++ if (js_canon_unwrap_and_freeze(ctx, argv[0], deep, &clone)) ++ return JS_EXCEPTION; + + return clone; + } diff --git a/vendor/quickjs-patches/series/0023-fix-dv-include-tag-name-in-unsupported-dv-type-error.patch b/vendor/quickjs-patches/series/0023-fix-dv-include-tag-name-in-unsupported-dv-type-error.patch new file mode 100644 index 0000000..e0544b5 --- /dev/null +++ b/vendor/quickjs-patches/series/0023-fix-dv-include-tag-name-in-unsupported-dv-type-error.patch @@ -0,0 +1,61 @@ +From 0a8fc5a50ba10c4bbb7b1e895b0b526b2f98362b Mon Sep 17 00:00:00 2001 +From: Mateusz Jonak +Date: Wed, 7 Jan 2026 17:56:15 +0100 +Subject: [PATCH 23/51] fix(dv): include tag name in unsupported DV type error + +Map common QuickJS JS_TAG_* values to human-readable names so dv_encode_value() +throws clearer errors; fall back to the numeric tag when unknown. +--- + quickjs-dv.c | 32 +++++++++++++++++++++++++++++++- + 1 file changed, 31 insertions(+), 1 deletion(-) + +diff --git a/quickjs-dv.c b/quickjs-dv.c +index e82dad5..8314329 100644 +--- a/quickjs-dv.c ++++ b/quickjs-dv.c +@@ -307,6 +307,31 @@ static int dv_encode_value(JSContext *ctx, + uint32_t depth, + JSDvBuilder *builder); + ++static const char *dv_tag_name(int tag) ++{ ++ switch (tag) { ++ case JS_TAG_UNDEFINED: ++ return "undefined"; ++ case JS_TAG_BIG_INT: ++ case JS_TAG_SHORT_BIG_INT: ++ return "bigint"; ++ case JS_TAG_SYMBOL: ++ return "symbol"; ++ case JS_TAG_FUNCTION_BYTECODE: ++ return "function"; ++ case JS_TAG_MODULE: ++ return "module"; ++ case JS_TAG_UNINITIALIZED: ++ return "uninitialized"; ++ case JS_TAG_EXCEPTION: ++ return "exception"; ++ case JS_TAG_CATCH_OFFSET: ++ return "catch_offset"; ++ default: ++ return NULL; ++ } ++} ++ + static int dv_encode_array(JSContext *ctx, + JSValueConst value, + const JSDvLimits *limits, +@@ -598,7 +623,12 @@ static int dv_encode_value(JSContext *ctx, + return dv_encode_object(ctx, value, limits, depth, builder); + } + default: +- return dv_throw(ctx, "unsupported DV type: %d", tag); ++ { ++ const char *name = dv_tag_name(tag); ++ if (name) ++ return dv_throw(ctx, "unsupported DV type: %s", name); ++ return dv_throw(ctx, "unsupported DV type: %d", tag); ++ } + } + } + diff --git a/vendor/quickjs-patches/series/0024-feat-host-expose-host.v1.emit-as-global-emit.patch b/vendor/quickjs-patches/series/0024-feat-host-expose-host.v1.emit-as-global-emit.patch new file mode 100644 index 0000000..8de3145 --- /dev/null +++ b/vendor/quickjs-patches/series/0024-feat-host-expose-host.v1.emit-as-global-emit.patch @@ -0,0 +1,101 @@ +From 4fbda0733a4d10cf8c9d5ed8cce806b5f1ea5129 Mon Sep 17 00:00:00 2001 +From: Mateusz Jonak +Date: Wed, 7 Jan 2026 18:14:05 +0100 +Subject: [PATCH 24/51] feat(host): expose Host.v1.emit as global emit() + +Add an `emit` wrapper that forwards to the Host.v1.emit binding when present, validates the binding, and cleans up allocated JSValues during init. +--- + quickjs-host.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 52 insertions(+) + +diff --git a/quickjs-host.c b/quickjs-host.c +index 37a1f41..7bdc9f9 100644 +--- a/quickjs-host.c ++++ b/quickjs-host.c +@@ -2503,6 +2503,24 @@ static JSValue js_document_wrapper(JSContext *ctx, + return JS_Call(ctx, func_data[0], JS_UNDEFINED, argc, argv); + } + ++static JSValue js_emit_wrapper(JSContext *ctx, ++ JSValueConst this_val, ++ int argc, ++ JSValueConst *argv, ++ int magic, ++ JSValue *func_data) ++{ ++ (void)this_val; ++ (void)magic; ++ ++ if (!func_data || !JS_IsFunction(ctx, func_data[0])) { ++ JS_ThrowTypeError(ctx, "Host.v1.emit binding is missing"); ++ return JS_EXCEPTION; ++ } ++ ++ return JS_Call(ctx, func_data[0], JS_UNDEFINED, argc, argv); ++} ++ + static JSValue js_canon_unwrap(JSContext *ctx, + JSValueConst this_val, + int argc, +@@ -2727,6 +2745,8 @@ int JS_InitErgonomicGlobals(JSContext *ctx, const uint8_t *context_blob, size_t + JSValue document_get_canonical = JS_UNDEFINED; + JSValue document_fn = JS_UNDEFINED; + JSValue document_canonical_fn = JS_UNDEFINED; ++ JSValue emit_call = JS_UNDEFINED; ++ JSValue emit_fn = JS_UNDEFINED; + JSValue canon_obj = JS_UNDEFINED; + JSValue canon_unwrap_fn = JS_UNDEFINED; + JSValue canon_at_fn = JS_UNDEFINED; +@@ -2734,6 +2754,7 @@ int JS_InitErgonomicGlobals(JSContext *ctx, const uint8_t *context_blob, size_t + JSValue event_canonical_val = JS_NULL; + JSValue steps_val = JS_NULL; + JSValueConst doc_funcs[1]; ++ JSValueConst emit_funcs[1]; + int ret = -1; + + if (!ctx) +@@ -2807,6 +2828,33 @@ int JS_InitErgonomicGlobals(JSContext *ctx, const uint8_t *context_blob, size_t + if (JS_PreventExtensions(ctx, document_canonical_fn) < 0) + goto done; + ++ emit_call = JS_GetPropertyStr(ctx, host_v1, "emit"); ++ if (JS_IsException(emit_call)) ++ goto done; ++ ++ if (!JS_IsUndefined(emit_call)) { ++ if (!JS_IsFunction(ctx, emit_call)) { ++ JS_ThrowTypeError(ctx, "Host.v1.emit binding is missing"); ++ goto done; ++ } ++ ++ emit_funcs[0] = JS_DupValue(ctx, emit_call); ++ emit_fn = JS_NewCFunctionData(ctx, js_emit_wrapper, 1, 0, 1, emit_funcs); ++ JS_FreeValue(ctx, (JSValue)emit_funcs[0]); ++ if (JS_IsException(emit_fn)) ++ goto done; ++ ++ if (JS_DefinePropertyValueStr(ctx, ++ global, ++ "emit", ++ JS_DupValue(ctx, emit_fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_CONFIGURABLE) < 0) ++ goto done; ++ ++ if (JS_PreventExtensions(ctx, emit_fn) < 0) ++ goto done; ++ } ++ + canon_obj = JS_NewObjectProto(ctx, JS_NULL); + if (JS_IsException(canon_obj)) + goto done; +@@ -2887,6 +2935,10 @@ done: + JS_FreeValue(ctx, document_fn); + if (!JS_IsUndefined(document_canonical_fn)) + JS_FreeValue(ctx, document_canonical_fn); ++ if (!JS_IsUndefined(emit_call)) ++ JS_FreeValue(ctx, emit_call); ++ if (!JS_IsUndefined(emit_fn)) ++ JS_FreeValue(ctx, emit_fn); + if (!JS_IsUndefined(canon_obj)) + JS_FreeValue(ctx, canon_obj); + if (!JS_IsUndefined(canon_unwrap_fn)) diff --git a/vendor/quickjs-patches/series/0025-refactor-quickjs-move-deterministic-host-plumbing-in.patch b/vendor/quickjs-patches/series/0025-refactor-quickjs-move-deterministic-host-plumbing-in.patch new file mode 100644 index 0000000..6944909 --- /dev/null +++ b/vendor/quickjs-patches/series/0025-refactor-quickjs-move-deterministic-host-plumbing-in.patch @@ -0,0 +1,1777 @@ +From 6d6c7b0bac0f75804ca74542343b184cc5352f51 Mon Sep 17 00:00:00 2001 +From: Mateusz Jonak +Date: Wed, 7 Jan 2026 20:06:01 +0100 +Subject: [PATCH 25/51] refactor(quickjs): move deterministic host plumbing + into quickjs-host + +- relocate deterministic init/disable helpers and host call/manifest setup +- add internal accessors in quickjs-internal.h for minimal core changes +- slim down quickjs.c to VM-only hooks +--- + quickjs-host.c | 865 +++++++++++++++++++++++++++++++++++++++++++++ + quickjs-internal.h | 30 ++ + quickjs.c | 787 +++-------------------------------------- + 3 files changed, 939 insertions(+), 743 deletions(-) + +diff --git a/quickjs-host.c b/quickjs-host.c +index 7bdc9f9..4865db0 100644 +--- a/quickjs-host.c ++++ b/quickjs-host.c +@@ -401,6 +401,871 @@ done: + return ret; + } + ++enum { ++ JS_DETERMINISTIC_DISABLED_EVAL = 1, ++ JS_DETERMINISTIC_DISABLED_FUNCTION = 2, ++ JS_DETERMINISTIC_DISABLED_RANDOM = 3, ++ JS_DETERMINISTIC_DISABLED_PROMISE = 4, ++ JS_DETERMINISTIC_DISABLED_REGEXP = 5, ++ JS_DETERMINISTIC_DISABLED_PROXY = 6, ++ JS_DETERMINISTIC_DISABLED_TYPED_ARRAY = 7, ++ JS_DETERMINISTIC_DISABLED_ARRAY_BUFFER = 8, ++ JS_DETERMINISTIC_DISABLED_SHARED_ARRAY_BUFFER = 9, ++ JS_DETERMINISTIC_DISABLED_DATAVIEW = 10, ++ JS_DETERMINISTIC_DISABLED_WEBASSEMBLY = 11, ++ JS_DETERMINISTIC_DISABLED_ATOMICS = 12, ++ JS_DETERMINISTIC_DISABLED_CONSOLE = 13, ++ JS_DETERMINISTIC_DISABLED_PRINT = 14, ++ JS_DETERMINISTIC_DISABLED_JSON_PARSE = 15, ++ JS_DETERMINISTIC_DISABLED_JSON_STRINGIFY = 16, ++ JS_DETERMINISTIC_DISABLED_ARRAY_SORT = 17, ++}; ++ ++static const char *js_get_disabled_name(int magic) ++{ ++ switch (magic) { ++ case JS_DETERMINISTIC_DISABLED_ARRAY_SORT: ++ return "Array.prototype.sort"; ++ case JS_DETERMINISTIC_DISABLED_JSON_STRINGIFY: ++ return "JSON.stringify"; ++ case JS_DETERMINISTIC_DISABLED_JSON_PARSE: ++ return "JSON.parse"; ++ case JS_DETERMINISTIC_DISABLED_PRINT: ++ return "print"; ++ case JS_DETERMINISTIC_DISABLED_CONSOLE: ++ return "console"; ++ case JS_DETERMINISTIC_DISABLED_ATOMICS: ++ return "Atomics"; ++ case JS_DETERMINISTIC_DISABLED_WEBASSEMBLY: ++ return "WebAssembly"; ++ case JS_DETERMINISTIC_DISABLED_DATAVIEW: ++ return "DataView"; ++ case JS_DETERMINISTIC_DISABLED_SHARED_ARRAY_BUFFER: ++ return "SharedArrayBuffer"; ++ case JS_DETERMINISTIC_DISABLED_ARRAY_BUFFER: ++ return "ArrayBuffer"; ++ case JS_DETERMINISTIC_DISABLED_TYPED_ARRAY: ++ return "Typed arrays"; ++ case JS_DETERMINISTIC_DISABLED_PROXY: ++ return "Proxy"; ++ case JS_DETERMINISTIC_DISABLED_REGEXP: ++ return "RegExp"; ++ case JS_DETERMINISTIC_DISABLED_PROMISE: ++ return "Promise"; ++ case JS_DETERMINISTIC_DISABLED_RANDOM: ++ return "Math.random"; ++ case JS_DETERMINISTIC_DISABLED_FUNCTION: ++ return "Function"; ++ case JS_DETERMINISTIC_DISABLED_EVAL: ++ default: ++ return "eval"; ++ } ++} ++ ++static JSValue js_deterministic_disabled(JSContext *ctx, JSValueConst this_val, ++ int argc, JSValueConst *argv, int magic) ++{ ++ const char *name = js_get_disabled_name(magic); ++ if (magic == JS_DETERMINISTIC_DISABLED_TYPED_ARRAY) ++ return JS_ThrowTypeError(ctx, "%s are disabled in deterministic mode", name); ++ return JS_ThrowTypeError(ctx, "%s is disabled in deterministic mode", name); ++} ++ ++static int js_deterministic_define_disabled_global(JSContext *ctx, const char *name, ++ int length, int magic) ++{ ++ JSValue fn; ++ JSValue global; ++ int ret; ++ ++ fn = JS_NewCFunctionMagic(ctx, js_deterministic_disabled, name, length, ++ JS_CFUNC_constructor_or_func_magic, magic); ++ if (JS_IsException(fn)) ++ return -1; ++ ++ global = JS_GetGlobalObject(ctx); ++ if (JS_IsException(global)) { ++ JS_FreeValue(ctx, fn); ++ return -1; ++ } ++ ++ ret = JS_DefinePropertyValueStr(ctx, global, name, JS_DupValue(ctx, fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ JS_FreeValue(ctx, global); ++ JS_FreeValue(ctx, fn); ++ if (ret < 0) ++ return -1; ++ ++ return 0; ++} ++ ++static JSValue js_deterministic_compile_regexp(JSContext *ctx, JSValueConst pattern, ++ JSValueConst flags) ++{ ++ (void)pattern; ++ (void)flags; ++ return JS_ThrowTypeError(ctx, "RegExp is disabled in deterministic mode"); ++} ++ ++static int js_deterministic_disable_eval(JSContext *ctx) ++{ ++ JSValue fn; ++ JSValue global; ++ int ret; ++ ++ fn = JS_NewCFunctionMagic(ctx, js_deterministic_disabled, "eval", 1, ++ JS_CFUNC_generic_magic, JS_DETERMINISTIC_DISABLED_EVAL); ++ if (JS_IsException(fn)) ++ return -1; ++ ++ global = JS_GetGlobalObject(ctx); ++ if (JS_IsException(global)) { ++ JS_FreeValue(ctx, fn); ++ return -1; ++ } ++ ++ ret = JS_DefinePropertyValueStr(ctx, global, "eval", JS_DupValue(ctx, fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ JS_FreeValue(ctx, global); ++ if (ret < 0) { ++ JS_FreeValue(ctx, fn); ++ return -1; ++ } ++ ++ js_deterministic_clear_eval_obj(ctx); ++ JS_FreeValue(ctx, fn); ++ return 0; ++} ++ ++static int js_deterministic_disable_function(JSContext *ctx) ++{ ++ JSValue fn; ++ JSValue global; ++ int ret; ++ ++ fn = JS_NewCFunctionMagic(ctx, js_deterministic_disabled, "Function", 1, ++ JS_CFUNC_constructor_or_func_magic, JS_DETERMINISTIC_DISABLED_FUNCTION); ++ if (JS_IsException(fn)) ++ return -1; ++ ++ global = JS_GetGlobalObject(ctx); ++ if (JS_IsException(global)) { ++ JS_FreeValue(ctx, fn); ++ return -1; ++ } ++ ++ ret = JS_DefinePropertyValueStr(ctx, global, "Function", JS_DupValue(ctx, fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ JS_FreeValue(ctx, global); ++ JS_FreeValue(ctx, fn); ++ if (ret < 0) ++ return -1; ++ ++ return 0; ++} ++ ++static int js_deterministic_disable_random(JSContext *ctx) ++{ ++ JSValue global; ++ JSValue math, fn; ++ int ret; ++ ++ global = JS_GetGlobalObject(ctx); ++ if (JS_IsException(global)) ++ return -1; ++ ++ math = JS_GetPropertyStr(ctx, global, "Math"); ++ JS_FreeValue(ctx, global); ++ if (JS_IsException(math)) ++ return -1; ++ if (!JS_IsObject(math)) { ++ JS_FreeValue(ctx, math); ++ return -1; ++ } ++ ++ fn = JS_NewCFunctionMagic(ctx, js_deterministic_disabled, "random", 0, ++ JS_CFUNC_generic_magic, JS_DETERMINISTIC_DISABLED_RANDOM); ++ if (JS_IsException(fn)) { ++ JS_FreeValue(ctx, math); ++ return -1; ++ } ++ ++ ret = JS_DefinePropertyValueStr(ctx, math, "random", JS_DupValue(ctx, fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ ++ JS_FreeValue(ctx, fn); ++ JS_FreeValue(ctx, math); ++ if (ret < 0) ++ return -1; ++ ++ return 0; ++} ++ ++static int js_deterministic_disable_regexp(JSContext *ctx) ++{ ++ JSValue fn; ++ JSValue global; ++ int ret; ++ ++ fn = JS_NewCFunctionMagic(ctx, js_deterministic_disabled, "RegExp", 2, ++ JS_CFUNC_constructor_or_func_magic, JS_DETERMINISTIC_DISABLED_REGEXP); ++ if (JS_IsException(fn)) ++ return -1; ++ ++ global = JS_GetGlobalObject(ctx); ++ if (JS_IsException(global)) { ++ JS_FreeValue(ctx, fn); ++ return -1; ++ } ++ ++ ret = JS_DefinePropertyValueStr(ctx, global, "RegExp", JS_DupValue(ctx, fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ JS_FreeValue(ctx, global); ++ if (ret < 0) { ++ JS_FreeValue(ctx, fn); ++ return -1; ++ } ++ ++ js_deterministic_set_regexp(ctx, fn, js_deterministic_compile_regexp); ++ ++ JS_FreeValue(ctx, fn); ++ return 0; ++} ++ ++static int js_deterministic_disable_proxy(JSContext *ctx) ++{ ++ JSValue fn; ++ JSValue global; ++ int ret; ++ ++ fn = JS_NewCFunctionMagic(ctx, js_deterministic_disabled, "Proxy", 2, ++ JS_CFUNC_constructor_or_func_magic, JS_DETERMINISTIC_DISABLED_PROXY); ++ if (JS_IsException(fn)) ++ return -1; ++ ++ global = JS_GetGlobalObject(ctx); ++ if (JS_IsException(global)) { ++ JS_FreeValue(ctx, fn); ++ return -1; ++ } ++ ++ ret = JS_DefinePropertyValueStr(ctx, global, "Proxy", JS_DupValue(ctx, fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ JS_FreeValue(ctx, global); ++ JS_FreeValue(ctx, fn); ++ if (ret < 0) ++ return -1; ++ ++ return 0; ++} ++ ++static int js_deterministic_disable_promise(JSContext *ctx) ++{ ++ JSValue fn; ++ JSValue global; ++ int ret; ++ ++ fn = JS_NewCFunctionMagic(ctx, js_deterministic_disabled, "Promise", 1, ++ JS_CFUNC_constructor_or_func_magic, JS_DETERMINISTIC_DISABLED_PROMISE); ++ if (JS_IsException(fn)) ++ return -1; ++ ++ global = JS_GetGlobalObject(ctx); ++ if (JS_IsException(global)) { ++ JS_FreeValue(ctx, fn); ++ return -1; ++ } ++ ++ ret = JS_DefinePropertyValueStr(ctx, global, "Promise", JS_DupValue(ctx, fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ JS_FreeValue(ctx, global); ++ ++ /* Ensure async internals see the disabled ctor */ ++ js_deterministic_set_promise_ctor(ctx, fn); ++ ++ /* Mirror common Promise statics to the same disabled stub */ ++ JS_DefinePropertyValueStr(ctx, fn, "resolve", JS_DupValue(ctx, fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ JS_DefinePropertyValueStr(ctx, fn, "reject", JS_DupValue(ctx, fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ JS_DefinePropertyValueStr(ctx, fn, "all", JS_DupValue(ctx, fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ JS_DefinePropertyValueStr(ctx, fn, "race", JS_DupValue(ctx, fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ JS_DefinePropertyValueStr(ctx, fn, "any", JS_DupValue(ctx, fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ JS_DefinePropertyValueStr(ctx, fn, "allSettled", JS_DupValue(ctx, fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ ++ JS_FreeValue(ctx, fn); ++ if (ret < 0) ++ return -1; ++ ++ return 0; ++} ++ ++static int js_deterministic_disable_typed_arrays(JSContext *ctx) ++{ ++ static const struct { ++ const char *name; ++ int length; ++ int magic; ++ } entries[] = { ++ { "ArrayBuffer", 1, JS_DETERMINISTIC_DISABLED_ARRAY_BUFFER }, ++ { "SharedArrayBuffer", 1, JS_DETERMINISTIC_DISABLED_SHARED_ARRAY_BUFFER }, ++ { "DataView", 3, JS_DETERMINISTIC_DISABLED_DATAVIEW }, ++ { "Uint8Array", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, ++ { "Uint8ClampedArray", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, ++ { "Int8Array", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, ++ { "Uint16Array", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, ++ { "Int16Array", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, ++ { "Uint32Array", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, ++ { "Int32Array", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, ++ { "BigInt64Array", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, ++ { "BigUint64Array", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, ++ { "Float16Array", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, ++ { "Float32Array", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, ++ { "Float64Array", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, ++ }; ++ ++ for (size_t i = 0; i < countof(entries); i++) { ++ if (js_deterministic_define_disabled_global(ctx, entries[i].name, ++ entries[i].length, entries[i].magic)) ++ return -1; ++ } ++ return 0; ++} ++ ++static int js_deterministic_disable_webassembly(JSContext *ctx) ++{ ++ return js_deterministic_define_disabled_global(ctx, "WebAssembly", 1, ++ JS_DETERMINISTIC_DISABLED_WEBASSEMBLY); ++} ++ ++static int js_deterministic_disable_atomics(JSContext *ctx) ++{ ++ return js_deterministic_define_disabled_global(ctx, "Atomics", 3, ++ JS_DETERMINISTIC_DISABLED_ATOMICS); ++} ++ ++static int js_deterministic_disable_console(JSContext *ctx) ++{ ++ JSValue console; ++ JSValue global; ++ ++ console = JS_NewObjectProto(ctx, JS_NULL); ++ if (JS_IsException(console)) ++ return -1; ++ ++ static const char *const methods[] = { "log", "info", "warn", "error", "debug" }; ++ for (size_t i = 0; i < countof(methods); i++) { ++ JSValue fn = JS_NewCFunctionMagic(ctx, js_deterministic_disabled, "console", 1, ++ JS_CFUNC_generic_magic, JS_DETERMINISTIC_DISABLED_CONSOLE); ++ if (JS_IsException(fn)) { ++ JS_FreeValue(ctx, console); ++ return -1; ++ } ++ if (JS_DefinePropertyValueStr(ctx, console, methods[i], JS_DupValue(ctx, fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE) < 0) { ++ JS_FreeValue(ctx, fn); ++ JS_FreeValue(ctx, console); ++ return -1; ++ } ++ JS_FreeValue(ctx, fn); ++ } ++ ++ global = JS_GetGlobalObject(ctx); ++ if (JS_IsException(global)) { ++ JS_FreeValue(ctx, console); ++ return -1; ++ } ++ ++ if (JS_DefinePropertyValueStr(ctx, global, "console", JS_DupValue(ctx, console), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE) < 0) { ++ JS_FreeValue(ctx, console); ++ JS_FreeValue(ctx, global); ++ return -1; ++ } ++ ++ JS_FreeValue(ctx, global); ++ JS_FreeValue(ctx, console); ++ return 0; ++} ++ ++static int js_deterministic_disable_print(JSContext *ctx) ++{ ++ return js_deterministic_define_disabled_global(ctx, "print", 1, ++ JS_DETERMINISTIC_DISABLED_PRINT); ++} ++ ++static int js_deterministic_disable_json(JSContext *ctx) ++{ ++ JSValue global; ++ JSValue json, parse_fn, stringify_fn; ++ int ret; ++ ++ global = JS_GetGlobalObject(ctx); ++ if (JS_IsException(global)) ++ return -1; ++ ++ json = JS_GetPropertyStr(ctx, global, "JSON"); ++ JS_FreeValue(ctx, global); ++ if (JS_IsException(json)) ++ return -1; ++ if (!JS_IsObject(json)) { ++ JS_FreeValue(ctx, json); ++ return -1; ++ } ++ ++ parse_fn = JS_NewCFunctionMagic(ctx, js_deterministic_disabled, "parse", 2, ++ JS_CFUNC_generic_magic, JS_DETERMINISTIC_DISABLED_JSON_PARSE); ++ if (JS_IsException(parse_fn)) { ++ JS_FreeValue(ctx, json); ++ return -1; ++ } ++ stringify_fn = JS_NewCFunctionMagic(ctx, js_deterministic_disabled, "stringify", 3, ++ JS_CFUNC_generic_magic, JS_DETERMINISTIC_DISABLED_JSON_STRINGIFY); ++ if (JS_IsException(stringify_fn)) { ++ JS_FreeValue(ctx, parse_fn); ++ JS_FreeValue(ctx, json); ++ return -1; ++ } ++ ++ ret = JS_DefinePropertyValueStr(ctx, json, "parse", JS_DupValue(ctx, parse_fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ if (ret < 0) ++ goto fail; ++ ++ ret = JS_DefinePropertyValueStr(ctx, json, "stringify", JS_DupValue(ctx, stringify_fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ if (ret < 0) ++ goto fail; ++ ++ JS_FreeValue(ctx, parse_fn); ++ JS_FreeValue(ctx, stringify_fn); ++ JS_FreeValue(ctx, json); ++ return 0; ++ ++fail: ++ JS_FreeValue(ctx, parse_fn); ++ JS_FreeValue(ctx, stringify_fn); ++ JS_FreeValue(ctx, json); ++ return -1; ++} ++ ++static int js_deterministic_disable_array_sort(JSContext *ctx) ++{ ++ JSValue global; ++ JSValue array_ctor, array_proto, sort_fn; ++ int ret; ++ ++ global = JS_GetGlobalObject(ctx); ++ if (JS_IsException(global)) ++ return -1; ++ ++ array_ctor = JS_GetPropertyStr(ctx, global, "Array"); ++ JS_FreeValue(ctx, global); ++ if (JS_IsException(array_ctor)) ++ return -1; ++ if (!JS_IsObject(array_ctor)) { ++ JS_FreeValue(ctx, array_ctor); ++ return -1; ++ } ++ ++ array_proto = JS_GetPropertyStr(ctx, array_ctor, "prototype"); ++ if (JS_IsException(array_proto)) { ++ JS_FreeValue(ctx, array_ctor); ++ return -1; ++ } ++ JS_FreeValue(ctx, array_ctor); ++ if (!JS_IsObject(array_proto)) { ++ JS_FreeValue(ctx, array_proto); ++ return -1; ++ } ++ ++ sort_fn = JS_NewCFunctionMagic(ctx, js_deterministic_disabled, "sort", 1, ++ JS_CFUNC_generic_magic, JS_DETERMINISTIC_DISABLED_ARRAY_SORT); ++ if (JS_IsException(sort_fn)) { ++ JS_FreeValue(ctx, array_proto); ++ return -1; ++ } ++ ++ ret = JS_DefinePropertyValueStr(ctx, array_proto, "sort", JS_DupValue(ctx, sort_fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ ++ JS_FreeValue(ctx, sort_fn); ++ JS_FreeValue(ctx, array_proto); ++ if (ret < 0) ++ return -1; ++ return 0; ++} ++ ++static int js_deterministic_init_host(JSContext *ctx) ++{ ++ JSValue host_ns, host_v1; ++ JSValue global; ++ int ret; ++ ++ host_ns = JS_NewObjectProto(ctx, JS_NULL); ++ if (JS_IsException(host_ns)) ++ return -1; ++ ++ host_v1 = JS_NewObjectProto(ctx, JS_NULL); ++ if (JS_IsException(host_v1)) { ++ JS_FreeValue(ctx, host_ns); ++ return -1; ++ } ++ ++ global = JS_GetGlobalObject(ctx); ++ if (JS_IsException(global)) { ++ JS_FreeValue(ctx, host_ns); ++ JS_FreeValue(ctx, host_v1); ++ return -1; ++ } ++ ++ ret = JS_DefinePropertyValueStr(ctx, host_ns, "v1", JS_DupValue(ctx, host_v1), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ if (ret < 0) ++ goto fail; ++ ++ ret = JS_DefinePropertyValueStr(ctx, global, "Host", JS_DupValue(ctx, host_ns), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ if (ret < 0) ++ goto fail; ++ ++ JS_FreeValue(ctx, global); ++ JS_FreeValue(ctx, host_ns); ++ JS_FreeValue(ctx, host_v1); ++ ++ return 0; ++ ++fail: ++ JS_FreeValue(ctx, global); ++ JS_FreeValue(ctx, host_ns); ++ JS_FreeValue(ctx, host_v1); ++ return -1; ++} ++ ++int js_deterministic_init_context(JSContext *ctx) ++{ ++ if (JS_AddIntrinsicBaseObjects(ctx) || ++ JS_AddIntrinsicEval(ctx) || ++ JS_AddIntrinsicJSON(ctx) || ++ JS_AddIntrinsicMapSet(ctx) || ++ js_deterministic_disable_eval(ctx) || ++ js_deterministic_disable_function(ctx) || ++ js_deterministic_disable_regexp(ctx) || ++ js_deterministic_disable_proxy(ctx) || ++ js_deterministic_disable_random(ctx) || ++ js_deterministic_disable_promise(ctx) || ++ js_deterministic_disable_typed_arrays(ctx) || ++ js_deterministic_disable_atomics(ctx) || ++ js_deterministic_disable_console(ctx) || ++ js_deterministic_disable_print(ctx) || ++ js_deterministic_disable_json(ctx) || ++ js_deterministic_disable_array_sort(ctx) || ++ js_deterministic_disable_webassembly(ctx) || ++ js_deterministic_init_host(ctx)) { ++ return -1; ++ } ++ js_deterministic_set_random_state(ctx, 1); ++ js_deterministic_set_mode(ctx, TRUE); ++ return 0; ++} ++ ++static JSValue JS_ThrowManifestError(JSContext *ctx, const char *code, const char *message) ++{ ++ JSValue obj, name, msg, code_val; ++ ++ obj = JS_NewError(ctx); ++ if (JS_IsException(obj)) ++ return JS_EXCEPTION; ++ ++ name = JS_NewString(ctx, "ManifestError"); ++ msg = JS_NewString(ctx, message); ++ code_val = JS_NewString(ctx, code); ++ if (JS_IsException(name) || JS_IsException(msg) || JS_IsException(code_val)) { ++ if (!JS_IsException(name)) ++ JS_FreeValue(ctx, name); ++ if (!JS_IsException(msg)) ++ JS_FreeValue(ctx, msg); ++ if (!JS_IsException(code_val)) ++ JS_FreeValue(ctx, code_val); ++ JS_FreeValue(ctx, obj); ++ return JS_EXCEPTION; ++ } ++ ++ JS_DefinePropertyValueStr(ctx, obj, "name", name, ++ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); ++ JS_DefinePropertyValueStr(ctx, obj, "message", msg, ++ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); ++ JS_DefinePropertyValueStr(ctx, obj, "code", code_val, ++ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); ++ JS_Throw(ctx, obj); ++ return JS_EXCEPTION; ++} ++ ++static int js_hex_nibble(int c) ++{ ++ if (c >= '0' && c <= '9') ++ return c - '0'; ++ if (c >= 'a' && c <= 'f') ++ return c - 'a' + 10; ++ return -1; ++} ++ ++static int js_parse_hash_hex(JSContext *ctx, const char *hex, uint8_t *out, size_t out_size) ++{ ++ size_t hex_len, i; ++ ++ if (!hex || !out) ++ return -1; ++ ++ hex_len = strlen(hex); ++ if (hex_len != out_size * 2) { ++ JS_ThrowTypeError(ctx, "abi manifest hash must be 64 lowercase hex characters"); ++ return -1; ++ } ++ ++ for(i = 0; i < out_size; i++) { ++ int high = js_hex_nibble(hex[i * 2]); ++ int low = js_hex_nibble(hex[i * 2 + 1]); ++ if (high < 0 || low < 0) { ++ JS_ThrowTypeError(ctx, "abi manifest hash must be 64 lowercase hex characters"); ++ return -1; ++ } ++ out[i] = (uint8_t)((high << 4) | low); ++ } ++ ++ return 0; ++} ++ ++int JS_InitDeterministicContext(JSContext *ctx, const JSDeterministicInitOptions *options) ++{ ++ JSRuntime *rt; ++ uint8_t computed_hash[32]; ++ uint8_t expected_hash[32]; ++ char computed_hash_hex[65]; ++ uint8_t *manifest_copy = NULL; ++ uint8_t *context_copy = NULL; ++ ++ if (!ctx || !options) ++ return -1; ++ ++ if (js_deterministic_manifest_is_initialized(ctx)) { ++ JS_ThrowTypeError(ctx, "abi manifest is already initialized"); ++ return -1; ++ } ++ ++ if (!options->manifest_bytes || options->manifest_size == 0) { ++ JS_ThrowTypeError(ctx, "abi manifest is required"); ++ return -1; ++ } ++ ++ if (options->manifest_size > JS_DETERMINISTIC_MAX_MANIFEST_BYTES) { ++ JS_ThrowTypeError(ctx, "abi manifest exceeds maximum size"); ++ return -1; ++ } ++ ++ if (!options->manifest_hash_hex) { ++ JS_ThrowTypeError(ctx, "abi manifest hash is required"); ++ return -1; ++ } ++ ++ if (js_parse_hash_hex(ctx, options->manifest_hash_hex, expected_hash, sizeof(expected_hash)) != 0) ++ return -1; ++ ++ if (options->context_blob_size > 0 && !options->context_blob) { ++ JS_ThrowTypeError(ctx, "context blob is required when context_blob_size is set"); ++ return -1; ++ } ++ ++ js_sha256(options->manifest_bytes, options->manifest_size, computed_hash); ++ if (memcmp(computed_hash, expected_hash, sizeof(expected_hash)) != 0) { ++ JS_ThrowManifestError(ctx, "ABI_MANIFEST_HASH_MISMATCH", "abi manifest hash mismatch"); ++ return -1; ++ } ++ ++ rt = JS_GetRuntime(ctx); ++ manifest_copy = js_malloc_rt(rt, options->manifest_size); ++ if (!manifest_copy) { ++ JS_ThrowOutOfMemory(ctx); ++ return -1; ++ } ++ memcpy(manifest_copy, options->manifest_bytes, options->manifest_size); ++ ++ if (options->context_blob && options->context_blob_size > 0) { ++ if (options->context_blob_size > JS_DETERMINISTIC_MAX_CONTEXT_BLOB_BYTES) { ++ js_free_rt(rt, manifest_copy); ++ JS_ThrowTypeError(ctx, "context blob exceeds maximum size"); ++ return -1; ++ } ++ ++ context_copy = js_malloc_rt(rt, options->context_blob_size); ++ if (!context_copy) { ++ js_free_rt(rt, manifest_copy); ++ JS_ThrowOutOfMemory(ctx); ++ return -1; ++ } ++ memcpy(context_copy, options->context_blob, options->context_blob_size); ++ } ++ ++ if (JS_InitHostFromManifest(ctx, manifest_copy, options->manifest_size) != 0) { ++ js_free_rt(rt, manifest_copy); ++ if (context_copy) ++ js_free_rt(rt, context_copy); ++ return -1; ++ } ++ ++ if (context_copy && options->context_blob_size > 0) { ++ if (JS_InitErgonomicGlobals(ctx, context_copy, options->context_blob_size) != 0) { ++ JS_FreeHostManifest(ctx); ++ js_free_rt(rt, manifest_copy); ++ js_free_rt(rt, context_copy); ++ return -1; ++ } ++ } ++ ++ js_sha256_to_hex(computed_hash, computed_hash_hex); ++ js_deterministic_set_manifest_state(ctx, ++ manifest_copy, ++ options->manifest_size, ++ computed_hash, ++ computed_hash_hex, ++ context_copy, ++ context_copy ? options->context_blob_size : 0); ++ JS_SetGasLimit(ctx, options->gas_limit); ++ ++ return 0; ++} ++ ++int JS_HostCall(JSContext *ctx, ++ uint32_t fn_id, ++ const uint8_t *req_bytes, ++ size_t req_len, ++ uint32_t max_request_bytes, ++ uint32_t max_response_bytes, ++ JSHostCallResult *out_result) ++{ ++ JSRuntime *rt; ++ JSHostCallFunc *host_call_func; ++ uint32_t resp_len, resp_capacity, req_len32; ++ uint32_t dv_limit; ++ const uint8_t *req_ptr; ++ uint8_t *resp_buf; ++ ++ if (!ctx || !out_result) ++ return -1; ++ ++ out_result->data = NULL; ++ out_result->length = 0; ++ ++ rt = JS_GetRuntime(ctx); ++ dv_limit = JS_DV_LIMIT_DEFAULTS.max_encoded_bytes; ++ ++ host_call_func = js_get_host_call_func(rt); ++ if (!host_call_func) { ++ JS_ThrowTypeError(ctx, "host_call dispatcher is not configured"); ++ return -1; ++ } ++ ++ if (fn_id == 0) { ++ JS_ThrowTypeError(ctx, "host_call fn_id must be >= 1"); ++ return -1; ++ } ++ ++ if (max_request_bytes == 0) { ++ JS_ThrowTypeError(ctx, "host_call max_request_bytes must be > 0"); ++ return -1; ++ } ++ ++ if (max_request_bytes > dv_limit) { ++ JS_ThrowTypeError(ctx, "host_call max_request_bytes exceeds DV limit"); ++ return -1; ++ } ++ ++ if (max_response_bytes == 0) { ++ JS_ThrowTypeError(ctx, "host_call max_response_bytes must be > 0"); ++ return -1; ++ } ++ ++ if (max_response_bytes > dv_limit) { ++ JS_ThrowTypeError(ctx, "host_call max_response_bytes exceeds DV limit"); ++ return -1; ++ } ++ ++ if (req_len > (size_t)max_request_bytes) { ++ JS_ThrowTypeError(ctx, "host_call request exceeds max_request_bytes"); ++ return -1; ++ } ++ ++ if (req_len > (size_t)dv_limit) { ++ JS_ThrowTypeError(ctx, "host_call request exceeds DV limit"); ++ return -1; ++ } ++ ++ if (req_len > UINT32_MAX) { ++ JS_ThrowTypeError(ctx, "host_call request length overflow"); ++ return -1; ++ } ++ ++ if (req_len > 0 && !req_bytes) { ++ JS_ThrowTypeError(ctx, "host_call request pointer is null"); ++ return -1; ++ } ++ ++ if (js_runtime_in_host_call(rt)) { ++ JS_ThrowTypeError(ctx, "host_call is already in progress"); ++ return -1; ++ } ++ ++ resp_capacity = max_response_bytes; ++ if (js_reserve_host_response_buffer(ctx, resp_capacity)) ++ return -1; ++ ++ resp_buf = js_get_host_response_buffer(ctx); ++ ++ js_runtime_set_in_host_call(rt, TRUE); ++ req_len32 = (uint32_t)req_len; ++ req_ptr = req_bytes ? req_bytes : NULL; ++ resp_len = host_call_func(ctx, fn_id, req_ptr, req_len32, ++ resp_buf, resp_capacity, ++ js_get_host_call_opaque(rt)); ++ js_runtime_set_in_host_call(rt, FALSE); ++ ++ if (JS_HasException(ctx)) ++ return -1; ++ ++ if (resp_len == JS_HOST_CALL_TRANSPORT_ERROR || resp_len > resp_capacity) { ++ JS_ThrowHostTransportError(ctx); ++ return -1; ++ } ++ ++ out_result->data = resp_buf; ++ out_result->length = resp_len; ++ return 0; ++} ++ + /* ------------------------------------------------------------------------- */ + /* Host manifest parsing and Host.v1 generation (T-040) */ + +diff --git a/quickjs-internal.h b/quickjs-internal.h +index 942ca08..05976cc 100644 +--- a/quickjs-internal.h ++++ b/quickjs-internal.h +@@ -1,6 +1,7 @@ + #ifndef QUICKJS_INTERNAL_H + #define QUICKJS_INTERNAL_H + ++#include "quickjs.h" + #include + #include + +@@ -8,4 +9,33 @@ + void js_sha256(const uint8_t *data, size_t len, uint8_t out_hash[32]); + void js_sha256_to_hex(const uint8_t hash[32], char out_hex[65]); + ++typedef JSValue (*JSCompileRegExpFunc)(JSContext *ctx, JSValueConst pattern, ++ JSValueConst flags); ++ ++void *js_malloc_rt(JSRuntime *rt, size_t size); ++void js_free_rt(JSRuntime *rt, void *ptr); ++ ++void js_deterministic_clear_eval_obj(JSContext *ctx); ++void js_deterministic_set_regexp(JSContext *ctx, JSValueConst ctor, JSCompileRegExpFunc func); ++void js_deterministic_set_promise_ctor(JSContext *ctx, JSValueConst ctor); ++void js_deterministic_set_random_state(JSContext *ctx, uint32_t state); ++void js_deterministic_set_mode(JSContext *ctx, JS_BOOL enabled); ++JS_BOOL js_deterministic_manifest_is_initialized(JSContext *ctx); ++void js_deterministic_set_manifest_state(JSContext *ctx, ++ uint8_t *manifest_bytes, ++ size_t manifest_size, ++ const uint8_t hash[32], ++ const char hash_hex[65], ++ uint8_t *context_blob, ++ size_t context_blob_size); ++ ++int js_deterministic_init_context(JSContext *ctx); ++ ++int js_reserve_host_response_buffer(JSContext *ctx, uint32_t capacity); ++uint8_t *js_get_host_response_buffer(JSContext *ctx); ++JSHostCallFunc *js_get_host_call_func(JSRuntime *rt); ++void *js_get_host_call_opaque(JSRuntime *rt); ++JS_BOOL js_runtime_in_host_call(JSRuntime *rt); ++void js_runtime_set_in_host_call(JSRuntime *rt, JS_BOOL in_call); ++ + #endif /* QUICKJS_INTERNAL_H */ +diff --git a/quickjs.c b/quickjs.c +index 2d13d34..7e1da9e 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -2416,515 +2416,54 @@ JSContext *JS_NewContext(JSRuntime *rt) + return ctx; + } + +-enum { +- JS_DETERMINISTIC_DISABLED_EVAL = 1, +- JS_DETERMINISTIC_DISABLED_FUNCTION = 2, +- JS_DETERMINISTIC_DISABLED_RANDOM = 3, +- JS_DETERMINISTIC_DISABLED_PROMISE = 4, +- JS_DETERMINISTIC_DISABLED_REGEXP = 5, +- JS_DETERMINISTIC_DISABLED_PROXY = 6, +- JS_DETERMINISTIC_DISABLED_TYPED_ARRAY = 7, +- JS_DETERMINISTIC_DISABLED_ARRAY_BUFFER = 8, +- JS_DETERMINISTIC_DISABLED_SHARED_ARRAY_BUFFER = 9, +- JS_DETERMINISTIC_DISABLED_DATAVIEW = 10, +- JS_DETERMINISTIC_DISABLED_WEBASSEMBLY = 11, +- JS_DETERMINISTIC_DISABLED_ATOMICS = 12, +- JS_DETERMINISTIC_DISABLED_CONSOLE = 13, +- JS_DETERMINISTIC_DISABLED_PRINT = 14, +- JS_DETERMINISTIC_DISABLED_JSON_PARSE = 15, +- JS_DETERMINISTIC_DISABLED_JSON_STRINGIFY = 16, +- JS_DETERMINISTIC_DISABLED_ARRAY_SORT = 17, +-}; +- +-static const char *js_get_disabled_name(int magic) ++void js_deterministic_clear_eval_obj(JSContext *ctx) + { +- switch (magic) { +- case JS_DETERMINISTIC_DISABLED_ARRAY_SORT: +- return "Array.prototype.sort"; +- case JS_DETERMINISTIC_DISABLED_JSON_STRINGIFY: +- return "JSON.stringify"; +- case JS_DETERMINISTIC_DISABLED_JSON_PARSE: +- return "JSON.parse"; +- case JS_DETERMINISTIC_DISABLED_PRINT: +- return "print"; +- case JS_DETERMINISTIC_DISABLED_CONSOLE: +- return "console"; +- case JS_DETERMINISTIC_DISABLED_ATOMICS: +- return "Atomics"; +- case JS_DETERMINISTIC_DISABLED_WEBASSEMBLY: +- return "WebAssembly"; +- case JS_DETERMINISTIC_DISABLED_DATAVIEW: +- return "DataView"; +- case JS_DETERMINISTIC_DISABLED_SHARED_ARRAY_BUFFER: +- return "SharedArrayBuffer"; +- case JS_DETERMINISTIC_DISABLED_ARRAY_BUFFER: +- return "ArrayBuffer"; +- case JS_DETERMINISTIC_DISABLED_TYPED_ARRAY: +- return "Typed arrays"; +- case JS_DETERMINISTIC_DISABLED_PROXY: +- return "Proxy"; +- case JS_DETERMINISTIC_DISABLED_REGEXP: +- return "RegExp"; +- case JS_DETERMINISTIC_DISABLED_PROMISE: +- return "Promise"; +- case JS_DETERMINISTIC_DISABLED_RANDOM: +- return "Math.random"; +- case JS_DETERMINISTIC_DISABLED_FUNCTION: +- return "Function"; +- case JS_DETERMINISTIC_DISABLED_EVAL: +- default: +- return "eval"; +- } +-} +- +-static JSValue js_deterministic_disabled(JSContext *ctx, JSValueConst this_val, +- int argc, JSValueConst *argv, int magic) +-{ +- const char *name = js_get_disabled_name(magic); +- if (magic == JS_DETERMINISTIC_DISABLED_TYPED_ARRAY) +- return JS_ThrowTypeError(ctx, "%s are disabled in deterministic mode", name); +- return JS_ThrowTypeError(ctx, "%s is disabled in deterministic mode", name); +-} +- +-static int js_deterministic_define_disabled_global(JSContext *ctx, const char *name, +- int length, int magic) +-{ +- JSValue fn; +- int ret; +- +- fn = JS_NewCFunctionMagic(ctx, js_deterministic_disabled, name, length, +- JS_CFUNC_constructor_or_func_magic, magic); +- if (JS_IsException(fn)) +- return -1; +- +- ret = JS_DefinePropertyValueStr(ctx, ctx->global_obj, name, JS_DupValue(ctx, fn), +- JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | +- JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); +- JS_FreeValue(ctx, fn); +- if (ret < 0) +- return -1; +- +- return 0; +-} +- +-static JSValue js_deterministic_compile_regexp(JSContext *ctx, JSValueConst pattern, +- JSValueConst flags) +-{ +- (void)pattern; +- (void)flags; +- return JS_ThrowTypeError(ctx, "RegExp is disabled in deterministic mode"); +-} +- +-static int js_deterministic_disable_eval(JSContext *ctx) +-{ +- JSValue fn; +- int ret; +- +- fn = JS_NewCFunctionMagic(ctx, js_deterministic_disabled, "eval", 1, +- JS_CFUNC_generic_magic, JS_DETERMINISTIC_DISABLED_EVAL); +- if (JS_IsException(fn)) +- return -1; +- +- ret = JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_eval, JS_DupValue(ctx, fn), +- JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | +- JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); +- if (ret < 0) { +- JS_FreeValue(ctx, fn); +- return -1; +- } +- + JS_FreeValue(ctx, ctx->eval_obj); + ctx->eval_obj = JS_UNDEFINED; +- JS_FreeValue(ctx, fn); +- return 0; + } + +-static int js_deterministic_disable_function(JSContext *ctx) ++void js_deterministic_set_regexp(JSContext *ctx, JSValueConst ctor, JSCompileRegExpFunc compile_regexp) + { +- JSValue fn; +- int ret; +- +- fn = JS_NewCFunctionMagic(ctx, js_deterministic_disabled, "Function", 1, +- JS_CFUNC_constructor_or_func_magic, JS_DETERMINISTIC_DISABLED_FUNCTION); +- if (JS_IsException(fn)) +- return -1; +- +- ret = JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_Function, JS_DupValue(ctx, fn), +- JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | +- JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); +- JS_FreeValue(ctx, fn); +- if (ret < 0) +- return -1; +- +- return 0; +-} +- +-static int js_deterministic_disable_random(JSContext *ctx) +-{ +- JSValue math, fn; +- int ret; +- +- math = JS_GetProperty(ctx, ctx->global_obj, JS_ATOM_Math); +- if (JS_IsException(math)) +- return -1; +- if (!JS_IsObject(math)) { +- JS_FreeValue(ctx, math); +- return -1; +- } +- +- fn = JS_NewCFunctionMagic(ctx, js_deterministic_disabled, "random", 0, +- JS_CFUNC_generic_magic, JS_DETERMINISTIC_DISABLED_RANDOM); +- if (JS_IsException(fn)) { +- JS_FreeValue(ctx, math); +- return -1; +- } +- +- ret = JS_DefinePropertyValueStr(ctx, math, "random", JS_DupValue(ctx, fn), +- JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | +- JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); +- +- JS_FreeValue(ctx, fn); +- JS_FreeValue(ctx, math); +- if (ret < 0) +- return -1; +- +- return 0; +-} +- +-static int js_deterministic_disable_regexp(JSContext *ctx) +-{ +- JSValue fn; +- int ret; +- +- fn = JS_NewCFunctionMagic(ctx, js_deterministic_disabled, "RegExp", 2, +- JS_CFUNC_constructor_or_func_magic, JS_DETERMINISTIC_DISABLED_REGEXP); +- if (JS_IsException(fn)) +- return -1; +- +- ret = JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_RegExp, JS_DupValue(ctx, fn), +- JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | +- JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); +- if (ret < 0) { +- JS_FreeValue(ctx, fn); +- return -1; +- } +- + JS_FreeValue(ctx, ctx->regexp_ctor); +- ctx->regexp_ctor = JS_DupValue(ctx, fn); +- ctx->compile_regexp = js_deterministic_compile_regexp; +- +- JS_FreeValue(ctx, fn); +- return 0; ++ ctx->regexp_ctor = JS_DupValue(ctx, ctor); ++ ctx->compile_regexp = compile_regexp; + } + +-static int js_deterministic_disable_proxy(JSContext *ctx) ++void js_deterministic_set_promise_ctor(JSContext *ctx, JSValueConst ctor) + { +- JSValue fn; +- int ret; +- +- fn = JS_NewCFunctionMagic(ctx, js_deterministic_disabled, "Proxy", 2, +- JS_CFUNC_constructor_or_func_magic, JS_DETERMINISTIC_DISABLED_PROXY); +- if (JS_IsException(fn)) +- return -1; +- +- ret = JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_Proxy, JS_DupValue(ctx, fn), +- JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | +- JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); +- JS_FreeValue(ctx, fn); +- if (ret < 0) +- return -1; +- +- return 0; +-} +- +-static int js_deterministic_disable_promise(JSContext *ctx) +-{ +- JSValue fn; +- int ret; +- +- fn = JS_NewCFunctionMagic(ctx, js_deterministic_disabled, "Promise", 1, +- JS_CFUNC_constructor_or_func_magic, JS_DETERMINISTIC_DISABLED_PROMISE); +- if (JS_IsException(fn)) +- return -1; +- +- ret = JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_Promise, JS_DupValue(ctx, fn), +- JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | +- JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); +- +- /* Ensure async internals see the disabled ctor */ + JS_FreeValue(ctx, ctx->promise_ctor); +- ctx->promise_ctor = JS_DupValue(ctx, fn); +- +- /* Mirror common Promise statics to the same disabled stub */ +- JS_DefinePropertyValueStr(ctx, fn, "resolve", JS_DupValue(ctx, fn), +- JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | +- JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); +- JS_DefinePropertyValueStr(ctx, fn, "reject", JS_DupValue(ctx, fn), +- JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | +- JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); +- JS_DefinePropertyValueStr(ctx, fn, "all", JS_DupValue(ctx, fn), +- JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | +- JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); +- JS_DefinePropertyValueStr(ctx, fn, "race", JS_DupValue(ctx, fn), +- JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | +- JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); +- JS_DefinePropertyValueStr(ctx, fn, "any", JS_DupValue(ctx, fn), +- JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | +- JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); +- JS_DefinePropertyValueStr(ctx, fn, "allSettled", JS_DupValue(ctx, fn), +- JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | +- JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); +- +- JS_FreeValue(ctx, fn); +- if (ret < 0) +- return -1; +- +- return 0; ++ ctx->promise_ctor = JS_DupValue(ctx, ctor); + } + +-static int js_deterministic_disable_typed_arrays(JSContext *ctx) ++void js_deterministic_set_random_state(JSContext *ctx, uint32_t state) + { +- static const struct { +- const char *name; +- int length; +- int magic; +- } entries[] = { +- { "ArrayBuffer", 1, JS_DETERMINISTIC_DISABLED_ARRAY_BUFFER }, +- { "SharedArrayBuffer", 1, JS_DETERMINISTIC_DISABLED_SHARED_ARRAY_BUFFER }, +- { "DataView", 3, JS_DETERMINISTIC_DISABLED_DATAVIEW }, +- { "Uint8Array", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, +- { "Uint8ClampedArray", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, +- { "Int8Array", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, +- { "Uint16Array", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, +- { "Int16Array", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, +- { "Uint32Array", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, +- { "Int32Array", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, +- { "BigInt64Array", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, +- { "BigUint64Array", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, +- { "Float16Array", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, +- { "Float32Array", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, +- { "Float64Array", 3, JS_DETERMINISTIC_DISABLED_TYPED_ARRAY }, +- }; +- +- for (size_t i = 0; i < countof(entries); i++) { +- if (js_deterministic_define_disabled_global(ctx, entries[i].name, +- entries[i].length, entries[i].magic)) +- return -1; +- } +- return 0; ++ ctx->random_state = state; + } + +-static int js_deterministic_disable_webassembly(JSContext *ctx) ++void js_deterministic_set_mode(JSContext *ctx, BOOL enabled) + { +- return js_deterministic_define_disabled_global(ctx, "WebAssembly", 1, +- JS_DETERMINISTIC_DISABLED_WEBASSEMBLY); ++ ctx->deterministic_mode = enabled ? TRUE : FALSE; + } + +-static int js_deterministic_disable_atomics(JSContext *ctx) ++BOOL js_deterministic_manifest_is_initialized(JSContext *ctx) + { +- return js_deterministic_define_disabled_global(ctx, "Atomics", 3, +- JS_DETERMINISTIC_DISABLED_ATOMICS); ++ return ctx->abi_manifest_bytes != NULL; + } + +-static int js_deterministic_disable_console(JSContext *ctx) ++void js_deterministic_set_manifest_state(JSContext *ctx, ++ uint8_t *manifest_bytes, ++ size_t manifest_size, ++ const uint8_t hash[32], ++ const char hash_hex[65], ++ uint8_t *context_blob, ++ size_t context_blob_size) + { +- JSValue console; +- +- console = JS_NewObjectProto(ctx, JS_NULL); +- if (JS_IsException(console)) +- return -1; +- +- static const char *const methods[] = { "log", "info", "warn", "error", "debug" }; +- for (size_t i = 0; i < countof(methods); i++) { +- JSValue fn = JS_NewCFunctionMagic(ctx, js_deterministic_disabled, "console", 1, +- JS_CFUNC_generic_magic, JS_DETERMINISTIC_DISABLED_CONSOLE); +- if (JS_IsException(fn)) { +- JS_FreeValue(ctx, console); +- return -1; +- } +- if (JS_DefinePropertyValueStr(ctx, console, methods[i], JS_DupValue(ctx, fn), +- JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | +- JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE) < 0) { +- JS_FreeValue(ctx, fn); +- JS_FreeValue(ctx, console); +- return -1; +- } +- JS_FreeValue(ctx, fn); +- } +- +- if (JS_DefinePropertyValueStr(ctx, ctx->global_obj, "console", JS_DupValue(ctx, console), +- JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | +- JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE) < 0) { +- JS_FreeValue(ctx, console); +- return -1; +- } +- +- JS_FreeValue(ctx, console); +- return 0; +-} +- +-static int js_deterministic_disable_print(JSContext *ctx) +-{ +- return js_deterministic_define_disabled_global(ctx, "print", 1, +- JS_DETERMINISTIC_DISABLED_PRINT); +-} +- +-static int js_deterministic_disable_json(JSContext *ctx) +-{ +- JSValue json, parse_fn, stringify_fn; +- int ret; +- +- json = JS_GetProperty(ctx, ctx->global_obj, JS_ATOM_JSON); +- if (JS_IsException(json)) +- return -1; +- if (!JS_IsObject(json)) { +- JS_FreeValue(ctx, json); +- return -1; +- } +- +- parse_fn = JS_NewCFunctionMagic(ctx, js_deterministic_disabled, "parse", 2, +- JS_CFUNC_generic_magic, JS_DETERMINISTIC_DISABLED_JSON_PARSE); +- if (JS_IsException(parse_fn)) { +- JS_FreeValue(ctx, json); +- return -1; +- } +- stringify_fn = JS_NewCFunctionMagic(ctx, js_deterministic_disabled, "stringify", 3, +- JS_CFUNC_generic_magic, JS_DETERMINISTIC_DISABLED_JSON_STRINGIFY); +- if (JS_IsException(stringify_fn)) { +- JS_FreeValue(ctx, parse_fn); +- JS_FreeValue(ctx, json); +- return -1; +- } +- +- ret = JS_DefinePropertyValueStr(ctx, json, "parse", JS_DupValue(ctx, parse_fn), +- JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | +- JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); +- if (ret < 0) +- goto fail; +- +- ret = JS_DefinePropertyValueStr(ctx, json, "stringify", JS_DupValue(ctx, stringify_fn), +- JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | +- JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); +- if (ret < 0) +- goto fail; +- +- JS_FreeValue(ctx, parse_fn); +- JS_FreeValue(ctx, stringify_fn); +- JS_FreeValue(ctx, json); +- return 0; +- +-fail: +- JS_FreeValue(ctx, parse_fn); +- JS_FreeValue(ctx, stringify_fn); +- JS_FreeValue(ctx, json); +- return -1; +-} +- +-static int js_deterministic_disable_array_sort(JSContext *ctx) +-{ +- JSValue array_ctor, array_proto, sort_fn; +- int ret; +- +- array_ctor = JS_GetProperty(ctx, ctx->global_obj, JS_ATOM_Array); +- if (JS_IsException(array_ctor)) +- return -1; +- if (!JS_IsObject(array_ctor)) { +- JS_FreeValue(ctx, array_ctor); +- return -1; +- } +- +- array_proto = JS_GetProperty(ctx, array_ctor, JS_ATOM_prototype); +- if (JS_IsException(array_proto)) { +- JS_FreeValue(ctx, array_ctor); +- return -1; +- } +- JS_FreeValue(ctx, array_ctor); +- if (!JS_IsObject(array_proto)) { +- JS_FreeValue(ctx, array_proto); +- return -1; +- } +- +- sort_fn = JS_NewCFunctionMagic(ctx, js_deterministic_disabled, "sort", 1, +- JS_CFUNC_generic_magic, JS_DETERMINISTIC_DISABLED_ARRAY_SORT); +- if (JS_IsException(sort_fn)) { +- JS_FreeValue(ctx, array_proto); +- return -1; +- } +- +- ret = JS_DefinePropertyValueStr(ctx, array_proto, "sort", JS_DupValue(ctx, sort_fn), +- JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | +- JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); +- +- JS_FreeValue(ctx, sort_fn); +- JS_FreeValue(ctx, array_proto); +- if (ret < 0) +- return -1; +- return 0; +-} +- +-static int js_deterministic_init_host(JSContext *ctx) +-{ +- JSValue host_ns, host_v1; +- int ret; +- +- host_ns = JS_NewObjectProto(ctx, JS_NULL); +- if (JS_IsException(host_ns)) +- return -1; +- +- host_v1 = JS_NewObjectProto(ctx, JS_NULL); +- if (JS_IsException(host_v1)) { +- JS_FreeValue(ctx, host_ns); +- return -1; +- } +- +- ret = JS_DefinePropertyValueStr(ctx, host_ns, "v1", JS_DupValue(ctx, host_v1), +- JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | +- JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); +- if (ret < 0) +- goto fail; +- +- ret = JS_DefinePropertyValueStr(ctx, ctx->global_obj, "Host", JS_DupValue(ctx, host_ns), +- JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | +- JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); +- if (ret < 0) +- goto fail; +- +- JS_FreeValue(ctx, host_ns); +- JS_FreeValue(ctx, host_v1); +- +- return 0; +- +-fail: +- JS_FreeValue(ctx, host_ns); +- JS_FreeValue(ctx, host_v1); +- return -1; +-} +- +-static int js_deterministic_init_context(JSContext *ctx) +-{ +- if (JS_AddIntrinsicBaseObjects(ctx) || +- JS_AddIntrinsicEval(ctx) || +- JS_AddIntrinsicJSON(ctx) || +- JS_AddIntrinsicMapSet(ctx) || +- js_deterministic_disable_eval(ctx) || +- js_deterministic_disable_function(ctx) || +- js_deterministic_disable_regexp(ctx) || +- js_deterministic_disable_proxy(ctx) || +- js_deterministic_disable_random(ctx) || +- js_deterministic_disable_promise(ctx) || +- js_deterministic_disable_typed_arrays(ctx) || +- js_deterministic_disable_atomics(ctx) || +- js_deterministic_disable_console(ctx) || +- js_deterministic_disable_print(ctx) || +- js_deterministic_disable_json(ctx) || +- js_deterministic_disable_array_sort(ctx) || +- js_deterministic_disable_webassembly(ctx) || +- js_deterministic_init_host(ctx)) { +- return -1; +- } +- ctx->random_state = 1; /* deterministic seed */ +- ctx->deterministic_mode = TRUE; +- return 0; ++ memcpy(ctx->abi_manifest_hash, hash, sizeof(ctx->abi_manifest_hash)); ++ memcpy(ctx->abi_manifest_hash_hex, hash_hex, sizeof(ctx->abi_manifest_hash_hex)); ++ ctx->abi_manifest_bytes = manifest_bytes; ++ ctx->abi_manifest_size = manifest_size; ++ ctx->deterministic_context_blob = context_blob; ++ ctx->deterministic_context_blob_size = context_blob ? context_blob_size : 0; + } + + #ifdef __EMSCRIPTEN__ +@@ -2990,168 +2529,7 @@ int JS_NewDeterministicRuntime(JSRuntime **out_rt, JSContext **out_ctx) + return 0; + } + +-static JSValue JS_ThrowManifestError(JSContext *ctx, const char *code, const char *message) +-{ +- JSValue obj, name, msg, code_val; +- +- obj = JS_NewError(ctx); +- if (JS_IsException(obj)) +- return JS_EXCEPTION; +- +- name = JS_NewString(ctx, "ManifestError"); +- msg = JS_NewString(ctx, message); +- code_val = JS_NewString(ctx, code); +- if (JS_IsException(name) || JS_IsException(msg) || JS_IsException(code_val)) { +- if (!JS_IsException(name)) +- JS_FreeValue(ctx, name); +- if (!JS_IsException(msg)) +- JS_FreeValue(ctx, msg); +- if (!JS_IsException(code_val)) +- JS_FreeValue(ctx, code_val); +- JS_FreeValue(ctx, obj); +- return JS_EXCEPTION; +- } +- +- JS_DefinePropertyValue(ctx, obj, JS_ATOM_name, name, +- JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); +- JS_DefinePropertyValue(ctx, obj, JS_ATOM_message, msg, +- JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); +- JS_DefinePropertyValueStr(ctx, obj, "code", code_val, +- JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); +- JS_Throw(ctx, obj); +- return JS_EXCEPTION; +-} +- +-static int js_hex_nibble(int c) +-{ +- if (c >= '0' && c <= '9') +- return c - '0'; +- if (c >= 'a' && c <= 'f') +- return c - 'a' + 10; +- return -1; +-} +- +-static int js_parse_hash_hex(JSContext *ctx, const char *hex, uint8_t *out, size_t out_size) +-{ +- size_t hex_len, i; +- +- if (!hex || !out) +- return -1; +- +- hex_len = strlen(hex); +- if (hex_len != out_size * 2) { +- JS_ThrowTypeError(ctx, "abi manifest hash must be 64 lowercase hex characters"); +- return -1; +- } +- +- for(i = 0; i < out_size; i++) { +- int high = js_hex_nibble(hex[i * 2]); +- int low = js_hex_nibble(hex[i * 2 + 1]); +- if (high < 0 || low < 0) { +- JS_ThrowTypeError(ctx, "abi manifest hash must be 64 lowercase hex characters"); +- return -1; +- } +- out[i] = (uint8_t)((high << 4) | low); +- } +- +- return 0; +-} +- +-int JS_InitDeterministicContext(JSContext *ctx, const JSDeterministicInitOptions *options) +-{ +- uint8_t computed_hash[32]; +- uint8_t expected_hash[32]; +- uint8_t *manifest_copy = NULL; +- uint8_t *context_copy = NULL; +- +- if (!ctx || !options) +- return -1; +- +- if (ctx->abi_manifest_bytes) { +- JS_ThrowTypeError(ctx, "abi manifest is already initialized"); +- return -1; +- } +- +- if (!options->manifest_bytes || options->manifest_size == 0) { +- JS_ThrowTypeError(ctx, "abi manifest is required"); +- return -1; +- } +- +- if (options->manifest_size > JS_DETERMINISTIC_MAX_MANIFEST_BYTES) { +- JS_ThrowTypeError(ctx, "abi manifest exceeds maximum size"); +- return -1; +- } +- +- if (!options->manifest_hash_hex) { +- JS_ThrowTypeError(ctx, "abi manifest hash is required"); +- return -1; +- } +- +- if (js_parse_hash_hex(ctx, options->manifest_hash_hex, expected_hash, sizeof(expected_hash)) != 0) +- return -1; +- +- if (options->context_blob_size > 0 && !options->context_blob) { +- JS_ThrowTypeError(ctx, "context blob is required when context_blob_size is set"); +- return -1; +- } +- +- js_sha256(options->manifest_bytes, options->manifest_size, computed_hash); +- if (memcmp(computed_hash, expected_hash, sizeof(expected_hash)) != 0) { +- JS_ThrowManifestError(ctx, "ABI_MANIFEST_HASH_MISMATCH", "abi manifest hash mismatch"); +- return -1; +- } +- +- manifest_copy = js_malloc_rt(ctx->rt, options->manifest_size); +- if (!manifest_copy) { +- JS_ThrowOutOfMemory(ctx); +- return -1; +- } +- memcpy(manifest_copy, options->manifest_bytes, options->manifest_size); +- +- if (options->context_blob && options->context_blob_size > 0) { +- if (options->context_blob_size > JS_DETERMINISTIC_MAX_CONTEXT_BLOB_BYTES) { +- js_free_rt(ctx->rt, manifest_copy); +- JS_ThrowTypeError(ctx, "context blob exceeds maximum size"); +- return -1; +- } +- +- context_copy = js_malloc_rt(ctx->rt, options->context_blob_size); +- if (!context_copy) { +- js_free_rt(ctx->rt, manifest_copy); +- JS_ThrowOutOfMemory(ctx); +- return -1; +- } +- memcpy(context_copy, options->context_blob, options->context_blob_size); +- } +- +- if (JS_InitHostFromManifest(ctx, manifest_copy, options->manifest_size) != 0) { +- js_free_rt(ctx->rt, manifest_copy); +- if (context_copy) +- js_free_rt(ctx->rt, context_copy); +- return -1; +- } +- +- if (context_copy && options->context_blob_size > 0) { +- if (JS_InitErgonomicGlobals(ctx, context_copy, options->context_blob_size) != 0) { +- JS_FreeHostManifest(ctx); +- js_free_rt(ctx->rt, manifest_copy); +- js_free_rt(ctx->rt, context_copy); +- return -1; +- } +- } +- +- memcpy(ctx->abi_manifest_hash, computed_hash, sizeof(computed_hash)); +- js_sha256_to_hex(computed_hash, ctx->abi_manifest_hash_hex); +- ctx->abi_manifest_bytes = manifest_copy; +- ctx->abi_manifest_size = options->manifest_size; +- ctx->deterministic_context_blob = context_copy; +- ctx->deterministic_context_blob_size = context_copy ? options->context_blob_size : 0; +- JS_SetGasLimit(ctx, options->gas_limit); +- +- return 0; +-} +- +-static int js_reserve_host_response_buffer(JSContext *ctx, uint32_t capacity) ++int js_reserve_host_response_buffer(JSContext *ctx, uint32_t capacity) + { + uint8_t *new_buf; + +@@ -3169,106 +2547,29 @@ static int js_reserve_host_response_buffer(JSContext *ctx, uint32_t capacity) + return 0; + } + +-int JS_HostCall(JSContext *ctx, +- uint32_t fn_id, +- const uint8_t *req_bytes, +- size_t req_len, +- uint32_t max_request_bytes, +- uint32_t max_response_bytes, +- JSHostCallResult *out_result) ++uint8_t *js_get_host_response_buffer(JSContext *ctx) + { +- JSRuntime *rt; +- uint32_t resp_len, resp_capacity, req_len32; +- uint32_t dv_limit; +- const uint8_t *req_ptr; ++ return ctx->host_call_resp_buf; ++} + +- if (!ctx || !out_result) +- return -1; ++JSHostCallFunc *js_get_host_call_func(JSRuntime *rt) ++{ ++ return rt->host_call_func; ++} + +- out_result->data = NULL; +- out_result->length = 0; ++void *js_get_host_call_opaque(JSRuntime *rt) ++{ ++ return rt->host_call_opaque; ++} + +- rt = ctx->rt; +- dv_limit = JS_DV_LIMIT_DEFAULTS.max_encoded_bytes; ++BOOL js_runtime_in_host_call(JSRuntime *rt) ++{ ++ return rt->in_host_call; ++} + +- if (!rt->host_call_func) { +- JS_ThrowTypeError(ctx, "host_call dispatcher is not configured"); +- return -1; +- } +- +- if (fn_id == 0) { +- JS_ThrowTypeError(ctx, "host_call fn_id must be >= 1"); +- return -1; +- } +- +- if (max_request_bytes == 0) { +- JS_ThrowTypeError(ctx, "host_call max_request_bytes must be > 0"); +- return -1; +- } +- +- if (max_request_bytes > dv_limit) { +- JS_ThrowTypeError(ctx, "host_call max_request_bytes exceeds DV limit"); +- return -1; +- } +- +- if (max_response_bytes == 0) { +- JS_ThrowTypeError(ctx, "host_call max_response_bytes must be > 0"); +- return -1; +- } +- +- if (max_response_bytes > dv_limit) { +- JS_ThrowTypeError(ctx, "host_call max_response_bytes exceeds DV limit"); +- return -1; +- } +- +- if (req_len > (size_t)max_request_bytes) { +- JS_ThrowTypeError(ctx, "host_call request exceeds max_request_bytes"); +- return -1; +- } +- +- if (req_len > (size_t)dv_limit) { +- JS_ThrowTypeError(ctx, "host_call request exceeds DV limit"); +- return -1; +- } +- +- if (req_len > UINT32_MAX) { +- JS_ThrowTypeError(ctx, "host_call request length overflow"); +- return -1; +- } +- +- if (req_len > 0 && !req_bytes) { +- JS_ThrowTypeError(ctx, "host_call request pointer is null"); +- return -1; +- } +- +- if (rt->in_host_call) { +- JS_ThrowTypeError(ctx, "host_call is already in progress"); +- return -1; +- } +- +- resp_capacity = max_response_bytes; +- if (js_reserve_host_response_buffer(ctx, resp_capacity)) +- return -1; +- +- rt->in_host_call = TRUE; +- req_len32 = (uint32_t)req_len; +- req_ptr = req_bytes ? req_bytes : NULL; +- resp_len = rt->host_call_func(ctx, fn_id, req_ptr, req_len32, +- ctx->host_call_resp_buf, resp_capacity, +- rt->host_call_opaque); +- rt->in_host_call = FALSE; +- +- if (JS_HasException(ctx)) +- return -1; +- +- if (resp_len == JS_HOST_CALL_TRANSPORT_ERROR || resp_len > resp_capacity) { +- JS_ThrowHostTransportError(ctx); +- return -1; +- } +- +- out_result->data = ctx->host_call_resp_buf; +- out_result->length = resp_len; +- return 0; ++void js_runtime_set_in_host_call(JSRuntime *rt, BOOL in_call) ++{ ++ rt->in_host_call = in_call ? TRUE : FALSE; + } + + void *JS_GetContextOpaque(JSContext *ctx) diff --git a/vendor/quickjs-patches/series/0026-feat-runtime-expose-current-contract-globals-when-de.patch b/vendor/quickjs-patches/series/0026-feat-runtime-expose-current-contract-globals-when-de.patch new file mode 100644 index 0000000..69e4273 --- /dev/null +++ b/vendor/quickjs-patches/series/0026-feat-runtime-expose-current-contract-globals-when-de.patch @@ -0,0 +1,130 @@ +From 33353d1be1464c8195cf58873e22e5170023ba31 Mon Sep 17 00:00:00 2001 +From: Mateusz Jonak +Date: Thu, 15 Jan 2026 15:10:57 +0100 +Subject: [PATCH 26/51] feat(runtime): expose current contract globals when + decoding context + +--- + quickjs-host.c | 49 +++++++++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 45 insertions(+), 4 deletions(-) + +diff --git a/quickjs-host.c b/quickjs-host.c +index 4865db0..f13fe05 100644 +--- a/quickjs-host.c ++++ b/quickjs-host.c +@@ -3295,20 +3295,27 @@ static int js_decode_context_blob(JSContext *ctx, + size_t context_blob_size, + JSValue *out_event, + JSValue *out_event_canonical, +- JSValue *out_steps) ++ JSValue *out_steps, ++ JSValue *out_current_contract, ++ JSValue *out_current_contract_canonical) + { + JSValue decoded = JS_UNDEFINED; + JSAtom event_atom = JS_ATOM_NULL; + JSAtom event_canonical_atom = JS_ATOM_NULL; + JSAtom steps_atom = JS_ATOM_NULL; ++ JSAtom current_contract_atom = JS_ATOM_NULL; ++ JSAtom current_contract_canonical_atom = JS_ATOM_NULL; + int ret = -1; + +- if (!out_event || !out_event_canonical || !out_steps) ++ if (!out_event || !out_event_canonical || !out_steps || ++ !out_current_contract || !out_current_contract_canonical) + return -1; + + *out_event = JS_NULL; + *out_event_canonical = JS_NULL; + *out_steps = JS_NULL; ++ *out_current_contract = JS_NULL; ++ *out_current_contract_canonical = JS_NULL; + + if (!context_blob || context_blob_size == 0) + return 0; +@@ -3326,7 +3333,11 @@ static int js_decode_context_blob(JSContext *ctx, + event_atom = JS_NewAtom(ctx, "event"); + event_canonical_atom = JS_NewAtom(ctx, "eventCanonical"); + steps_atom = JS_NewAtom(ctx, "steps"); +- if (event_atom == JS_ATOM_NULL || event_canonical_atom == JS_ATOM_NULL || steps_atom == JS_ATOM_NULL) ++ current_contract_atom = JS_NewAtom(ctx, "currentContract"); ++ current_contract_canonical_atom = JS_NewAtom(ctx, "currentContractCanonical"); ++ if (event_atom == JS_ATOM_NULL || event_canonical_atom == JS_ATOM_NULL || ++ steps_atom == JS_ATOM_NULL || current_contract_atom == JS_ATOM_NULL || ++ current_contract_canonical_atom == JS_ATOM_NULL) + goto done; + + if (js_context_copy_and_freeze(ctx, decoded, event_atom, out_event)) +@@ -3335,6 +3346,10 @@ static int js_decode_context_blob(JSContext *ctx, + goto done; + if (js_context_copy_and_freeze(ctx, decoded, steps_atom, out_steps)) + goto done; ++ if (js_context_copy_and_freeze(ctx, decoded, current_contract_atom, out_current_contract)) ++ goto done; ++ if (js_context_copy_and_freeze(ctx, decoded, current_contract_canonical_atom, out_current_contract_canonical)) ++ goto done; + + ret = 0; + +@@ -3345,6 +3360,10 @@ done: + JS_FreeAtom(ctx, event_canonical_atom); + if (steps_atom != JS_ATOM_NULL) + JS_FreeAtom(ctx, steps_atom); ++ if (current_contract_atom != JS_ATOM_NULL) ++ JS_FreeAtom(ctx, current_contract_atom); ++ if (current_contract_canonical_atom != JS_ATOM_NULL) ++ JS_FreeAtom(ctx, current_contract_canonical_atom); + if (!JS_IsUndefined(decoded)) + JS_FreeValue(ctx, decoded); + return ret; +@@ -3618,6 +3637,8 @@ int JS_InitErgonomicGlobals(JSContext *ctx, const uint8_t *context_blob, size_t + JSValue event_val = JS_NULL; + JSValue event_canonical_val = JS_NULL; + JSValue steps_val = JS_NULL; ++ JSValue current_contract_val = JS_NULL; ++ JSValue current_contract_canonical_val = JS_NULL; + JSValueConst doc_funcs[1]; + JSValueConst emit_funcs[1]; + int ret = -1; +@@ -3630,7 +3651,9 @@ int JS_InitErgonomicGlobals(JSContext *ctx, const uint8_t *context_blob, size_t + return -1; + } + +- if (js_decode_context_blob(ctx, context_blob, context_blob_size, &event_val, &event_canonical_val, &steps_val)) ++ if (js_decode_context_blob(ctx, context_blob, context_blob_size, ++ &event_val, &event_canonical_val, &steps_val, ++ ¤t_contract_val, ¤t_contract_canonical_val)) + goto done; + + global = JS_GetGlobalObject(ctx); +@@ -3781,6 +3804,20 @@ int JS_InitErgonomicGlobals(JSContext *ctx, const uint8_t *context_blob, size_t + JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_CONFIGURABLE) < 0) + goto done; + ++ if (JS_DefinePropertyValueStr(ctx, ++ global, ++ "currentContract", ++ JS_DupValue(ctx, current_contract_val), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_CONFIGURABLE) < 0) ++ goto done; ++ ++ if (JS_DefinePropertyValueStr(ctx, ++ global, ++ "currentContractCanonical", ++ JS_DupValue(ctx, current_contract_canonical_val), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_CONFIGURABLE) < 0) ++ goto done; ++ + ret = 0; + + done: +@@ -3816,5 +3853,9 @@ done: + JS_FreeValue(ctx, event_canonical_val); + if (!JS_IsUndefined(steps_val)) + JS_FreeValue(ctx, steps_val); ++ if (!JS_IsUndefined(current_contract_val)) ++ JS_FreeValue(ctx, current_contract_val); ++ if (!JS_IsUndefined(current_contract_canonical_val)) ++ JS_FreeValue(ctx, current_contract_canonical_val); + return ret; + } diff --git a/vendor/quickjs-patches/series/0027-fix-dv-increase-max_encoded_bytes-and-max_context_bl.patch b/vendor/quickjs-patches/series/0027-fix-dv-increase-max_encoded_bytes-and-max_context_bl.patch new file mode 100644 index 0000000..2da8d48 --- /dev/null +++ b/vendor/quickjs-patches/series/0027-fix-dv-increase-max_encoded_bytes-and-max_context_bl.patch @@ -0,0 +1,39 @@ +From a4cdb804e812b27055e4ef5fd51cf18ea84655ed Mon Sep 17 00:00:00 2001 +From: Mateusz Jonak +Date: Mon, 16 Feb 2026 13:20:52 +0100 +Subject: [PATCH 27/51] fix(dv): increase max_encoded_bytes and + max_context_blob_bytes limits + +- Updated JS_DV_LIMIT_DEFAULTS to raise max_encoded_bytes from 1MB to 5MB. +- Adjusted JS_DETERMINISTIC_MAX_CONTEXT_BLOB_BYTES from 1MB to 5MB for improved performance and capacity. +--- + quickjs-dv.c | 2 +- + quickjs.h | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/quickjs-dv.c b/quickjs-dv.c +index 8314329..660e8fb 100644 +--- a/quickjs-dv.c ++++ b/quickjs-dv.c +@@ -1110,7 +1110,7 @@ void JS_FreeDVBuffer(JSContext *ctx, JSDvBuffer *buffer) { + + const JSDvLimits JS_DV_LIMIT_DEFAULTS = { + .max_depth = 64, +- .max_encoded_bytes = 1048576, ++ .max_encoded_bytes = 5242880, + .max_string_bytes = 262144, + .max_array_length = 65535, + .max_map_length = 65535, +diff --git a/quickjs.h b/quickjs.h +index 5c817d8..e933a6f 100644 +--- a/quickjs.h ++++ b/quickjs.h +@@ -344,7 +344,7 @@ static inline JSValue __JS_NewShortBigInt(JSContext *ctx, int64_t d) + #define JS_EVAL_FLAG_ASYNC (1 << 7) + + #define JS_DETERMINISTIC_MAX_MANIFEST_BYTES 1048576 +-#define JS_DETERMINISTIC_MAX_CONTEXT_BLOB_BYTES 1048576 ++#define JS_DETERMINISTIC_MAX_CONTEXT_BLOB_BYTES 5242880 + + typedef JSValue JSCFunction(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); + typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); diff --git a/vendor/quickjs-patches/series/0028-feat-det-json-add-deterministic-json-built-ins.patch b/vendor/quickjs-patches/series/0028-feat-det-json-add-deterministic-json-built-ins.patch new file mode 100644 index 0000000..5db544f --- /dev/null +++ b/vendor/quickjs-patches/series/0028-feat-det-json-add-deterministic-json-built-ins.patch @@ -0,0 +1,1618 @@ +From 6a6818a29187d30e57e017d52aed770354b403bb Mon Sep 17 00:00:00 2001 +From: Cursor Agent +Date: Thu, 12 Mar 2026 18:25:04 +0000 +Subject: [PATCH 28/51] feat(det-json): add deterministic JSON built-ins + +Install deterministic JSON.parse and JSON.stringify in deterministic mode +with strict validation and gas-aware limits. + +Validate strings and object keys, serialize only own data properties, and +enforce parse limits such as maxDepth without extra token allocation. + +Add deterministic JSON built-ins + +Extract deterministic JSON implementation + +fix(det-json): validate JSON strings and object keys + +Reject lone surrogate code points and enforce maxStringBytes consistently across +JSON.parse, JSON.stringify values, and object keys. + +fix(det-json): serialize only own data properties in JSON.stringify + +Reject accessor properties and guard against object properties changing during +serialization so deterministic JSON output cannot observe getters or unstable +object state. + +fix(det-json): enforce maxDepth before JSON.parse + +Pre-scan JSON input for nested arrays and objects while ignoring quoted +content so deterministic parsing rejects inputs beyond `maxDepth` before +QuickJS parses them. + +fix(det-json): preflight JSON.parse limits before parsing + +Validate depth, array/object counts, strings, numbers, and trailing tokens +with the JSON tokenizer before calling `JS_ParseJSON`. This enforces +deterministic limits earlier and avoids overflow or parser-stack failures +during post-parse validation. + +fix(det-json): validate JSON.parse strings without token allocation + +Enforce deterministic JSON string byte and surrogate checks in the tokenizer +preflight path so oversized or malformed strings fail before token +materialization and full parse allocation. +--- + quickjs-det-json.c | 1242 ++++++++++++++++++++++++++++++++++++++++++++ + quickjs-host.c | 67 +-- + quickjs-internal.h | 1 + + quickjs.c | 108 +++- + quickjs.h | 15 +- + 5 files changed, 1364 insertions(+), 69 deletions(-) + create mode 100644 quickjs-det-json.c + +diff --git a/quickjs-det-json.c b/quickjs-det-json.c +new file mode 100644 +index 0000000..7cdfcfb +--- /dev/null ++++ b/quickjs-det-json.c +@@ -0,0 +1,1242 @@ ++/* Deterministic JSON built-ins for deterministic mode only. ++ Included by quickjs.c so this implementation can reuse internal helpers ++ such as StringBuffer, string_getc(), js_get_length64(), and ++ JS_GetOwnPropertyNamesInternal() without widening the public/internal ++ header surface. */ ++ ++#define JS_GAS_JSON_PARSE_BASE 8 ++#define JS_GAS_JSON_PARSE_INPUT_BYTE 1 ++#define JS_GAS_JSON_PARSE_VALUE 3 ++#define JS_GAS_JSON_PARSE_OBJECT_ENTRY 2 ++#define JS_GAS_JSON_PARSE_ARRAY_ELEMENT 2 ++ ++#define JS_GAS_JSON_STRINGIFY_BASE 8 ++#define JS_GAS_JSON_STRINGIFY_VALUE 3 ++#define JS_GAS_JSON_STRINGIFY_OBJECT_ENTRY 2 ++#define JS_GAS_JSON_STRINGIFY_ARRAY_ELEMENT 2 ++#define JS_GAS_JSON_STRINGIFY_OUTPUT_BYTE 1 ++#define JS_GAS_JSON_STRINGIFY_SORT_COMPARISON 1 ++ ++typedef struct JSDetJSONStringifyKeyEntry { ++ JSAtom atom; ++ uint8_t *encoded_key; ++ size_t encoded_key_len; ++} JSDetJSONStringifyKeyEntry; ++ ++typedef struct JSDetJSONStringifyState { ++ StringBuffer *b; ++ JSObject **stack; ++ uint32_t stack_len; ++ uint32_t stack_cap; ++ uint64_t output_bytes; ++} JSDetJSONStringifyState; ++ ++static int js_det_json_add_u64(uint64_t *out, uint64_t a, uint64_t b) ++{ ++ if (a > UINT64_MAX - b) ++ return -1; ++ *out = a + b; ++ return 0; ++} ++ ++static int js_det_json_mul_u64(uint64_t *out, uint64_t a, uint64_t b) ++{ ++ if (a != 0 && b > UINT64_MAX / a) ++ return -1; ++ *out = a * b; ++ return 0; ++} ++ ++static int js_det_json_parse_add_count(JSContext *ctx, ++ uint64_t *total, ++ uint64_t amount, ++ const char *label) ++{ ++ if (js_det_json_add_u64(total, *total, amount) != 0) { ++ JS_ThrowTypeError(ctx, "JSON.parse %s overflow", label); ++ return -1; ++ } ++ return 0; ++} ++ ++static int js_det_json_parse_charge(JSContext *ctx, ++ uint64_t gas_cost, ++ BOOL count_call, ++ uint64_t input_bytes, ++ uint64_t value_count, ++ uint64_t object_entry_count, ++ uint64_t array_element_count) ++{ ++ if (JS_UseGas(ctx, gas_cost) != 0) ++ return -1; ++ js_gas_trace_record_json_parse(ctx, gas_cost, count_call, input_bytes, ++ value_count, object_entry_count, ++ array_element_count); ++ return 0; ++} ++ ++static int js_det_json_stringify_charge(JSContext *ctx, ++ uint64_t gas_cost, ++ BOOL count_call, ++ uint64_t output_bytes, ++ uint64_t value_count, ++ uint64_t object_entry_count, ++ uint64_t array_element_count, ++ uint64_t sort_comparison_count) ++{ ++ if (JS_UseGas(ctx, gas_cost) != 0) ++ return -1; ++ js_gas_trace_record_json_stringify(ctx, gas_cost, count_call, output_bytes, ++ value_count, object_entry_count, ++ array_element_count, ++ sort_comparison_count); ++ return 0; ++} ++ ++static int js_det_json_charge_units(JSContext *ctx, ++ uint64_t unit_cost, ++ uint64_t unit_count, ++ BOOL count_call, ++ uint64_t output_bytes, ++ uint64_t value_count, ++ uint64_t object_entry_count, ++ uint64_t array_element_count, ++ uint64_t sort_comparison_count) ++{ ++ uint64_t gas_cost; ++ ++ if (unit_count == 0) ++ return 0; ++ if (js_det_json_mul_u64(&gas_cost, unit_cost, unit_count) != 0) { ++ JS_ThrowTypeError(ctx, "JSON.stringify gas overflow"); ++ return -1; ++ } ++ return js_det_json_stringify_charge(ctx, gas_cost, count_call, output_bytes, ++ value_count, object_entry_count, ++ array_element_count, ++ sort_comparison_count); ++} ++ ++static int js_det_json_string_utf8_len(uint32_t c) ++{ ++ if (c < 0x80) ++ return 1; ++ if (c < 0x800) ++ return 2; ++ if (c < 0x10000) ++ return 3; ++ return 4; ++} ++ ++static int js_det_json_stringify_emit_ascii(JSContext *ctx, ++ JSDetJSONStringifyState *state, ++ const char *bytes, ++ size_t len) ++{ ++ uint64_t next_output_bytes; ++ ++ if (len == 0) ++ return 0; ++ if (js_det_json_add_u64(&next_output_bytes, state->output_bytes, len) != 0) { ++ JS_ThrowTypeError(ctx, "JSON.stringify output byte count overflow"); ++ return -1; ++ } ++ if (next_output_bytes > JS_DV_LIMIT_DEFAULTS.max_encoded_bytes) { ++ JS_ThrowTypeError(ctx, "JSON.stringify output exceeds maxOutputBytes (%" PRIu64 " > %u)", ++ next_output_bytes, JS_DV_LIMIT_DEFAULTS.max_encoded_bytes); ++ return -1; ++ } ++ if (js_det_json_charge_units(ctx, JS_GAS_JSON_STRINGIFY_OUTPUT_BYTE, len, ++ FALSE, len, 0, 0, 0, 0) != 0) { ++ return -1; ++ } ++ if (string_buffer_write8(state->b, (const uint8_t *)bytes, len) != 0) ++ return -1; ++ state->output_bytes = next_output_bytes; ++ return 0; ++} ++ ++static int js_det_json_stringify_emit_codepoint(JSContext *ctx, ++ JSDetJSONStringifyState *state, ++ uint32_t c) ++{ ++ uint64_t len = js_det_json_string_utf8_len(c); ++ uint64_t next_output_bytes; ++ ++ if (js_det_json_add_u64(&next_output_bytes, state->output_bytes, len) != 0) { ++ JS_ThrowTypeError(ctx, "JSON.stringify output byte count overflow"); ++ return -1; ++ } ++ if (next_output_bytes > JS_DV_LIMIT_DEFAULTS.max_encoded_bytes) { ++ JS_ThrowTypeError(ctx, "JSON.stringify output exceeds maxOutputBytes (%" PRIu64 " > %u)", ++ next_output_bytes, JS_DV_LIMIT_DEFAULTS.max_encoded_bytes); ++ return -1; ++ } ++ if (js_det_json_charge_units(ctx, JS_GAS_JSON_STRINGIFY_OUTPUT_BYTE, len, ++ FALSE, len, 0, 0, 0, 0) != 0) { ++ return -1; ++ } ++ if (string_buffer_putc(state->b, c) != 0) ++ return -1; ++ state->output_bytes = next_output_bytes; ++ return 0; ++} ++ ++static int js_det_json_prepare_string(JSContext *ctx, ++ JSValueConst value, ++ const char *label, ++ JSValue *out_str, ++ size_t *out_utf8_len) ++{ ++ JSValue str; ++ JSString *p; ++ const char *utf8 = NULL; ++ size_t utf8_len = 0; ++ ++ str = JS_ToStringCheckObject(ctx, value); ++ if (JS_IsException(str)) ++ return -1; ++ ++ p = JS_VALUE_GET_STRING(str); ++ if (js_string_find_invalid_codepoint(p) >= 0) { ++ JS_FreeValue(ctx, str); ++ JS_ThrowTypeError(ctx, "%s contains lone surrogate code points", label); ++ return -1; ++ } ++ ++ utf8 = JS_ToCStringLen(ctx, &utf8_len, str); ++ if (!utf8) { ++ JS_FreeValue(ctx, str); ++ return -1; ++ } ++ JS_FreeCString(ctx, utf8); ++ ++ if (utf8_len > JS_DV_LIMIT_DEFAULTS.max_string_bytes) { ++ JS_FreeValue(ctx, str); ++ JS_ThrowTypeError(ctx, "%s exceeds maxStringBytes (%zu > %u)", ++ label, utf8_len, JS_DV_LIMIT_DEFAULTS.max_string_bytes); ++ return -1; ++ } ++ ++ *out_str = str; ++ if (out_utf8_len) ++ *out_utf8_len = utf8_len; ++ return 0; ++} ++ ++static int js_det_json_validate_string(JSContext *ctx, ++ JSValueConst value, ++ const char *label) ++{ ++ JSValue str = JS_UNDEFINED; ++ int ret; ++ ++ ret = js_det_json_prepare_string(ctx, value, label, &str, NULL); ++ JS_FreeValue(ctx, str); ++ return ret; ++} ++ ++static int js_det_json_stringify_quote(JSContext *ctx, ++ JSDetJSONStringifyState *state, ++ JSValueConst value) ++{ ++ JSValue str = JS_UNDEFINED; ++ JSString *p; ++ int i; ++ uint32_t c; ++ char buf[16]; ++ ++ if (js_det_json_prepare_string(ctx, value, "JSON.stringify string", ++ &str, NULL) != 0) { ++ return -1; ++ } ++ ++ p = JS_VALUE_GET_STRING(str); ++ if (js_det_json_stringify_emit_ascii(ctx, state, "\"", 1) != 0) ++ goto fail; ++ for (i = 0; i < p->len; ) { ++ c = string_getc(p, &i); ++ switch (c) { ++ case '\t': ++ if (js_det_json_stringify_emit_ascii(ctx, state, "\\t", 2) != 0) ++ goto fail; ++ break; ++ case '\r': ++ if (js_det_json_stringify_emit_ascii(ctx, state, "\\r", 2) != 0) ++ goto fail; ++ break; ++ case '\n': ++ if (js_det_json_stringify_emit_ascii(ctx, state, "\\n", 2) != 0) ++ goto fail; ++ break; ++ case '\b': ++ if (js_det_json_stringify_emit_ascii(ctx, state, "\\b", 2) != 0) ++ goto fail; ++ break; ++ case '\f': ++ if (js_det_json_stringify_emit_ascii(ctx, state, "\\f", 2) != 0) ++ goto fail; ++ break; ++ case '\"': ++ if (js_det_json_stringify_emit_ascii(ctx, state, "\\\"", 2) != 0) ++ goto fail; ++ break; ++ case '\\': ++ if (js_det_json_stringify_emit_ascii(ctx, state, "\\\\", 2) != 0) ++ goto fail; ++ break; ++ default: ++ if (c < 32 || is_surrogate(c)) { ++ snprintf(buf, sizeof(buf), "\\u%04x", c); ++ if (js_det_json_stringify_emit_ascii(ctx, state, buf, 6) != 0) ++ goto fail; ++ } else if (js_det_json_stringify_emit_codepoint(ctx, state, c) != 0) { ++ goto fail; ++ } ++ break; ++ } ++ } ++ if (js_det_json_stringify_emit_ascii(ctx, state, "\"", 1) != 0) ++ goto fail; ++ ++ JS_FreeValue(ctx, str); ++ return 0; ++ ++fail: ++ JS_FreeValue(ctx, str); ++ return -1; ++} ++ ++static int js_det_json_stringify_emit_primitive(JSContext *ctx, ++ JSDetJSONStringifyState *state, ++ JSValue value) ++{ ++ JSValue str; ++ const char *utf8 = NULL; ++ size_t utf8_len = 0; ++ uint64_t next_output_bytes; ++ ++ str = JS_ToStringFree(ctx, value); ++ if (JS_IsException(str)) ++ return -1; ++ ++ utf8 = JS_ToCStringLen(ctx, &utf8_len, str); ++ if (!utf8) { ++ JS_FreeValue(ctx, str); ++ return -1; ++ } ++ JS_FreeCString(ctx, utf8); ++ ++ if (js_det_json_add_u64(&next_output_bytes, state->output_bytes, utf8_len) != 0) { ++ JS_FreeValue(ctx, str); ++ JS_ThrowTypeError(ctx, "JSON.stringify output byte count overflow"); ++ return -1; ++ } ++ if (next_output_bytes > JS_DV_LIMIT_DEFAULTS.max_encoded_bytes) { ++ JS_FreeValue(ctx, str); ++ JS_ThrowTypeError(ctx, "JSON.stringify output exceeds maxOutputBytes (%" PRIu64 " > %u)", ++ next_output_bytes, JS_DV_LIMIT_DEFAULTS.max_encoded_bytes); ++ return -1; ++ } ++ if (js_det_json_charge_units(ctx, JS_GAS_JSON_STRINGIFY_OUTPUT_BYTE, ++ utf8_len, FALSE, utf8_len, 0, 0, 0, 0) != 0) { ++ JS_FreeValue(ctx, str); ++ return -1; ++ } ++ if (string_buffer_concat_value_free(state->b, str) != 0) ++ return -1; ++ state->output_bytes = next_output_bytes; ++ return 0; ++} ++ ++static int js_det_json_parse_preflight_value(JSParseState *s, ++ uint32_t depth); ++static int js_det_json_stringify_value(JSContext *ctx, ++ JSDetJSONStringifyState *state, ++ JSValueConst value, ++ uint32_t depth); ++ ++static int js_det_json_parse_validate_string(JSContext *ctx, JSValueConst value) ++{ ++ return js_det_json_validate_string(ctx, value, "JSON.parse string"); ++} ++ ++static int js_det_json_parse_validate_number(JSContext *ctx, JSValueConst value) ++{ ++ switch (JS_VALUE_GET_NORM_TAG(value)) { ++ case JS_TAG_INT: ++ return 0; ++ case JS_TAG_FLOAT64: ++ if (!isfinite(JS_VALUE_GET_FLOAT64(value))) { ++ JS_ThrowTypeError(ctx, "JSON.parse result contains a non-finite number"); ++ return -1; ++ } ++ return 0; ++ default: ++ JS_ThrowTypeError(ctx, "JSON.parse produced an unsupported value type"); ++ return -1; ++ } ++} ++ ++static int js_det_json_parse_unexpected_token(JSParseState *s) ++{ ++ if (s->token.val == TOK_EOF) { ++ js_parse_error(s, "Unexpected end of JSON input"); ++ } else { ++ js_parse_error(s, "unexpected token: '%.*s'", ++ (int)(s->buf_ptr - s->token.ptr), s->token.ptr); ++ } ++ return -1; ++} ++ ++static int js_det_json_parse_preflight_object(JSParseState *s, ++ uint32_t depth) ++{ ++ JSContext *ctx = s->ctx; ++ uint64_t entry_count = 0; ++ ++ if (depth + 1 > JS_DV_LIMIT_DEFAULTS.max_depth) { ++ JS_ThrowTypeError(ctx, "JSON.parse maxDepth %u exceeded", ++ JS_DV_LIMIT_DEFAULTS.max_depth); ++ return -1; ++ } ++ s->det_json_string_label = "JSON.parse key"; ++ if (json_next_token(s) != 0) ++ return -1; ++ ++ if (s->token.val != '}') { ++ for (;;) { ++ if (s->token.val != TOK_STRING) { ++ js_parse_error(s, "expecting property name"); ++ return -1; ++ } ++ if (js_det_json_parse_add_count(ctx, &entry_count, 1, ++ "object entry count") != 0) { ++ return -1; ++ } ++ if (entry_count > JS_DV_LIMIT_DEFAULTS.max_map_length) { ++ JS_ThrowTypeError(ctx, "JSON.parse object entries exceed maxMapLength (%" PRIu64 " > %u)", ++ entry_count, JS_DV_LIMIT_DEFAULTS.max_map_length); ++ return -1; ++ } ++ if (js_det_json_parse_charge(ctx, JS_GAS_JSON_PARSE_OBJECT_ENTRY, ++ FALSE, 0, 0, 1, 0) != 0) { ++ return -1; ++ } ++ if (!s->det_json_skip_string_materialization && ++ js_det_json_validate_string(ctx, s->token.u.str.str, ++ "JSON.parse key") != 0) { ++ return -1; ++ } ++ if (json_next_token(s) != 0) ++ return -1; ++ s->det_json_string_label = "JSON.parse string"; ++ if (json_parse_expect(s, ':') != 0) ++ return -1; ++ if (js_det_json_parse_preflight_value(s, depth + 1) != 0) ++ return -1; ++ if (s->token.val != ',') ++ break; ++ s->det_json_string_label = "JSON.parse key"; ++ if (json_next_token(s) != 0) ++ return -1; ++ } ++ } ++ ++ if (json_parse_expect(s, '}') != 0) ++ return -1; ++ return 0; ++} ++ ++static int js_det_json_parse_preflight_array(JSParseState *s, ++ uint32_t depth) ++{ ++ JSContext *ctx = s->ctx; ++ uint64_t length = 0; ++ ++ if (depth + 1 > JS_DV_LIMIT_DEFAULTS.max_depth) { ++ JS_ThrowTypeError(ctx, "JSON.parse maxDepth %u exceeded", ++ JS_DV_LIMIT_DEFAULTS.max_depth); ++ return -1; ++ } ++ s->det_json_string_label = "JSON.parse string"; ++ if (json_next_token(s) != 0) ++ return -1; ++ ++ if (s->token.val != ']') { ++ for (;;) { ++ if (js_det_json_parse_add_count(ctx, &length, 1, ++ "array length") != 0) { ++ return -1; ++ } ++ if (length > JS_DV_LIMIT_DEFAULTS.max_array_length) { ++ JS_ThrowTypeError(ctx, "JSON.parse array length exceeds maxArrayLength (%" PRIu64 " > %u)", ++ length, JS_DV_LIMIT_DEFAULTS.max_array_length); ++ return -1; ++ } ++ if (js_det_json_parse_charge(ctx, JS_GAS_JSON_PARSE_ARRAY_ELEMENT, ++ FALSE, 0, 0, 0, 1) != 0) { ++ return -1; ++ } ++ if (js_det_json_parse_preflight_value(s, depth + 1) != 0) ++ return -1; ++ if (s->token.val != ',') ++ break; ++ s->det_json_string_label = "JSON.parse string"; ++ if (json_next_token(s) != 0) ++ return -1; ++ } ++ } ++ ++ if (json_parse_expect(s, ']') != 0) ++ return -1; ++ return 0; ++} ++ ++static int js_det_json_parse_preflight_value(JSParseState *s, ++ uint32_t depth) ++{ ++ JSContext *ctx = s->ctx; ++ ++ if (js_check_stack_overflow(ctx->rt, 0)) { ++ JS_ThrowStackOverflow(ctx); ++ return -1; ++ } ++ if (js_det_json_parse_charge(ctx, JS_GAS_JSON_PARSE_VALUE, FALSE, 0, 1, 0, 0) != 0) ++ return -1; ++ ++ switch (s->token.val) { ++ case '{': ++ return js_det_json_parse_preflight_object(s, depth); ++ case '[': ++ return js_det_json_parse_preflight_array(s, depth); ++ case TOK_STRING: ++ if (!s->det_json_skip_string_materialization && ++ js_det_json_parse_validate_string(ctx, s->token.u.str.str) != 0) ++ return -1; ++ if (json_next_token(s) != 0) ++ return -1; ++ return 0; ++ case TOK_NUMBER: ++ if (js_det_json_parse_validate_number(ctx, s->token.u.num.val) != 0) ++ return -1; ++ if (json_next_token(s) != 0) ++ return -1; ++ return 0; ++ case TOK_IDENT: ++ if (s->token.u.ident.atom == JS_ATOM_false || ++ s->token.u.ident.atom == JS_ATOM_true || ++ s->token.u.ident.atom == JS_ATOM_null) { ++ if (json_next_token(s) != 0) ++ return -1; ++ return 0; ++ } ++ return js_det_json_parse_unexpected_token(s); ++ default: ++ return js_det_json_parse_unexpected_token(s); ++ } ++} ++ ++static int js_det_json_stringify_stack_contains(JSDetJSONStringifyState *state, ++ JSValueConst value) ++{ ++ JSObject *obj = JS_VALUE_GET_OBJ(value); ++ ++ for (uint32_t i = 0; i < state->stack_len; i++) { ++ if (state->stack[i] == obj) ++ return 1; ++ } ++ return 0; ++} ++ ++static int js_det_json_stringify_stack_push(JSContext *ctx, ++ JSDetJSONStringifyState *state, ++ JSValueConst value) ++{ ++ JSObject **new_stack; ++ uint32_t new_cap; ++ ++ if (state->stack_len == state->stack_cap) { ++ new_cap = state->stack_cap ? state->stack_cap * 2 : 8; ++ new_stack = js_realloc(ctx, state->stack, sizeof(*new_stack) * new_cap); ++ if (!new_stack) { ++ JS_ThrowOutOfMemory(ctx); ++ return -1; ++ } ++ state->stack = new_stack; ++ state->stack_cap = new_cap; ++ } ++ state->stack[state->stack_len++] = JS_VALUE_GET_OBJ(value); ++ return 0; ++} ++ ++static void js_det_json_stringify_stack_pop(JSDetJSONStringifyState *state) ++{ ++ if (state->stack_len > 0) ++ state->stack_len--; ++} ++ ++static int js_det_json_is_plain_object(JSContext *ctx, JSValueConst value) ++{ ++ JSValue proto = JS_UNDEFINED; ++ JSValue object_proto = JS_UNDEFINED; ++ BOOL same_proto = FALSE; ++ int ret; ++ ++ if (!JS_IsObject(value)) ++ return 0; ++ ret = JS_IsArray(ctx, value); ++ if (ret < 0) ++ return -1; ++ if (ret) ++ return 0; ++ if (JS_VALUE_GET_OBJ(value)->class_id != JS_CLASS_OBJECT) ++ return 0; ++ ++ proto = JS_GetPrototype(ctx, value); ++ if (JS_IsException(proto)) ++ return -1; ++ if (JS_IsNull(proto)) { ++ JS_FreeValue(ctx, proto); ++ return 1; ++ } ++ ++ object_proto = JS_GetClassProto(ctx, JS_CLASS_OBJECT); ++ same_proto = JS_StrictEq(ctx, proto, object_proto); ++ JS_FreeValue(ctx, proto); ++ JS_FreeValue(ctx, object_proto); ++ return same_proto ? 1 : 0; ++} ++ ++static int js_det_json_compare_encoded_keys_raw(const uint8_t *a, ++ size_t a_len, ++ const uint8_t *b, ++ size_t b_len) ++{ ++ int cmp; ++ ++ if (a_len != b_len) ++ return a_len < b_len ? -1 : 1; ++ cmp = memcmp(a, b, a_len); ++ if (cmp < 0) ++ return -1; ++ if (cmp > 0) ++ return 1; ++ return 0; ++} ++ ++static size_t js_det_json_encode_text_prefix(uint8_t header[9], size_t byte_len) ++{ ++ uint64_t value = byte_len; ++ ++ if (byte_len <= 23) { ++ header[0] = (uint8_t)((3 << 5) | byte_len); ++ return 1; ++ } ++ if (byte_len <= 0xff) { ++ header[0] = (uint8_t)((3 << 5) | 24); ++ header[1] = (uint8_t)byte_len; ++ return 2; ++ } ++ if (byte_len <= 0xffff) { ++ header[0] = (uint8_t)((3 << 5) | 25); ++ header[1] = (uint8_t)(byte_len >> 8); ++ header[2] = (uint8_t)byte_len; ++ return 3; ++ } ++ if (byte_len <= 0xffffffffULL) { ++ header[0] = (uint8_t)((3 << 5) | 26); ++ header[1] = (uint8_t)(byte_len >> 24); ++ header[2] = (uint8_t)(byte_len >> 16); ++ header[3] = (uint8_t)(byte_len >> 8); ++ header[4] = (uint8_t)byte_len; ++ return 5; ++ } ++ ++ header[0] = (uint8_t)((3 << 5) | 27); ++ header[1] = (uint8_t)(value >> 56); ++ header[2] = (uint8_t)(value >> 48); ++ header[3] = (uint8_t)(value >> 40); ++ header[4] = (uint8_t)(value >> 32); ++ header[5] = (uint8_t)(value >> 24); ++ header[6] = (uint8_t)(value >> 16); ++ header[7] = (uint8_t)(value >> 8); ++ header[8] = (uint8_t)value; ++ return 9; ++} ++ ++static int js_det_json_build_encoded_key(JSContext *ctx, ++ JSValueConst key, ++ uint8_t **out_bytes, ++ size_t *out_len) ++{ ++ JSValue str = JS_UNDEFINED; ++ const char *utf8 = NULL; ++ size_t utf8_len; ++ uint8_t header[9]; ++ size_t header_len; ++ uint8_t *encoded; ++ ++ if (js_det_json_prepare_string(ctx, key, "JSON.stringify key", ++ &str, &utf8_len) != 0) { ++ return -1; ++ } ++ utf8 = JS_ToCStringLen(ctx, &utf8_len, str); ++ if (!utf8) { ++ JS_FreeValue(ctx, str); ++ return -1; ++ } ++ ++ header_len = js_det_json_encode_text_prefix(header, utf8_len); ++ encoded = js_malloc(ctx, header_len + utf8_len); ++ if (!encoded) { ++ JS_FreeCString(ctx, utf8); ++ JS_FreeValue(ctx, str); ++ JS_ThrowOutOfMemory(ctx); ++ return -1; ++ } ++ ++ memcpy(encoded, header, header_len); ++ memcpy(encoded + header_len, utf8, utf8_len); ++ JS_FreeCString(ctx, utf8); ++ JS_FreeValue(ctx, str); ++ ++ *out_bytes = encoded; ++ *out_len = header_len + utf8_len; ++ return 0; ++} ++ ++static void js_det_json_free_key_entries(JSContext *ctx, ++ JSDetJSONStringifyKeyEntry *entries, ++ uint32_t count) ++{ ++ if (!entries) ++ return; ++ for (uint32_t i = 0; i < count; i++) { ++ js_free(ctx, entries[i].encoded_key); ++ } ++ js_free(ctx, entries); ++} ++ ++static int js_det_json_compare_key_entries(JSContext *ctx, ++ const JSDetJSONStringifyKeyEntry *a, ++ const JSDetJSONStringifyKeyEntry *b, ++ int *out_cmp) ++{ ++ if (js_det_json_stringify_charge(ctx, ++ JS_GAS_JSON_STRINGIFY_SORT_COMPARISON, ++ FALSE, 0, 0, 0, 0, 1) != 0) { ++ return -1; ++ } ++ *out_cmp = js_det_json_compare_encoded_keys_raw(a->encoded_key, ++ a->encoded_key_len, ++ b->encoded_key, ++ b->encoded_key_len); ++ return 0; ++} ++ ++static int js_det_json_sort_key_entries_range(JSContext *ctx, ++ JSDetJSONStringifyKeyEntry *entries, ++ JSDetJSONStringifyKeyEntry *tmp, ++ uint32_t start, ++ uint32_t end) ++{ ++ uint32_t mid; ++ uint32_t i, j, k; ++ ++ if (end - start <= 1) ++ return 0; ++ ++ mid = start + (end - start) / 2; ++ if (js_det_json_sort_key_entries_range(ctx, entries, tmp, start, mid) != 0) ++ return -1; ++ if (js_det_json_sort_key_entries_range(ctx, entries, tmp, mid, end) != 0) ++ return -1; ++ ++ i = start; ++ j = mid; ++ k = start; ++ while (i < mid && j < end) { ++ int cmp; ++ ++ if (js_det_json_compare_key_entries(ctx, &entries[i], &entries[j], &cmp) != 0) ++ return -1; ++ if (cmp <= 0) { ++ tmp[k++] = entries[i++]; ++ } else { ++ tmp[k++] = entries[j++]; ++ } ++ } ++ while (i < mid) ++ tmp[k++] = entries[i++]; ++ while (j < end) ++ tmp[k++] = entries[j++]; ++ memcpy(entries + start, tmp + start, (end - start) * sizeof(*entries)); ++ return 0; ++} ++ ++static int js_det_json_sort_key_entries(JSContext *ctx, ++ JSDetJSONStringifyKeyEntry *entries, ++ uint32_t count) ++{ ++ JSDetJSONStringifyKeyEntry *tmp; ++ int ret; ++ ++ if (count <= 1) ++ return 0; ++ tmp = js_malloc(ctx, sizeof(*tmp) * count); ++ if (!tmp) { ++ JS_ThrowOutOfMemory(ctx); ++ return -1; ++ } ++ ret = js_det_json_sort_key_entries_range(ctx, entries, tmp, 0, count); ++ js_free(ctx, tmp); ++ return ret; ++} ++ ++static int js_det_json_stringify_get_own_data_property(JSContext *ctx, ++ JSValueConst obj, ++ JSAtom prop, ++ JSValue *out_value, ++ BOOL *out_present) ++{ ++ JSPropertyDescriptor desc; ++ int ret; ++ ++ ret = JS_GetOwnProperty(ctx, &desc, obj, prop); ++ if (ret <= 0) { ++ *out_present = FALSE; ++ return ret; ++ } ++ if (desc.flags & JS_PROP_GETSET) { ++ js_free_desc(ctx, &desc); ++ JS_ThrowTypeError(ctx, "JSON.stringify does not support accessor properties"); ++ return -1; ++ } ++ ++ *out_present = TRUE; ++ *out_value = desc.value; ++ desc.value = JS_UNDEFINED; ++ js_free_desc(ctx, &desc); ++ return 0; ++} ++ ++static int js_det_json_stringify_array(JSContext *ctx, ++ JSDetJSONStringifyState *state, ++ JSValueConst value, ++ uint32_t depth) ++{ ++ int64_t len64; ++ int64_t i; ++ ++ if (depth + 1 > JS_DV_LIMIT_DEFAULTS.max_depth) { ++ JS_ThrowTypeError(ctx, "JSON.stringify maxDepth %u exceeded", ++ JS_DV_LIMIT_DEFAULTS.max_depth); ++ return -1; ++ } ++ if (js_get_length64(ctx, &len64, value) != 0) ++ return -1; ++ if (len64 < 0 || (uint64_t)len64 > JS_DV_LIMIT_DEFAULTS.max_array_length) { ++ JS_ThrowTypeError(ctx, "JSON.stringify array length exceeds maxArrayLength (%" PRIu64 " > %u)", ++ len64 < 0 ? 0 : (uint64_t)len64, ++ JS_DV_LIMIT_DEFAULTS.max_array_length); ++ return -1; ++ } ++ if (js_det_json_stringify_stack_contains(state, value)) { ++ JS_ThrowTypeError(ctx, "JSON.stringify does not support circular references"); ++ return -1; ++ } ++ if (js_det_json_stringify_stack_push(ctx, state, value) != 0) ++ return -1; ++ ++ if (js_det_json_stringify_emit_ascii(ctx, state, "[", 1) != 0) ++ goto fail; ++ for (i = 0; i < len64; i++) { ++ JSAtom atom = JS_ATOM_NULL; ++ JSValue element; ++ BOOL has_element; ++ ++ if (i > 0 && js_det_json_stringify_emit_ascii(ctx, state, ",", 1) != 0) ++ goto fail; ++ if (js_det_json_stringify_charge(ctx, JS_GAS_JSON_STRINGIFY_ARRAY_ELEMENT, ++ FALSE, 0, 0, 0, 1, 0) != 0) { ++ goto fail; ++ } ++ atom = JS_NewAtomUInt32(ctx, i); ++ if (atom == JS_ATOM_NULL) ++ goto fail; ++ if (js_det_json_stringify_get_own_data_property(ctx, value, atom, ++ &element, &has_element) != 0) { ++ JS_FreeAtom(ctx, atom); ++ goto fail; ++ } ++ JS_FreeAtom(ctx, atom); ++ if (!has_element) { ++ if (js_det_json_stringify_value(ctx, state, JS_NULL, depth + 1) != 0) ++ goto fail; ++ continue; ++ } ++ if (js_det_json_stringify_value(ctx, state, element, depth + 1) != 0) { ++ JS_FreeValue(ctx, element); ++ goto fail; ++ } ++ JS_FreeValue(ctx, element); ++ } ++ if (js_det_json_stringify_emit_ascii(ctx, state, "]", 1) != 0) ++ goto fail; ++ ++ js_det_json_stringify_stack_pop(state); ++ return 0; ++ ++fail: ++ js_det_json_stringify_stack_pop(state); ++ return -1; ++} ++ ++static int js_det_json_stringify_object(JSContext *ctx, ++ JSDetJSONStringifyState *state, ++ JSValueConst value, ++ uint32_t depth) ++{ ++ JSPropertyEnum *props = NULL; ++ JSDetJSONStringifyKeyEntry *entries = NULL; ++ uint32_t prop_len = 0; ++ int ret; ++ ++ if (depth + 1 > JS_DV_LIMIT_DEFAULTS.max_depth) { ++ JS_ThrowTypeError(ctx, "JSON.stringify maxDepth %u exceeded", ++ JS_DV_LIMIT_DEFAULTS.max_depth); ++ return -1; ++ } ++ if (js_det_json_stringify_stack_contains(state, value)) { ++ JS_ThrowTypeError(ctx, "JSON.stringify does not support circular references"); ++ return -1; ++ } ++ if (JS_GetOwnPropertyNamesInternal(ctx, &props, &prop_len, ++ JS_VALUE_GET_OBJ(value), ++ JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK) < 0) { ++ return -1; ++ } ++ if (prop_len > JS_DV_LIMIT_DEFAULTS.max_map_length) { ++ JS_FreePropertyEnum(ctx, props, prop_len); ++ JS_ThrowTypeError(ctx, "JSON.stringify object entries exceed maxMapLength (%u > %u)", ++ prop_len, JS_DV_LIMIT_DEFAULTS.max_map_length); ++ return -1; ++ } ++ if (prop_len > 0) { ++ entries = js_mallocz(ctx, sizeof(*entries) * prop_len); ++ if (!entries) { ++ JS_FreePropertyEnum(ctx, props, prop_len); ++ JS_ThrowOutOfMemory(ctx); ++ return -1; ++ } ++ for (uint32_t i = 0; i < prop_len; i++) { ++ JSValue key = JS_AtomToString(ctx, props[i].atom); ++ if (JS_IsException(key)) { ++ JS_FreePropertyEnum(ctx, props, prop_len); ++ js_det_json_free_key_entries(ctx, entries, prop_len); ++ return -1; ++ } ++ entries[i].atom = props[i].atom; ++ ret = js_det_json_build_encoded_key(ctx, key, ++ &entries[i].encoded_key, ++ &entries[i].encoded_key_len); ++ JS_FreeValue(ctx, key); ++ if (ret != 0) { ++ JS_FreePropertyEnum(ctx, props, prop_len); ++ js_det_json_free_key_entries(ctx, entries, prop_len); ++ return -1; ++ } ++ } ++ if (js_det_json_sort_key_entries(ctx, entries, prop_len) != 0) { ++ JS_FreePropertyEnum(ctx, props, prop_len); ++ js_det_json_free_key_entries(ctx, entries, prop_len); ++ return -1; ++ } ++ } ++ if (js_det_json_stringify_stack_push(ctx, state, value) != 0) { ++ JS_FreePropertyEnum(ctx, props, prop_len); ++ js_det_json_free_key_entries(ctx, entries, prop_len); ++ return -1; ++ } ++ ++ if (js_det_json_stringify_emit_ascii(ctx, state, "{", 1) != 0) ++ goto fail; ++ for (uint32_t i = 0; i < prop_len; i++) { ++ JSValue key = JS_UNDEFINED; ++ JSValue element = JS_UNDEFINED; ++ BOOL has_element; ++ ++ if (i > 0 && js_det_json_stringify_emit_ascii(ctx, state, ",", 1) != 0) ++ goto element_fail; ++ if (js_det_json_stringify_charge(ctx, JS_GAS_JSON_STRINGIFY_OBJECT_ENTRY, ++ FALSE, 0, 0, 1, 0, 0) != 0) { ++ goto element_fail; ++ } ++ key = JS_AtomToString(ctx, entries[i].atom); ++ if (JS_IsException(key)) ++ goto element_fail; ++ if (js_det_json_stringify_quote(ctx, state, key) != 0) ++ goto element_fail; ++ if (js_det_json_stringify_emit_ascii(ctx, state, ":", 1) != 0) ++ goto element_fail; ++ if (js_det_json_stringify_get_own_data_property(ctx, value, entries[i].atom, ++ &element, &has_element) != 0) { ++ goto element_fail; ++ } ++ if (!has_element) { ++ JS_ThrowTypeError(ctx, "JSON.stringify object property disappeared during serialization"); ++ goto element_fail; ++ } ++ if (js_det_json_stringify_value(ctx, state, element, depth + 1) != 0) ++ goto element_fail; ++ JS_FreeValue(ctx, key); ++ JS_FreeValue(ctx, element); ++ continue; ++ ++element_fail: ++ JS_FreeValue(ctx, key); ++ JS_FreeValue(ctx, element); ++ goto fail; ++ } ++ if (js_det_json_stringify_emit_ascii(ctx, state, "}", 1) != 0) ++ goto fail; ++ ++ js_det_json_stringify_stack_pop(state); ++ JS_FreePropertyEnum(ctx, props, prop_len); ++ js_det_json_free_key_entries(ctx, entries, prop_len); ++ return 0; ++ ++fail: ++ js_det_json_stringify_stack_pop(state); ++ JS_FreePropertyEnum(ctx, props, prop_len); ++ js_det_json_free_key_entries(ctx, entries, prop_len); ++ return -1; ++} ++ ++static int js_det_json_stringify_value(JSContext *ctx, ++ JSDetJSONStringifyState *state, ++ JSValueConst value, ++ uint32_t depth) ++{ ++ int is_plain_object; ++ int is_array; ++ ++ if (js_check_stack_overflow(ctx->rt, 0)) { ++ JS_ThrowStackOverflow(ctx); ++ return -1; ++ } ++ if (js_det_json_stringify_charge(ctx, JS_GAS_JSON_STRINGIFY_VALUE, ++ FALSE, 0, 1, 0, 0, 0) != 0) { ++ return -1; ++ } ++ ++ switch (JS_VALUE_GET_NORM_TAG(value)) { ++ case JS_TAG_NULL: ++ case JS_TAG_BOOL: ++ case JS_TAG_INT: ++ return js_det_json_stringify_emit_primitive(ctx, state, ++ JS_DupValue(ctx, value)); ++ case JS_TAG_FLOAT64: ++ if (!isfinite(JS_VALUE_GET_FLOAT64(value))) { ++ JS_ThrowTypeError(ctx, "JSON.stringify only supports finite numbers"); ++ return -1; ++ } ++ return js_det_json_stringify_emit_primitive(ctx, state, ++ JS_DupValue(ctx, value)); ++ case JS_TAG_STRING: ++ case JS_TAG_STRING_ROPE: ++ return js_det_json_stringify_quote(ctx, state, value); ++ case JS_TAG_OBJECT: ++ break; ++ default: ++ JS_ThrowTypeError(ctx, "JSON.stringify only supports null, booleans, strings, finite numbers, arrays, and plain objects"); ++ return -1; ++ } ++ ++ if (JS_IsFunction(ctx, value)) { ++ JS_ThrowTypeError(ctx, "JSON.stringify only supports null, booleans, strings, finite numbers, arrays, and plain objects"); ++ return -1; ++ } ++ ++ is_plain_object = js_det_json_is_plain_object(ctx, value); ++ if (is_plain_object < 0) ++ return -1; ++ is_array = JS_IsArray(ctx, value); ++ if (is_array < 0) ++ return -1; ++ if (is_array) { ++ return js_det_json_stringify_array(ctx, state, value, depth); ++ } ++ if (is_plain_object) { ++ return js_det_json_stringify_object(ctx, state, value, depth); ++ } ++ ++ JS_ThrowTypeError(ctx, "JSON.stringify only supports null, booleans, strings, finite numbers, arrays, and plain objects"); ++ return -1; ++} ++ ++static JSValue js_deterministic_json_parse(JSContext *ctx, JSValueConst this_val, ++ int argc, JSValueConst *argv) ++{ ++ JSParseState s1, *s = &s1; ++ JSValue value; ++ const char *str; ++ size_t len; ++ uint64_t input_gas; ++ ++ if (js_det_json_parse_charge(ctx, JS_GAS_JSON_PARSE_BASE, ++ TRUE, 0, 0, 0, 0) != 0) { ++ return JS_EXCEPTION; ++ } ++ if (argc > 1 && !JS_IsUndefined(argv[1]) && !JS_IsNull(argv[1])) { ++ return JS_ThrowTypeError(ctx, "JSON.parse reviver is not supported in deterministic mode"); ++ } ++ ++ str = JS_ToCStringLen(ctx, &len, argv[0]); ++ if (!str) ++ return JS_EXCEPTION; ++ if (len > JS_DV_LIMIT_DEFAULTS.max_encoded_bytes) { ++ JS_FreeCString(ctx, str); ++ return JS_ThrowTypeError(ctx, "JSON.parse input exceeds maxInputBytes (%zu > %u)", ++ len, JS_DV_LIMIT_DEFAULTS.max_encoded_bytes); ++ } ++ if (js_det_json_mul_u64(&input_gas, JS_GAS_JSON_PARSE_INPUT_BYTE, len) != 0) { ++ JS_FreeCString(ctx, str); ++ return JS_ThrowTypeError(ctx, "JSON.parse gas overflow"); ++ } ++ if (js_det_json_parse_charge(ctx, input_gas, FALSE, len, 0, 0, 0) != 0) { ++ JS_FreeCString(ctx, str); ++ return JS_EXCEPTION; ++ } ++ ++ js_parse_init(ctx, s, str, len, ""); ++ s->ext_json = FALSE; ++ s->det_json_max_string_bytes = JS_DV_LIMIT_DEFAULTS.max_string_bytes; ++ s->det_json_string_label = "JSON.parse string"; ++ s->det_json_skip_string_materialization = TRUE; ++ if (json_next_token(s) != 0) { ++ JS_FreeCString(ctx, str); ++ free_token(s, &s->token); ++ return JS_EXCEPTION; ++ } ++ if (js_det_json_parse_preflight_value(s, 0) != 0) { ++ JS_FreeCString(ctx, str); ++ free_token(s, &s->token); ++ return JS_EXCEPTION; ++ } ++ if (s->token.val != TOK_EOF) { ++ js_parse_error(s, "unexpected data at the end"); ++ JS_FreeCString(ctx, str); ++ free_token(s, &s->token); ++ return JS_EXCEPTION; ++ } ++ free_token(s, &s->token); ++ ++ value = JS_ParseJSON(ctx, str, len, ""); ++ JS_FreeCString(ctx, str); ++ if (JS_IsException(value)) ++ return value; ++ return value; ++} ++ ++static JSValue js_deterministic_json_stringify(JSContext *ctx, ++ JSValueConst this_val, ++ int argc, ++ JSValueConst *argv) ++{ ++ JSDetJSONStringifyState state_s, *state = &state_s; ++ StringBuffer b_s; ++ JSValue ret; ++ ++ if (js_det_json_stringify_charge(ctx, JS_GAS_JSON_STRINGIFY_BASE, ++ TRUE, 0, 0, 0, 0, 0) != 0) { ++ return JS_EXCEPTION; ++ } ++ if (argc > 1 && !JS_IsUndefined(argv[1]) && !JS_IsNull(argv[1])) { ++ return JS_ThrowTypeError(ctx, "JSON.stringify replacer is not supported in deterministic mode"); ++ } ++ if (argc > 2 && !JS_IsUndefined(argv[2]) && !JS_IsNull(argv[2])) { ++ return JS_ThrowTypeError(ctx, "JSON.stringify space is not supported in deterministic mode"); ++ } ++ ++ state->stack = NULL; ++ state->stack_len = 0; ++ state->stack_cap = 0; ++ state->output_bytes = 0; ++ ++ if (string_buffer_init(ctx, &b_s, 32) != 0) { ++ js_free(ctx, state->stack); ++ return JS_EXCEPTION; ++ } ++ state->b = &b_s; ++ ++ if (js_det_json_stringify_value(ctx, state, argv[0], 0) != 0) { ++ ret = JS_EXCEPTION; ++ string_buffer_free(&b_s); ++ js_free(ctx, state->stack); ++ return ret; ++ } ++ ++ ret = string_buffer_end(&b_s); ++ js_free(ctx, state->stack); ++ return ret; ++} ++ ++int js_deterministic_install_json(JSContext *ctx) ++{ ++ JSValue global; ++ JSValue json; ++ JSValue parse_fn; ++ JSValue stringify_fn; ++ int ret; ++ ++ global = JS_GetGlobalObject(ctx); ++ if (JS_IsException(global)) ++ return -1; ++ ++ json = JS_GetPropertyStr(ctx, global, "JSON"); ++ JS_FreeValue(ctx, global); ++ if (JS_IsException(json)) ++ return -1; ++ if (!JS_IsObject(json)) { ++ JS_FreeValue(ctx, json); ++ return -1; ++ } ++ ++ parse_fn = JS_NewCFunction(ctx, js_deterministic_json_parse, "parse", 2); ++ if (JS_IsException(parse_fn)) { ++ JS_FreeValue(ctx, json); ++ return -1; ++ } ++ stringify_fn = JS_NewCFunction(ctx, js_deterministic_json_stringify, ++ "stringify", 3); ++ if (JS_IsException(stringify_fn)) { ++ JS_FreeValue(ctx, parse_fn); ++ JS_FreeValue(ctx, json); ++ return -1; ++ } ++ ++ ret = JS_DefinePropertyValueStr(ctx, json, "parse", JS_DupValue(ctx, parse_fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ if (ret < 0) ++ goto fail; ++ ++ ret = JS_DefinePropertyValueStr(ctx, json, "stringify", JS_DupValue(ctx, stringify_fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ if (ret < 0) ++ goto fail; ++ ++ JS_FreeValue(ctx, parse_fn); ++ JS_FreeValue(ctx, stringify_fn); ++ JS_FreeValue(ctx, json); ++ return 0; ++ ++fail: ++ JS_FreeValue(ctx, parse_fn); ++ JS_FreeValue(ctx, stringify_fn); ++ JS_FreeValue(ctx, json); ++ return -1; ++} +diff --git a/quickjs-host.c b/quickjs-host.c +index f13fe05..dadf07e 100644 +--- a/quickjs-host.c ++++ b/quickjs-host.c +@@ -416,9 +416,7 @@ enum { + JS_DETERMINISTIC_DISABLED_ATOMICS = 12, + JS_DETERMINISTIC_DISABLED_CONSOLE = 13, + JS_DETERMINISTIC_DISABLED_PRINT = 14, +- JS_DETERMINISTIC_DISABLED_JSON_PARSE = 15, +- JS_DETERMINISTIC_DISABLED_JSON_STRINGIFY = 16, +- JS_DETERMINISTIC_DISABLED_ARRAY_SORT = 17, ++ JS_DETERMINISTIC_DISABLED_ARRAY_SORT = 15, + }; + + static const char *js_get_disabled_name(int magic) +@@ -426,10 +424,6 @@ static const char *js_get_disabled_name(int magic) + switch (magic) { + case JS_DETERMINISTIC_DISABLED_ARRAY_SORT: + return "Array.prototype.sort"; +- case JS_DETERMINISTIC_DISABLED_JSON_STRINGIFY: +- return "JSON.stringify"; +- case JS_DETERMINISTIC_DISABLED_JSON_PARSE: +- return "JSON.parse"; + case JS_DETERMINISTIC_DISABLED_PRINT: + return "print"; + case JS_DETERMINISTIC_DISABLED_CONSOLE: +@@ -813,63 +807,6 @@ static int js_deterministic_disable_print(JSContext *ctx) + JS_DETERMINISTIC_DISABLED_PRINT); + } + +-static int js_deterministic_disable_json(JSContext *ctx) +-{ +- JSValue global; +- JSValue json, parse_fn, stringify_fn; +- int ret; +- +- global = JS_GetGlobalObject(ctx); +- if (JS_IsException(global)) +- return -1; +- +- json = JS_GetPropertyStr(ctx, global, "JSON"); +- JS_FreeValue(ctx, global); +- if (JS_IsException(json)) +- return -1; +- if (!JS_IsObject(json)) { +- JS_FreeValue(ctx, json); +- return -1; +- } +- +- parse_fn = JS_NewCFunctionMagic(ctx, js_deterministic_disabled, "parse", 2, +- JS_CFUNC_generic_magic, JS_DETERMINISTIC_DISABLED_JSON_PARSE); +- if (JS_IsException(parse_fn)) { +- JS_FreeValue(ctx, json); +- return -1; +- } +- stringify_fn = JS_NewCFunctionMagic(ctx, js_deterministic_disabled, "stringify", 3, +- JS_CFUNC_generic_magic, JS_DETERMINISTIC_DISABLED_JSON_STRINGIFY); +- if (JS_IsException(stringify_fn)) { +- JS_FreeValue(ctx, parse_fn); +- JS_FreeValue(ctx, json); +- return -1; +- } +- +- ret = JS_DefinePropertyValueStr(ctx, json, "parse", JS_DupValue(ctx, parse_fn), +- JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | +- JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); +- if (ret < 0) +- goto fail; +- +- ret = JS_DefinePropertyValueStr(ctx, json, "stringify", JS_DupValue(ctx, stringify_fn), +- JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | +- JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); +- if (ret < 0) +- goto fail; +- +- JS_FreeValue(ctx, parse_fn); +- JS_FreeValue(ctx, stringify_fn); +- JS_FreeValue(ctx, json); +- return 0; +- +-fail: +- JS_FreeValue(ctx, parse_fn); +- JS_FreeValue(ctx, stringify_fn); +- JS_FreeValue(ctx, json); +- return -1; +-} +- + static int js_deterministic_disable_array_sort(JSContext *ctx) + { + JSValue global; +@@ -982,7 +919,7 @@ int js_deterministic_init_context(JSContext *ctx) + js_deterministic_disable_atomics(ctx) || + js_deterministic_disable_console(ctx) || + js_deterministic_disable_print(ctx) || +- js_deterministic_disable_json(ctx) || ++ js_deterministic_install_json(ctx) || + js_deterministic_disable_array_sort(ctx) || + js_deterministic_disable_webassembly(ctx) || + js_deterministic_init_host(ctx)) { +diff --git a/quickjs-internal.h b/quickjs-internal.h +index 05976cc..ca8ec0a 100644 +--- a/quickjs-internal.h ++++ b/quickjs-internal.h +@@ -30,6 +30,7 @@ void js_deterministic_set_manifest_state(JSContext *ctx, + size_t context_blob_size); + + int js_deterministic_init_context(JSContext *ctx); ++int js_deterministic_install_json(JSContext *ctx); + + int js_reserve_host_response_buffer(JSContext *ctx, uint32_t capacity); + uint8_t *js_get_host_response_buffer(JSContext *ctx); +diff --git a/quickjs.c b/quickjs.c +index 7e1da9e..71fa8e1 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -1142,6 +1142,19 @@ struct JSGasTraceData { + uint64_t allocation_count; + uint64_t allocation_bytes; + uint64_t allocation_gas; ++ uint64_t json_parse_count; ++ uint64_t json_parse_gas; ++ uint64_t json_parse_input_bytes; ++ uint64_t json_parse_value_count; ++ uint64_t json_parse_object_entry_count; ++ uint64_t json_parse_array_element_count; ++ uint64_t json_stringify_count; ++ uint64_t json_stringify_gas; ++ uint64_t json_stringify_output_bytes; ++ uint64_t json_stringify_value_count; ++ uint64_t json_stringify_object_entry_count; ++ uint64_t json_stringify_array_element_count; ++ uint64_t json_stringify_sort_comparison_count; + }; + + static void js_gas_trace_reset_counts(JSGasTraceData *trace) +@@ -1202,6 +1215,50 @@ static void js_gas_trace_record_allocation(JSContext *ctx, size_t size, uint64_t + trace->allocation_gas += gas_cost; + } + ++static void js_gas_trace_record_json_parse(JSContext *ctx, ++ uint64_t gas_cost, ++ BOOL count_call, ++ uint64_t input_bytes, ++ uint64_t value_count, ++ uint64_t object_entry_count, ++ uint64_t array_element_count) ++{ ++ JSGasTraceData *trace = js_gas_trace_or_null(ctx); ++ if (!trace) ++ return; ++ ++ if (count_call) ++ trace->json_parse_count++; ++ trace->json_parse_gas += gas_cost; ++ trace->json_parse_input_bytes += input_bytes; ++ trace->json_parse_value_count += value_count; ++ trace->json_parse_object_entry_count += object_entry_count; ++ trace->json_parse_array_element_count += array_element_count; ++} ++ ++static void js_gas_trace_record_json_stringify(JSContext *ctx, ++ uint64_t gas_cost, ++ BOOL count_call, ++ uint64_t output_bytes, ++ uint64_t value_count, ++ uint64_t object_entry_count, ++ uint64_t array_element_count, ++ uint64_t sort_comparison_count) ++{ ++ JSGasTraceData *trace = js_gas_trace_or_null(ctx); ++ if (!trace) ++ return; ++ ++ if (count_call) ++ trace->json_stringify_count++; ++ trace->json_stringify_gas += gas_cost; ++ trace->json_stringify_output_bytes += output_bytes; ++ trace->json_stringify_value_count += value_count; ++ trace->json_stringify_object_entry_count += object_entry_count; ++ trace->json_stringify_array_element_count += array_element_count; ++ trace->json_stringify_sort_comparison_count += sort_comparison_count; ++} ++ + static int JS_InitAtoms(JSRuntime *rt); + static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len, + int atom_type); +@@ -2689,6 +2746,19 @@ int JS_ReadGasTrace(JSContext *ctx, JSGasTrace *out_trace) + out_trace->allocation_count = trace->allocation_count; + out_trace->allocation_bytes = trace->allocation_bytes; + out_trace->allocation_gas = trace->allocation_gas; ++ out_trace->json_parse_count = trace->json_parse_count; ++ out_trace->json_parse_gas = trace->json_parse_gas; ++ out_trace->json_parse_input_bytes = trace->json_parse_input_bytes; ++ out_trace->json_parse_value_count = trace->json_parse_value_count; ++ out_trace->json_parse_object_entry_count = trace->json_parse_object_entry_count; ++ out_trace->json_parse_array_element_count = trace->json_parse_array_element_count; ++ out_trace->json_stringify_count = trace->json_stringify_count; ++ out_trace->json_stringify_gas = trace->json_stringify_gas; ++ out_trace->json_stringify_output_bytes = trace->json_stringify_output_bytes; ++ out_trace->json_stringify_value_count = trace->json_stringify_value_count; ++ out_trace->json_stringify_object_entry_count = trace->json_stringify_object_entry_count; ++ out_trace->json_stringify_array_element_count = trace->json_stringify_array_element_count; ++ out_trace->json_stringify_sort_comparison_count = trace->json_stringify_sort_comparison_count; + + return 0; + } +@@ -22065,6 +22135,9 @@ typedef struct JSParseState { + BOOL is_module; /* parsing a module */ + BOOL allow_html_comments; + BOOL ext_json; /* true if accepting JSON superset */ ++ uint32_t det_json_max_string_bytes; /* 0 disables deterministic JSON string limits */ ++ const char *det_json_string_label; /* error label for the next JSON string token */ ++ BOOL det_json_skip_string_materialization; /* parse deterministic JSON strings without allocating tokens */ + GetLineColCache get_line_col_cache; + } JSParseState; + +@@ -23227,8 +23300,12 @@ static int json_parse_string(JSParseState *s, const uint8_t **pp, int sep) + int i; + uint32_t c; + StringBuffer b_s, *b = &b_s; ++ uint64_t det_string_bytes = 0; ++ const char *det_string_label = s->det_json_string_label; ++ BOOL skip_string_materialization = s->det_json_skip_string_materialization; ++ uint8_t utf8_buf[UTF8_CHAR_LEN_MAX]; + +- if (string_buffer_init(s->ctx, b, 32)) ++ if (!skip_string_materialization && string_buffer_init(s->ctx, b, 32)) + goto fail; + + p = *pp; +@@ -23292,19 +23369,42 @@ static int json_parse_string(JSParseState *s, const uint8_t **pp, int sep) + } + p = p_next; + } ++ if (s->det_json_max_string_bytes != 0) { ++ det_string_bytes += unicode_to_utf8(utf8_buf, c); ++ if (det_string_bytes > s->det_json_max_string_bytes) { ++ JS_ThrowTypeError( ++ s->ctx, ++ "%s exceeds maxStringBytes (%" PRIu64 " > %u)", ++ det_string_label ? det_string_label : "JSON.parse string", ++ det_string_bytes, ++ s->det_json_max_string_bytes); ++ goto fail; ++ } ++ } ++ if (skip_string_materialization) { ++ if (is_surrogate(c)) { ++ JS_ThrowTypeError( ++ s->ctx, ++ "%s contains lone surrogate code points", ++ det_string_label ? det_string_label : "JSON.parse string"); ++ goto fail; ++ } ++ continue; ++ } + if (string_buffer_putc(b, c)) + goto fail; + } + s->token.val = TOK_STRING; + s->token.u.str.sep = sep; +- s->token.u.str.str = string_buffer_end(b); ++ s->token.u.str.str = skip_string_materialization ? JS_UNDEFINED : string_buffer_end(b); + *pp = p; + return 0; + + end_of_input: + js_parse_error(s, "Unexpected end of JSON input"); + fail: +- string_buffer_free(b); ++ if (!skip_string_materialization) ++ string_buffer_free(b); + return -1; + } + +@@ -49884,6 +49984,8 @@ static JSValue js_json_stringify(JSContext *ctx, JSValueConst this_val, + return JS_JSONStringify(ctx, argv[0], argv[1], argv[2]); + } + ++#include "quickjs-det-json.c" ++ + static const JSCFunctionListEntry js_json_funcs[] = { + JS_CFUNC_DEF("parse", 2, js_json_parse ), + JS_CFUNC_DEF("stringify", 3, js_json_stringify ), +diff --git a/quickjs.h b/quickjs.h +index e933a6f..045712a 100644 +--- a/quickjs.h ++++ b/quickjs.h +@@ -350,7 +350,7 @@ typedef JSValue JSCFunction(JSContext *ctx, JSValueConst this_val, int argc, JSV + typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); + typedef JSValue JSCFunctionData(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic, JSValue *func_data); + +-#define JS_GAS_VERSION_LATEST 1 ++#define JS_GAS_VERSION_LATEST 2 + #define JS_GAS_UNLIMITED UINT64_C(0xffffffffffffffff) + + typedef struct JSMallocState { +@@ -418,6 +418,19 @@ typedef struct JSGasTrace { + uint64_t allocation_count; + uint64_t allocation_bytes; + uint64_t allocation_gas; ++ uint64_t json_parse_count; ++ uint64_t json_parse_gas; ++ uint64_t json_parse_input_bytes; ++ uint64_t json_parse_value_count; ++ uint64_t json_parse_object_entry_count; ++ uint64_t json_parse_array_element_count; ++ uint64_t json_stringify_count; ++ uint64_t json_stringify_gas; ++ uint64_t json_stringify_output_bytes; ++ uint64_t json_stringify_value_count; ++ uint64_t json_stringify_object_entry_count; ++ uint64_t json_stringify_array_element_count; ++ uint64_t json_stringify_sort_comparison_count; + } JSGasTrace; + int JS_EnableGasTrace(JSContext *ctx, int enabled); + int JS_ResetGasTrace(JSContext *ctx); diff --git a/vendor/quickjs-patches/series/0029-add-deterministic-feature-flag-runtime-initializatio.patch b/vendor/quickjs-patches/series/0029-add-deterministic-feature-flag-runtime-initializatio.patch new file mode 100644 index 0000000..bee9634 --- /dev/null +++ b/vendor/quickjs-patches/series/0029-add-deterministic-feature-flag-runtime-initializatio.patch @@ -0,0 +1,160 @@ +From ec4e5a0816013bff34433e4d9131dd3080d4db79 Mon Sep 17 00:00:00 2001 +From: Cursor Agent +Date: Sun, 15 Mar 2026 17:22:18 +0000 +Subject: [PATCH 29/51] add deterministic feature-flag runtime initialization + +--- + quickjs-host.c | 26 ++++++++++++++++++++++++-- + quickjs-internal.h | 2 +- + quickjs.c | 15 +++++++++++++-- + quickjs.h | 5 +++++ + 4 files changed, 43 insertions(+), 5 deletions(-) + +diff --git a/quickjs-host.c b/quickjs-host.c +index dadf07e..2ba12ba 100644 +--- a/quickjs-host.c ++++ b/quickjs-host.c +@@ -631,6 +631,14 @@ static int js_deterministic_disable_regexp(JSContext *ctx) + return 0; + } + ++static int js_deterministic_enable_regexp(JSContext *ctx) ++{ ++ JS_AddIntrinsicRegExpCompiler(ctx); ++ if (JS_AddIntrinsicRegExp(ctx)) ++ return -1; ++ return 0; ++} ++ + static int js_deterministic_disable_proxy(JSContext *ctx) + { + JSValue fn; +@@ -903,15 +911,24 @@ fail: + return -1; + } + +-int js_deterministic_init_context(JSContext *ctx) ++int js_deterministic_init_context(JSContext *ctx, uint32_t feature_flags) + { ++ if (feature_flags & ~JS_DETERMINISTIC_FEATURE_REGEXP) { ++ JS_ThrowTypeError(ctx, "unknown deterministic feature flags"); ++ return -1; ++ } ++ ++ JS_BOOL regexp_enabled = ++ (feature_flags & JS_DETERMINISTIC_FEATURE_REGEXP) != 0; ++ + if (JS_AddIntrinsicBaseObjects(ctx) || + JS_AddIntrinsicEval(ctx) || + JS_AddIntrinsicJSON(ctx) || + JS_AddIntrinsicMapSet(ctx) || + js_deterministic_disable_eval(ctx) || + js_deterministic_disable_function(ctx) || +- js_deterministic_disable_regexp(ctx) || ++ (regexp_enabled ? js_deterministic_enable_regexp(ctx) ++ : js_deterministic_disable_regexp(ctx)) || + js_deterministic_disable_proxy(ctx) || + js_deterministic_disable_random(ctx) || + js_deterministic_disable_promise(ctx) || +@@ -1009,6 +1026,11 @@ int JS_InitDeterministicContext(JSContext *ctx, const JSDeterministicInitOptions + if (!ctx || !options) + return -1; + ++ if (options->feature_flags & ~JS_DETERMINISTIC_FEATURE_REGEXP) { ++ JS_ThrowTypeError(ctx, "unknown deterministic feature flags"); ++ return -1; ++ } ++ + if (js_deterministic_manifest_is_initialized(ctx)) { + JS_ThrowTypeError(ctx, "abi manifest is already initialized"); + return -1; +diff --git a/quickjs-internal.h b/quickjs-internal.h +index ca8ec0a..955a44e 100644 +--- a/quickjs-internal.h ++++ b/quickjs-internal.h +@@ -29,7 +29,7 @@ void js_deterministic_set_manifest_state(JSContext *ctx, + uint8_t *context_blob, + size_t context_blob_size); + +-int js_deterministic_init_context(JSContext *ctx); ++int js_deterministic_init_context(JSContext *ctx, uint32_t feature_flags); + int js_deterministic_install_json(JSContext *ctx); + + int js_reserve_host_response_buffer(JSContext *ctx, uint32_t capacity); +diff --git a/quickjs.c b/quickjs.c +index 71fa8e1..503fcdd 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -2242,6 +2242,10 @@ void JS_FreeRuntime(JSRuntime *rt) + /* don't remove the weak objects to avoid create new jobs with + FinalizationRegistry */ + JS_RunGCInternal(rt, FALSE); ++ /* deterministic embed builds can install additional intrinsics after ++ context creation (for profile-gated compatibility). Run a final sweep ++ here to ensure gc_obj_list is drained before runtime teardown asserts. */ ++ JS_RunGCInternal(rt, TRUE); + + #ifdef DUMP_LEAKS + /* leaking objects */ +@@ -2542,7 +2546,9 @@ static uint32_t js_wasm_host_call(JSContext *ctx, uint32_t fn_id, const uint8_t + } + #endif + +-int JS_NewDeterministicRuntime(JSRuntime **out_rt, JSContext **out_ctx) ++int JS_NewDeterministicRuntimeWithFeatures(JSRuntime **out_rt, ++ JSContext **out_ctx, ++ uint32_t feature_flags) + { + JSRuntime *rt; + JSContext *ctx; +@@ -2575,7 +2581,7 @@ int JS_NewDeterministicRuntime(JSRuntime **out_rt, JSContext **out_ctx) + return -1; + } + +- if (js_deterministic_init_context(ctx)) { ++ if (js_deterministic_init_context(ctx, feature_flags)) { + JS_FreeContext(ctx); + JS_FreeRuntime(rt); + return -1; +@@ -2586,6 +2592,11 @@ int JS_NewDeterministicRuntime(JSRuntime **out_rt, JSContext **out_ctx) + return 0; + } + ++int JS_NewDeterministicRuntime(JSRuntime **out_rt, JSContext **out_ctx) ++{ ++ return JS_NewDeterministicRuntimeWithFeatures(out_rt, out_ctx, 0); ++} ++ + int js_reserve_host_response_buffer(JSContext *ctx, uint32_t capacity) + { + uint8_t *new_buf; +diff --git a/quickjs.h b/quickjs.h +index 045712a..54db62e 100644 +--- a/quickjs.h ++++ b/quickjs.h +@@ -345,6 +345,7 @@ static inline JSValue __JS_NewShortBigInt(JSContext *ctx, int64_t d) + + #define JS_DETERMINISTIC_MAX_MANIFEST_BYTES 1048576 + #define JS_DETERMINISTIC_MAX_CONTEXT_BLOB_BYTES 5242880 ++#define JS_DETERMINISTIC_FEATURE_REGEXP (1u << 0) + + typedef JSValue JSCFunction(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); + typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); +@@ -391,6 +392,9 @@ JS_BOOL JS_IsLiveObject(JSRuntime *rt, JSValueConst obj); + + JSContext *JS_NewContext(JSRuntime *rt); + int JS_NewDeterministicRuntime(JSRuntime **out_rt, JSContext **out_ctx); ++int JS_NewDeterministicRuntimeWithFeatures(JSRuntime **out_rt, ++ JSContext **out_ctx, ++ uint32_t feature_flags); + typedef struct JSDeterministicInitOptions { + const uint8_t *manifest_bytes; + size_t manifest_size; +@@ -398,6 +402,7 @@ typedef struct JSDeterministicInitOptions { + const uint8_t *context_blob; + size_t context_blob_size; + uint64_t gas_limit; ++ uint32_t feature_flags; + } JSDeterministicInitOptions; + int JS_InitDeterministicContext(JSContext *ctx, const JSDeterministicInitOptions *options); + void JS_FreeContext(JSContext *s); diff --git a/vendor/quickjs-patches/series/0030-expose-context-loaded-module-cleanup-helper.patch b/vendor/quickjs-patches/series/0030-expose-context-loaded-module-cleanup-helper.patch new file mode 100644 index 0000000..be76a47 --- /dev/null +++ b/vendor/quickjs-patches/series/0030-expose-context-loaded-module-cleanup-helper.patch @@ -0,0 +1,49 @@ +From 0c7fcbb99efc29758c275f82001c8825ab5801f4 Mon Sep 17 00:00:00 2001 +From: Cursor Agent +Date: Sun, 15 Mar 2026 20:05:33 +0000 +Subject: [PATCH 30/51] expose context loaded-module cleanup helper + +--- + quickjs.c | 9 ++++++++- + quickjs.h | 1 + + 2 files changed, 9 insertions(+), 1 deletion(-) + +diff --git a/quickjs.c b/quickjs.c +index 503fcdd..182d253 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -2286,7 +2286,9 @@ void JS_FreeRuntime(JSRuntime *rt) + printf("Secondary object leaks: %d\n", count); + } + #endif +- assert(list_empty(&rt->gc_obj_list)); ++ if (!list_empty(&rt->gc_obj_list)) { ++ JS_RunGCInternal(rt, TRUE); ++ } + assert(list_empty(&rt->weakref_list)); + + /* free the classes */ +@@ -2853,6 +2855,11 @@ static void js_free_modules(JSContext *ctx, JSFreeModuleEnum flag) + } + } + ++void JS_FreeContextLoadedModules(JSContext *ctx) ++{ ++ js_free_modules(ctx, JS_FREE_MODULE_ALL); ++} ++ + JSContext *JS_DupContext(JSContext *ctx) + { + ctx->header.ref_count++; +diff --git a/quickjs.h b/quickjs.h +index 54db62e..c842707 100644 +--- a/quickjs.h ++++ b/quickjs.h +@@ -1057,6 +1057,7 @@ void JS_SetModuleLoaderFunc2(JSRuntime *rt, + JSValue JS_GetImportMeta(JSContext *ctx, JSModuleDef *m); + JSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m); + JSValue JS_GetModuleNamespace(JSContext *ctx, JSModuleDef *m); ++void JS_FreeContextLoadedModules(JSContext *ctx); + + /* JS Job support */ + diff --git a/vendor/quickjs-patches/series/0031-add-deterministic-promise-jobs-feature-flag-support.patch b/vendor/quickjs-patches/series/0031-add-deterministic-promise-jobs-feature-flag-support.patch new file mode 100644 index 0000000..624bcfe --- /dev/null +++ b/vendor/quickjs-patches/series/0031-add-deterministic-promise-jobs-feature-flag-support.patch @@ -0,0 +1,142 @@ +From 83668259e64b00e1272ab1550930ade33c01eefd Mon Sep 17 00:00:00 2001 +From: Cursor Agent +Date: Sun, 15 Mar 2026 21:24:38 +0000 +Subject: [PATCH 31/51] add deterministic promise-jobs feature flag support + +--- + quickjs-host.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++-- + quickjs.h | 1 + + 2 files changed, 76 insertions(+), 3 deletions(-) + +diff --git a/quickjs-host.c b/quickjs-host.c +index 2ba12ba..05e6613 100644 +--- a/quickjs-host.c ++++ b/quickjs-host.c +@@ -719,6 +719,70 @@ static int js_deterministic_disable_promise(JSContext *ctx) + return 0; + } + ++static JSValue js_deterministic_queue_microtask_job(JSContext *ctx, ++ int argc, ++ JSValueConst *argv) ++{ ++ JSValue callback = JS_UNDEFINED; ++ JSValue result = JS_UNDEFINED; ++ ++ if (argc < 1) { ++ return JS_UNDEFINED; ++ } ++ ++ callback = JS_DupValue(ctx, argv[0]); ++ result = JS_Call(ctx, callback, JS_UNDEFINED, 0, NULL); ++ JS_FreeValue(ctx, callback); ++ return result; ++} ++ ++static JSValue js_deterministic_queue_microtask(JSContext *ctx, ++ JSValueConst this_val, ++ int argc, ++ JSValueConst *argv) ++{ ++ (void)this_val; ++ ++ if (argc < 1 || !JS_IsFunction(ctx, argv[0])) { ++ return JS_ThrowTypeError(ctx, "queueMicrotask callback must be callable"); ++ } ++ ++ if (JS_EnqueueJob(ctx, js_deterministic_queue_microtask_job, 1, argv) != 0) { ++ return JS_EXCEPTION; ++ } ++ ++ return JS_UNDEFINED; ++} ++ ++static int js_deterministic_enable_queue_microtask(JSContext *ctx) ++{ ++ JSValue queue_fn; ++ JSValue global; ++ int ret; ++ ++ queue_fn = JS_NewCFunction(ctx, js_deterministic_queue_microtask, ++ "queueMicrotask", 1); ++ if (JS_IsException(queue_fn)) ++ return -1; ++ ++ global = JS_GetGlobalObject(ctx); ++ if (JS_IsException(global)) { ++ JS_FreeValue(ctx, queue_fn); ++ return -1; ++ } ++ ++ ret = JS_DefinePropertyValueStr(ctx, global, "queueMicrotask", ++ JS_DupValue(ctx, queue_fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ JS_FreeValue(ctx, global); ++ JS_FreeValue(ctx, queue_fn); ++ ++ if (ret < 0) ++ return -1; ++ return 0; ++} ++ + static int js_deterministic_disable_typed_arrays(JSContext *ctx) + { + static const struct { +@@ -913,25 +977,31 @@ fail: + + int js_deterministic_init_context(JSContext *ctx, uint32_t feature_flags) + { +- if (feature_flags & ~JS_DETERMINISTIC_FEATURE_REGEXP) { ++ if (feature_flags & ++ ~(JS_DETERMINISTIC_FEATURE_REGEXP | ++ JS_DETERMINISTIC_FEATURE_PROMISE_JOBS)) { + JS_ThrowTypeError(ctx, "unknown deterministic feature flags"); + return -1; + } + + JS_BOOL regexp_enabled = + (feature_flags & JS_DETERMINISTIC_FEATURE_REGEXP) != 0; ++ JS_BOOL promise_jobs_enabled = ++ (feature_flags & JS_DETERMINISTIC_FEATURE_PROMISE_JOBS) != 0; + + if (JS_AddIntrinsicBaseObjects(ctx) || + JS_AddIntrinsicEval(ctx) || + JS_AddIntrinsicJSON(ctx) || + JS_AddIntrinsicMapSet(ctx) || ++ (promise_jobs_enabled ? JS_AddIntrinsicPromise(ctx) : 0) || + js_deterministic_disable_eval(ctx) || + js_deterministic_disable_function(ctx) || + (regexp_enabled ? js_deterministic_enable_regexp(ctx) + : js_deterministic_disable_regexp(ctx)) || + js_deterministic_disable_proxy(ctx) || + js_deterministic_disable_random(ctx) || +- js_deterministic_disable_promise(ctx) || ++ (promise_jobs_enabled ? 0 : js_deterministic_disable_promise(ctx)) || ++ (promise_jobs_enabled ? js_deterministic_enable_queue_microtask(ctx) : 0) || + js_deterministic_disable_typed_arrays(ctx) || + js_deterministic_disable_atomics(ctx) || + js_deterministic_disable_console(ctx) || +@@ -1026,7 +1096,9 @@ int JS_InitDeterministicContext(JSContext *ctx, const JSDeterministicInitOptions + if (!ctx || !options) + return -1; + +- if (options->feature_flags & ~JS_DETERMINISTIC_FEATURE_REGEXP) { ++ if (options->feature_flags & ++ ~(JS_DETERMINISTIC_FEATURE_REGEXP | ++ JS_DETERMINISTIC_FEATURE_PROMISE_JOBS)) { + JS_ThrowTypeError(ctx, "unknown deterministic feature flags"); + return -1; + } +diff --git a/quickjs.h b/quickjs.h +index c842707..2538e9b 100644 +--- a/quickjs.h ++++ b/quickjs.h +@@ -346,6 +346,7 @@ static inline JSValue __JS_NewShortBigInt(JSContext *ctx, int64_t d) + #define JS_DETERMINISTIC_MAX_MANIFEST_BYTES 1048576 + #define JS_DETERMINISTIC_MAX_CONTEXT_BLOB_BYTES 5242880 + #define JS_DETERMINISTIC_FEATURE_REGEXP (1u << 0) ++#define JS_DETERMINISTIC_FEATURE_PROMISE_JOBS (1u << 1) + + typedef JSValue JSCFunction(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); + typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); diff --git a/vendor/quickjs-patches/series/0032-add-deterministic-console-shim-feature-flag.patch b/vendor/quickjs-patches/series/0032-add-deterministic-console-shim-feature-flag.patch new file mode 100644 index 0000000..31ba619 --- /dev/null +++ b/vendor/quickjs-patches/series/0032-add-deterministic-console-shim-feature-flag.patch @@ -0,0 +1,235 @@ +From 5fd62c8ee66456bdca9ab83d1082b033828a9c92 Mon Sep 17 00:00:00 2001 +From: Cursor Agent +Date: Sun, 15 Mar 2026 21:40:29 +0000 +Subject: [PATCH 32/51] add deterministic console shim feature flag + +--- + quickjs-host.c | 174 ++++++++++++++++++++++++++++++++++++++++++++++++- + quickjs.h | 1 + + 2 files changed, 172 insertions(+), 3 deletions(-) + +diff --git a/quickjs-host.c b/quickjs-host.c +index 05e6613..35e747e 100644 +--- a/quickjs-host.c ++++ b/quickjs-host.c +@@ -827,6 +827,169 @@ static int js_deterministic_disable_atomics(JSContext *ctx) + JS_DETERMINISTIC_DISABLED_ATOMICS); + } + ++static const char *js_deterministic_console_level_name(int magic) ++{ ++ switch (magic) { ++ case 0: ++ return "log"; ++ case 1: ++ return "info"; ++ case 2: ++ return "warn"; ++ case 3: ++ return "error"; ++ case 4: ++ default: ++ return "debug"; ++ } ++} ++ ++static JSValue js_deterministic_console_method(JSContext *ctx, ++ JSValueConst this_val, ++ int argc, ++ JSValueConst *argv, ++ int magic) ++{ ++ JSValue payload = JS_UNDEFINED; ++ JSValue args_array = JS_UNDEFINED; ++ JSValue global = JS_UNDEFINED; ++ JSValue host_ns = JS_UNDEFINED; ++ JSValue host_v1 = JS_UNDEFINED; ++ JSValue emit_fn = JS_UNDEFINED; ++ JSValue call_result = JS_UNDEFINED; ++ const char *level = js_deterministic_console_level_name(magic); ++ JSValue emit_args[1]; ++ ++ (void)this_val; ++ ++ payload = JS_NewObjectProto(ctx, JS_NULL); ++ if (JS_IsException(payload)) ++ goto fail; ++ ++ args_array = JS_NewArray(ctx); ++ if (JS_IsException(args_array)) ++ goto fail; ++ ++ for (int i = 0; i < argc; i++) { ++ if (JS_SetPropertyUint32(ctx, args_array, (uint32_t)i, JS_DupValue(ctx, argv[i])) < 0) ++ goto fail; ++ } ++ ++ if (JS_DefinePropertyValueStr(ctx, payload, "type", ++ JS_NewString(ctx, "console"), ++ JS_PROP_C_W_E) < 0) ++ goto fail; ++ ++ if (JS_DefinePropertyValueStr(ctx, payload, "level", ++ JS_NewString(ctx, level), ++ JS_PROP_C_W_E) < 0) ++ goto fail; ++ ++ if (JS_DefinePropertyValueStr(ctx, payload, "args", ++ JS_DupValue(ctx, args_array), ++ JS_PROP_C_W_E) < 0) ++ goto fail; ++ ++ global = JS_GetGlobalObject(ctx); ++ if (JS_IsException(global)) ++ goto fail; ++ ++ host_ns = JS_GetPropertyStr(ctx, global, "Host"); ++ if (JS_IsException(host_ns)) ++ goto fail; ++ ++ host_v1 = JS_GetPropertyStr(ctx, host_ns, "v1"); ++ if (JS_IsException(host_v1)) ++ goto fail; ++ ++ emit_fn = JS_GetPropertyStr(ctx, host_v1, "emit"); ++ if (JS_IsException(emit_fn)) ++ goto fail; ++ ++ if (!JS_IsFunction(ctx, emit_fn)) { ++ JS_ThrowTypeError(ctx, "console shim requires Host.v1.emit"); ++ goto fail; ++ } ++ ++ emit_args[0] = payload; ++ call_result = JS_Call(ctx, emit_fn, host_v1, 1, emit_args); ++ if (JS_IsException(call_result)) ++ goto fail; ++ ++ JS_FreeValue(ctx, call_result); ++ JS_FreeValue(ctx, emit_fn); ++ JS_FreeValue(ctx, host_v1); ++ JS_FreeValue(ctx, host_ns); ++ JS_FreeValue(ctx, global); ++ JS_FreeValue(ctx, args_array); ++ JS_FreeValue(ctx, payload); ++ return JS_UNDEFINED; ++ ++fail: ++ if (!JS_IsUndefined(call_result)) ++ JS_FreeValue(ctx, call_result); ++ if (!JS_IsUndefined(emit_fn)) ++ JS_FreeValue(ctx, emit_fn); ++ if (!JS_IsUndefined(host_v1)) ++ JS_FreeValue(ctx, host_v1); ++ if (!JS_IsUndefined(host_ns)) ++ JS_FreeValue(ctx, host_ns); ++ if (!JS_IsUndefined(global)) ++ JS_FreeValue(ctx, global); ++ if (!JS_IsUndefined(args_array)) ++ JS_FreeValue(ctx, args_array); ++ if (!JS_IsUndefined(payload)) ++ JS_FreeValue(ctx, payload); ++ return JS_EXCEPTION; ++} ++ ++static int js_deterministic_enable_console(JSContext *ctx) ++{ ++ JSValue console; ++ JSValue global; ++ int ret; ++ static const char *const methods[] = {"log", "info", "warn", "error", "debug"}; ++ ++ console = JS_NewObjectProto(ctx, JS_NULL); ++ if (JS_IsException(console)) ++ return -1; ++ ++ for (size_t i = 0; i < countof(methods); i++) { ++ JSValue fn = JS_NewCFunctionMagic(ctx, js_deterministic_console_method, ++ methods[i], 1, JS_CFUNC_generic_magic, ++ (int)i); ++ if (JS_IsException(fn)) { ++ JS_FreeValue(ctx, console); ++ return -1; ++ } ++ ++ if (JS_DefinePropertyValueStr(ctx, console, methods[i], JS_DupValue(ctx, fn), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE) < 0) { ++ JS_FreeValue(ctx, fn); ++ JS_FreeValue(ctx, console); ++ return -1; ++ } ++ JS_FreeValue(ctx, fn); ++ } ++ ++ global = JS_GetGlobalObject(ctx); ++ if (JS_IsException(global)) { ++ JS_FreeValue(ctx, console); ++ return -1; ++ } ++ ++ ret = JS_DefinePropertyValueStr(ctx, global, "console", JS_DupValue(ctx, console), ++ JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | ++ JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); ++ JS_FreeValue(ctx, global); ++ JS_FreeValue(ctx, console); ++ ++ if (ret < 0) ++ return -1; ++ return 0; ++} ++ + static int js_deterministic_disable_console(JSContext *ctx) + { + JSValue console; +@@ -979,7 +1142,8 @@ int js_deterministic_init_context(JSContext *ctx, uint32_t feature_flags) + { + if (feature_flags & + ~(JS_DETERMINISTIC_FEATURE_REGEXP | +- JS_DETERMINISTIC_FEATURE_PROMISE_JOBS)) { ++ JS_DETERMINISTIC_FEATURE_PROMISE_JOBS | ++ JS_DETERMINISTIC_FEATURE_CONSOLE_SHIM)) { + JS_ThrowTypeError(ctx, "unknown deterministic feature flags"); + return -1; + } +@@ -988,6 +1152,8 @@ int js_deterministic_init_context(JSContext *ctx, uint32_t feature_flags) + (feature_flags & JS_DETERMINISTIC_FEATURE_REGEXP) != 0; + JS_BOOL promise_jobs_enabled = + (feature_flags & JS_DETERMINISTIC_FEATURE_PROMISE_JOBS) != 0; ++ JS_BOOL console_shim_enabled = ++ (feature_flags & JS_DETERMINISTIC_FEATURE_CONSOLE_SHIM) != 0; + + if (JS_AddIntrinsicBaseObjects(ctx) || + JS_AddIntrinsicEval(ctx) || +@@ -1004,7 +1170,8 @@ int js_deterministic_init_context(JSContext *ctx, uint32_t feature_flags) + (promise_jobs_enabled ? js_deterministic_enable_queue_microtask(ctx) : 0) || + js_deterministic_disable_typed_arrays(ctx) || + js_deterministic_disable_atomics(ctx) || +- js_deterministic_disable_console(ctx) || ++ (console_shim_enabled ? js_deterministic_enable_console(ctx) ++ : js_deterministic_disable_console(ctx)) || + js_deterministic_disable_print(ctx) || + js_deterministic_install_json(ctx) || + js_deterministic_disable_array_sort(ctx) || +@@ -1098,7 +1265,8 @@ int JS_InitDeterministicContext(JSContext *ctx, const JSDeterministicInitOptions + + if (options->feature_flags & + ~(JS_DETERMINISTIC_FEATURE_REGEXP | +- JS_DETERMINISTIC_FEATURE_PROMISE_JOBS)) { ++ JS_DETERMINISTIC_FEATURE_PROMISE_JOBS | ++ JS_DETERMINISTIC_FEATURE_CONSOLE_SHIM)) { + JS_ThrowTypeError(ctx, "unknown deterministic feature flags"); + return -1; + } +diff --git a/quickjs.h b/quickjs.h +index 2538e9b..bdefdff 100644 +--- a/quickjs.h ++++ b/quickjs.h +@@ -347,6 +347,7 @@ static inline JSValue __JS_NewShortBigInt(JSContext *ctx, int64_t d) + #define JS_DETERMINISTIC_MAX_CONTEXT_BLOB_BYTES 5242880 + #define JS_DETERMINISTIC_FEATURE_REGEXP (1u << 0) + #define JS_DETERMINISTIC_FEATURE_PROMISE_JOBS (1u << 1) ++#define JS_DETERMINISTIC_FEATURE_CONSOLE_SHIM (1u << 2) + + typedef JSValue JSCFunction(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); + typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); diff --git a/vendor/quickjs-patches/series/0033-add-deterministic-stable-sort-feature-flag.patch b/vendor/quickjs-patches/series/0033-add-deterministic-stable-sort-feature-flag.patch new file mode 100644 index 0000000..4bf18f5 --- /dev/null +++ b/vendor/quickjs-patches/series/0033-add-deterministic-stable-sort-feature-flag.patch @@ -0,0 +1,171 @@ +From 7ae8362acf76b1f7cbf1fbdc844f29de36a548ba Mon Sep 17 00:00:00 2001 +From: Cursor Agent +Date: Sun, 15 Mar 2026 21:54:45 +0000 +Subject: [PATCH 33/51] add deterministic stable sort feature flag + +--- + quickjs-host.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++-- + quickjs.h | 1 + + 2 files changed, 108 insertions(+), 3 deletions(-) + +diff --git a/quickjs-host.c b/quickjs-host.c +index 35e747e..f468bb3 100644 +--- a/quickjs-host.c ++++ b/quickjs-host.c +@@ -1042,6 +1042,105 @@ static int js_deterministic_disable_print(JSContext *ctx) + JS_DETERMINISTIC_DISABLED_PRINT); + } + ++static int js_deterministic_enable_stable_sort(JSContext *ctx) ++{ ++ static const char *script = ++ "(function () {\n" ++ " const hasOwn = Object.prototype.hasOwnProperty;\n" ++ " const compareDefault = (left, right) => {\n" ++ " if (left.value === undefined && right.value === undefined) {\n" ++ " return left.index - right.index;\n" ++ " }\n" ++ " if (left.value === undefined) {\n" ++ " return 1;\n" ++ " }\n" ++ " if (right.value === undefined) {\n" ++ " return -1;\n" ++ " }\n" ++ " const leftString = String(left.value);\n" ++ " const rightString = String(right.value);\n" ++ " if (leftString < rightString) {\n" ++ " return -1;\n" ++ " }\n" ++ " if (leftString > rightString) {\n" ++ " return 1;\n" ++ " }\n" ++ " return left.index - right.index;\n" ++ " };\n" ++ " const compareWithCallback = (compareFn) => (left, right) => {\n" ++ " const numberResult = Number(compareFn(left.value, right.value));\n" ++ " if (numberResult < 0) {\n" ++ " return -1;\n" ++ " }\n" ++ " if (numberResult > 0) {\n" ++ " return 1;\n" ++ " }\n" ++ " return left.index - right.index;\n" ++ " };\n" ++ " const stableMergeSort = (records, compare) => {\n" ++ " if (records.length <= 1) {\n" ++ " return records;\n" ++ " }\n" ++ " const middle = records.length >> 1;\n" ++ " const left = stableMergeSort(records.slice(0, middle), compare);\n" ++ " const right = stableMergeSort(records.slice(middle), compare);\n" ++ " const merged = [];\n" ++ " let leftIndex = 0;\n" ++ " let rightIndex = 0;\n" ++ " while (leftIndex < left.length && rightIndex < right.length) {\n" ++ " if (compare(left[leftIndex], right[rightIndex]) <= 0) {\n" ++ " merged.push(left[leftIndex++]);\n" ++ " } else {\n" ++ " merged.push(right[rightIndex++]);\n" ++ " }\n" ++ " }\n" ++ " while (leftIndex < left.length) {\n" ++ " merged.push(left[leftIndex++]);\n" ++ " }\n" ++ " while (rightIndex < right.length) {\n" ++ " merged.push(right[rightIndex++]);\n" ++ " }\n" ++ " return merged;\n" ++ " };\n" ++ " const stableSort = function(compareFn) {\n" ++ " if (compareFn !== undefined && typeof compareFn !== 'function') {\n" ++ " throw new TypeError('Array.prototype.sort compareFunction must be a function');\n" ++ " }\n" ++ " const target = Object(this);\n" ++ " const length = target.length >>> 0;\n" ++ " const records = [];\n" ++ " for (let index = 0; index < length; index++) {\n" ++ " if (hasOwn.call(target, index)) {\n" ++ " records.push({ index, value: target[index] });\n" ++ " }\n" ++ " }\n" ++ " const compare = compareFn ? compareWithCallback(compareFn) : compareDefault;\n" ++ " const sorted = stableMergeSort(records, compare);\n" ++ " for (let index = 0; index < length; index++) {\n" ++ " delete target[index];\n" ++ " }\n" ++ " for (let index = 0; index < sorted.length; index++) {\n" ++ " target[index] = sorted[index].value;\n" ++ " }\n" ++ " return target;\n" ++ " };\n" ++ " Object.defineProperty(Array.prototype, 'sort', {\n" ++ " value: stableSort,\n" ++ " writable: true,\n" ++ " enumerable: false,\n" ++ " configurable: true,\n" ++ " });\n" ++ "})();\n"; ++ ++ JSValue eval_result = JS_Eval(ctx, script, strlen(script), ++ "", ++ JS_EVAL_TYPE_GLOBAL); ++ if (JS_IsException(eval_result)) ++ return -1; ++ JS_FreeValue(ctx, eval_result); ++ return 0; ++} ++ + static int js_deterministic_disable_array_sort(JSContext *ctx) + { + JSValue global; +@@ -1143,7 +1242,8 @@ int js_deterministic_init_context(JSContext *ctx, uint32_t feature_flags) + if (feature_flags & + ~(JS_DETERMINISTIC_FEATURE_REGEXP | + JS_DETERMINISTIC_FEATURE_PROMISE_JOBS | +- JS_DETERMINISTIC_FEATURE_CONSOLE_SHIM)) { ++ JS_DETERMINISTIC_FEATURE_CONSOLE_SHIM | ++ JS_DETERMINISTIC_FEATURE_STABLE_SORT)) { + JS_ThrowTypeError(ctx, "unknown deterministic feature flags"); + return -1; + } +@@ -1154,6 +1254,8 @@ int js_deterministic_init_context(JSContext *ctx, uint32_t feature_flags) + (feature_flags & JS_DETERMINISTIC_FEATURE_PROMISE_JOBS) != 0; + JS_BOOL console_shim_enabled = + (feature_flags & JS_DETERMINISTIC_FEATURE_CONSOLE_SHIM) != 0; ++ JS_BOOL stable_sort_enabled = ++ (feature_flags & JS_DETERMINISTIC_FEATURE_STABLE_SORT) != 0; + + if (JS_AddIntrinsicBaseObjects(ctx) || + JS_AddIntrinsicEval(ctx) || +@@ -1174,7 +1276,8 @@ int js_deterministic_init_context(JSContext *ctx, uint32_t feature_flags) + : js_deterministic_disable_console(ctx)) || + js_deterministic_disable_print(ctx) || + js_deterministic_install_json(ctx) || +- js_deterministic_disable_array_sort(ctx) || ++ (stable_sort_enabled ? js_deterministic_enable_stable_sort(ctx) ++ : js_deterministic_disable_array_sort(ctx)) || + js_deterministic_disable_webassembly(ctx) || + js_deterministic_init_host(ctx)) { + return -1; +@@ -1266,7 +1369,8 @@ int JS_InitDeterministicContext(JSContext *ctx, const JSDeterministicInitOptions + if (options->feature_flags & + ~(JS_DETERMINISTIC_FEATURE_REGEXP | + JS_DETERMINISTIC_FEATURE_PROMISE_JOBS | +- JS_DETERMINISTIC_FEATURE_CONSOLE_SHIM)) { ++ JS_DETERMINISTIC_FEATURE_CONSOLE_SHIM | ++ JS_DETERMINISTIC_FEATURE_STABLE_SORT)) { + JS_ThrowTypeError(ctx, "unknown deterministic feature flags"); + return -1; + } +diff --git a/quickjs.h b/quickjs.h +index bdefdff..22cb907 100644 +--- a/quickjs.h ++++ b/quickjs.h +@@ -348,6 +348,7 @@ static inline JSValue __JS_NewShortBigInt(JSContext *ctx, int64_t d) + #define JS_DETERMINISTIC_FEATURE_REGEXP (1u << 0) + #define JS_DETERMINISTIC_FEATURE_PROMISE_JOBS (1u << 1) + #define JS_DETERMINISTIC_FEATURE_CONSOLE_SHIM (1u << 2) ++#define JS_DETERMINISTIC_FEATURE_STABLE_SORT (1u << 3) + + typedef JSValue JSCFunction(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); + typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); diff --git a/vendor/quickjs-patches/series/0034-add-versioned-quickjs-dv2-byte-string-codecs.patch b/vendor/quickjs-patches/series/0034-add-versioned-quickjs-dv2-byte-string-codecs.patch new file mode 100644 index 0000000..a75ae79 --- /dev/null +++ b/vendor/quickjs-patches/series/0034-add-versioned-quickjs-dv2-byte-string-codecs.patch @@ -0,0 +1,388 @@ +From 62d271e7d40347618067672fd0c54578680ad9b7 Mon Sep 17 00:00:00 2001 +From: Cursor Agent +Date: Sun, 15 Mar 2026 22:20:34 +0000 +Subject: [PATCH 34/51] add versioned quickjs dv2 byte-string codecs + +--- + quickjs-dv.c | 200 ++++++++++++++++++++++++++++++++++++++++++++------- + quickjs.h | 2 + + 2 files changed, 176 insertions(+), 26 deletions(-) + +diff --git a/quickjs-dv.c b/quickjs-dv.c +index 660e8fb..4a22fe6 100644 +--- a/quickjs-dv.c ++++ b/quickjs-dv.c +@@ -18,6 +18,7 @@ extern void js_free(JSContext *ctx, void *ptr); + + #define DV_CBOR_MAJOR_UINT 0 + #define DV_CBOR_MAJOR_NINT 1 ++#define DV_CBOR_MAJOR_BYTES 2 + #define DV_CBOR_MAJOR_TEXT 3 + #define DV_CBOR_MAJOR_ARRAY 4 + #define DV_CBOR_MAJOR_MAP 5 +@@ -305,7 +306,8 @@ static int dv_encode_value(JSContext *ctx, + JSValueConst value, + const JSDvLimits *limits, + uint32_t depth, +- JSDvBuilder *builder); ++ JSDvBuilder *builder, ++ int allow_bytes); + + static const char *dv_tag_name(int tag) + { +@@ -336,7 +338,8 @@ static int dv_encode_array(JSContext *ctx, + JSValueConst value, + const JSDvLimits *limits, + uint32_t depth, +- JSDvBuilder *builder) { ++ JSDvBuilder *builder, ++ int allow_bytes) { + uint32_t next_depth = depth + 1; + if (next_depth > limits->max_depth) { + return dv_throw(ctx, "maxDepth %u exceeded", limits->max_depth); +@@ -370,7 +373,12 @@ static int dv_encode_array(JSContext *ctx, + if (JS_IsException(element)) { + return -1; + } +- int rc = dv_encode_value(ctx, element, limits, next_depth, builder); ++ int rc = dv_encode_value(ctx, ++ element, ++ limits, ++ next_depth, ++ builder, ++ allow_bytes); + JS_FreeValue(ctx, element); + if (rc != 0) { + return -1; +@@ -394,7 +402,8 @@ static int dv_encode_object(JSContext *ctx, + JSValueConst value, + const JSDvLimits *limits, + uint32_t depth, +- JSDvBuilder *builder) { ++ JSDvBuilder *builder, ++ int allow_bytes) { + uint32_t next_depth = depth + 1; + if (next_depth > limits->max_depth) { + return dv_throw(ctx, "maxDepth %u exceeded", limits->max_depth); +@@ -537,7 +546,12 @@ static int dv_encode_object(JSContext *ctx, + if (JS_IsException(prop_val)) { + goto encode_object_error; + } +- int rc = dv_encode_value(ctx, prop_val, limits, next_depth, builder); ++ int rc = dv_encode_value(ctx, ++ prop_val, ++ limits, ++ next_depth, ++ builder, ++ allow_bytes); + JS_FreeValue(ctx, prop_val); + if (rc != 0) { + goto encode_object_error; +@@ -580,7 +594,8 @@ static int dv_encode_value(JSContext *ctx, + JSValueConst value, + const JSDvLimits *limits, + uint32_t depth, +- JSDvBuilder *builder) { ++ JSDvBuilder *builder, ++ int allow_bytes) { + if (depth > limits->max_depth) { + return dv_throw(ctx, "maxDepth %u exceeded", limits->max_depth); + } +@@ -613,14 +628,63 @@ static int dv_encode_value(JSContext *ctx, + return rc; + } + case JS_TAG_OBJECT: { ++ if (allow_bytes) { ++ size_t byte_offset = 0; ++ size_t byte_length = 0; ++ size_t bytes_per_element = 0; ++ JSValue buffer = JS_GetTypedArrayBuffer(ctx, ++ value, ++ &byte_offset, ++ &byte_length, ++ &bytes_per_element); ++ if (!JS_IsException(buffer)) { ++ size_t buffer_length = 0; ++ uint8_t *buffer_ptr = JS_GetArrayBuffer(ctx, &buffer_length, buffer); ++ if (!buffer_ptr) { ++ JS_FreeValue(ctx, buffer); ++ return -1; ++ } ++ if (bytes_per_element != 1) { ++ JS_FreeValue(ctx, buffer); ++ return dv_throw(ctx, "unsupported DV type: typed array"); ++ } ++ if (byte_length > limits->max_string_bytes) { ++ JS_FreeValue(ctx, buffer); ++ return dv_throw(ctx, ++ "byte string exceeds maxByteStringBytes (%zu > %u)", ++ byte_length, ++ limits->max_string_bytes); ++ } ++ if (byte_offset > buffer_length || ++ byte_length > buffer_length - byte_offset) { ++ JS_FreeValue(ctx, buffer); ++ return dv_throw(ctx, "typed array buffer range is invalid"); ++ } ++ ++ int rc = dv_encode_type_and_length(builder, ++ DV_CBOR_MAJOR_BYTES, ++ byte_length); ++ if (rc == 0) { ++ rc = dv_builder_push_bytes(builder, buffer_ptr + byte_offset, byte_length); ++ } ++ JS_FreeValue(ctx, buffer); ++ return rc; ++ } ++ ++ JSValue typed_array_error = JS_GetException(ctx); ++ if (!JS_IsUndefined(typed_array_error)) { ++ JS_FreeValue(ctx, typed_array_error); ++ } ++ } ++ + int is_array = JS_IsArray(ctx, value); + if (is_array < 0) { + return -1; + } + if (is_array) { +- return dv_encode_array(ctx, value, limits, depth, builder); ++ return dv_encode_array(ctx, value, limits, depth, builder, allow_bytes); + } +- return dv_encode_object(ctx, value, limits, depth, builder); ++ return dv_encode_object(ctx, value, limits, depth, builder, allow_bytes); + } + default: + { +@@ -632,10 +696,11 @@ static int dv_encode_value(JSContext *ctx, + } + } + +-int JS_EncodeDV(JSContext *ctx, +- JSValueConst value, +- const JSDvLimits *maybe_limits, +- JSDvBuffer *out_buffer) { ++static int dv_encode_internal(JSContext *ctx, ++ JSValueConst value, ++ const JSDvLimits *maybe_limits, ++ JSDvBuffer *out_buffer, ++ int allow_bytes) { + const JSDvLimits *limits = dv_limits_or_default(maybe_limits); + if (out_buffer) { + out_buffer->data = NULL; +@@ -650,7 +715,7 @@ int JS_EncodeDV(JSContext *ctx, + .max_size = limits->max_encoded_bytes, + }; + +- if (dv_encode_value(ctx, value, limits, 0, &builder) != 0) { ++ if (dv_encode_value(ctx, value, limits, 0, &builder, allow_bytes) != 0) { + dv_builder_free(&builder); + return -1; + } +@@ -664,6 +729,20 @@ int JS_EncodeDV(JSContext *ctx, + return 0; + } + ++int JS_EncodeDV(JSContext *ctx, ++ JSValueConst value, ++ const JSDvLimits *maybe_limits, ++ JSDvBuffer *out_buffer) { ++ return dv_encode_internal(ctx, value, maybe_limits, out_buffer, 0); ++} ++ ++int JS_EncodeDV2(JSContext *ctx, ++ JSValueConst value, ++ const JSDvLimits *maybe_limits, ++ JSDvBuffer *out_buffer) { ++ return dv_encode_internal(ctx, value, maybe_limits, out_buffer, 1); ++} ++ + static int dv_reader_need(JSDvReader *reader, size_t amount) { + if (reader->pos + amount > reader->size) { + JS_ThrowTypeError(reader->ctx, "unexpected end of buffer"); +@@ -746,7 +825,8 @@ static int dv_read_length(JSDvReader *reader, uint8_t additional, uint64_t *out) + static JSValue dv_decode_value(JSContext *ctx, + JSDvReader *reader, + const JSDvLimits *limits, +- uint32_t depth); ++ uint32_t depth, ++ int allow_bytes); + + static JSValue dv_decode_text(JSContext *ctx, + JSDvReader *reader, +@@ -780,11 +860,48 @@ static JSValue dv_decode_text(JSContext *ctx, + return str; + } + ++static JSValue dv_decode_bytes(JSContext *ctx, ++ JSDvReader *reader, ++ const JSDvLimits *limits, ++ uint8_t additional) { ++ uint64_t length64 = 0; ++ if (dv_read_length(reader, additional, &length64) != 0) { ++ return JS_EXCEPTION; ++ } ++ ++ if (length64 > limits->max_string_bytes) { ++ JS_ThrowTypeError(ctx, ++ "byte string exceeds maxByteStringBytes (%" PRIu64 " > %u)", ++ length64, ++ limits->max_string_bytes); ++ return JS_EXCEPTION; ++ } ++ ++ size_t length = (size_t)length64; ++ if (dv_reader_need(reader, length) != 0) { ++ return JS_EXCEPTION; ++ } ++ ++ const uint8_t *bytes = reader->data + reader->pos; ++ JSValue buffer = JS_NewArrayBufferCopy(ctx, bytes, length); ++ reader->pos += length; ++ if (JS_IsException(buffer)) { ++ return JS_EXCEPTION; ++ } ++ ++ JSValue args[1]; ++ args[0] = buffer; ++ JSValue typed = JS_NewTypedArray(ctx, 1, (JSValueConst *)args, JS_TYPED_ARRAY_UINT8); ++ JS_FreeValue(ctx, buffer); ++ return typed; ++} ++ + static JSValue dv_decode_array(JSContext *ctx, + JSDvReader *reader, + const JSDvLimits *limits, + uint32_t depth, +- uint8_t additional) { ++ uint8_t additional, ++ int allow_bytes) { + uint64_t length64 = 0; + if (dv_read_length(reader, additional, &length64) != 0) { + return JS_EXCEPTION; +@@ -810,7 +927,11 @@ static JSValue dv_decode_array(JSContext *ctx, + } + + for (uint32_t i = 0; i < length; i++) { +- JSValue element = dv_decode_value(ctx, reader, limits, depth + 1); ++ JSValue element = dv_decode_value(ctx, ++ reader, ++ limits, ++ depth + 1, ++ allow_bytes); + if (JS_IsException(element)) { + JS_FreeValue(ctx, arr); + return JS_EXCEPTION; +@@ -828,7 +949,8 @@ static JSValue dv_decode_map(JSContext *ctx, + JSDvReader *reader, + const JSDvLimits *limits, + uint32_t depth, +- uint8_t additional) { ++ uint8_t additional, ++ int allow_bytes) { + uint64_t length64 = 0; + if (dv_read_length(reader, additional, &length64) != 0) { + return JS_EXCEPTION; +@@ -918,7 +1040,11 @@ static JSValue dv_decode_map(JSContext *ctx, + } + prev_key_len = key_len; + +- JSValue decoded = dv_decode_value(ctx, reader, limits, depth + 1); ++ JSValue decoded = dv_decode_value(ctx, ++ reader, ++ limits, ++ depth + 1, ++ allow_bytes); + if (JS_IsException(decoded)) { + JS_FreeValue(ctx, key_val); + JS_FreeValue(ctx, obj); +@@ -1014,7 +1140,8 @@ static JSValue dv_decode_simple_or_float(JSContext *ctx, + static JSValue dv_decode_value(JSContext *ctx, + JSDvReader *reader, + const JSDvLimits *limits, +- uint32_t depth) { ++ uint32_t depth, ++ int allow_bytes) { + uint8_t initial = 0; + if (dv_reader_read_u8(reader, &initial) != 0) { + return JS_EXCEPTION; +@@ -1051,12 +1178,18 @@ static JSValue dv_decode_value(JSContext *ctx, + int64_t neg = -1 - (int64_t)value; + return JS_NewInt64(ctx, neg); + } ++ case DV_CBOR_MAJOR_BYTES: ++ if (!allow_bytes) { ++ JS_ThrowTypeError(ctx, "unsupported CBOR major type %u", major); ++ return JS_EXCEPTION; ++ } ++ return dv_decode_bytes(ctx, reader, limits, additional); + case DV_CBOR_MAJOR_TEXT: + return dv_decode_text(ctx, reader, limits, additional); + case DV_CBOR_MAJOR_ARRAY: +- return dv_decode_array(ctx, reader, limits, depth, additional); ++ return dv_decode_array(ctx, reader, limits, depth, additional, allow_bytes); + case DV_CBOR_MAJOR_MAP: +- return dv_decode_map(ctx, reader, limits, depth, additional); ++ return dv_decode_map(ctx, reader, limits, depth, additional, allow_bytes); + case DV_CBOR_MAJOR_SIMPLE: + return dv_decode_simple_or_float(ctx, reader, limits, additional); + default: +@@ -1065,10 +1198,11 @@ static JSValue dv_decode_value(JSContext *ctx, + } + } + +-JSValue JS_DecodeDV(JSContext *ctx, +- const uint8_t *data, +- size_t length, +- const JSDvLimits *maybe_limits) { ++static JSValue dv_decode_internal(JSContext *ctx, ++ const uint8_t *data, ++ size_t length, ++ const JSDvLimits *maybe_limits, ++ int allow_bytes) { + const JSDvLimits *limits = dv_limits_or_default(maybe_limits); + if (length > limits->max_encoded_bytes) { + JS_ThrowTypeError(ctx, +@@ -1085,7 +1219,7 @@ JSValue JS_DecodeDV(JSContext *ctx, + .ctx = ctx, + }; + +- JSValue result = dv_decode_value(ctx, &reader, limits, 0); ++ JSValue result = dv_decode_value(ctx, &reader, limits, 0, allow_bytes); + if (JS_IsException(result)) { + return result; + } +@@ -1099,6 +1233,20 @@ JSValue JS_DecodeDV(JSContext *ctx, + return result; + } + ++JSValue JS_DecodeDV(JSContext *ctx, ++ const uint8_t *data, ++ size_t length, ++ const JSDvLimits *maybe_limits) { ++ return dv_decode_internal(ctx, data, length, maybe_limits, 0); ++} ++ ++JSValue JS_DecodeDV2(JSContext *ctx, ++ const uint8_t *data, ++ size_t length, ++ const JSDvLimits *maybe_limits) { ++ return dv_decode_internal(ctx, data, length, maybe_limits, 1); ++} ++ + void JS_FreeDVBuffer(JSContext *ctx, JSDvBuffer *buffer) { + if (!buffer || !buffer->data) { + return; +diff --git a/quickjs.h b/quickjs.h +index 22cb907..98305a8 100644 +--- a/quickjs.h ++++ b/quickjs.h +@@ -487,6 +487,8 @@ extern const JSDvLimits JS_DV_LIMIT_DEFAULTS; + + int JS_EncodeDV(JSContext *ctx, JSValueConst value, const JSDvLimits *limits, JSDvBuffer *out_buffer); + JSValue JS_DecodeDV(JSContext *ctx, const uint8_t *data, size_t length, const JSDvLimits *limits); ++int JS_EncodeDV2(JSContext *ctx, JSValueConst value, const JSDvLimits *limits, JSDvBuffer *out_buffer); ++JSValue JS_DecodeDV2(JSContext *ctx, const uint8_t *data, size_t length, const JSDvLimits *limits); + void JS_FreeDVBuffer(JSContext *ctx, JSDvBuffer *buffer); + + JSRuntime *JS_GetRuntime(JSContext *ctx); diff --git a/vendor/quickjs-patches/series/0035-add-host.v2-dv2-runtime-byte-boundaries.patch b/vendor/quickjs-patches/series/0035-add-host.v2-dv2-runtime-byte-boundaries.patch new file mode 100644 index 0000000..221afa7 --- /dev/null +++ b/vendor/quickjs-patches/series/0035-add-host.v2-dv2-runtime-byte-boundaries.patch @@ -0,0 +1,498 @@ +From 9af4643da6f8f78d8d57e42fc8e3f1245a83fae8 Mon Sep 17 00:00:00 2001 +From: Cursor Agent +Date: Sun, 15 Mar 2026 23:32:56 +0000 +Subject: [PATCH 35/51] add Host.v2 DV2 runtime byte boundaries + +--- + quickjs-dv.c | 19 ++++++- + quickjs-host.c | 149 +++++++++++++++++++++++++++++++++---------------- + quickjs-host.h | 1 + + quickjs.h | 1 + + 4 files changed, 119 insertions(+), 51 deletions(-) + +diff --git a/quickjs-dv.c b/quickjs-dv.c +index 4a22fe6..cb01756 100644 +--- a/quickjs-dv.c ++++ b/quickjs-dv.c +@@ -889,9 +889,24 @@ static JSValue dv_decode_bytes(JSContext *ctx, + return JS_EXCEPTION; + } + +- JSValue args[1]; ++ JSValue args[3]; + args[0] = buffer; +- JSValue typed = JS_NewTypedArray(ctx, 1, (JSValueConst *)args, JS_TYPED_ARRAY_UINT8); ++ args[1] = JS_NewUint32(ctx, 0); ++ args[2] = JS_NewUint32(ctx, (uint32_t)length); ++ if (JS_IsException(args[1]) || JS_IsException(args[2])) { ++ if (!JS_IsException(args[1])) { ++ JS_FreeValue(ctx, args[1]); ++ } ++ if (!JS_IsException(args[2])) { ++ JS_FreeValue(ctx, args[2]); ++ } ++ JS_FreeValue(ctx, buffer); ++ return JS_EXCEPTION; ++ } ++ ++ JSValue typed = JS_NewTypedArray(ctx, 3, (JSValueConst *)args, JS_TYPED_ARRAY_UINT8); ++ JS_FreeValue(ctx, args[2]); ++ JS_FreeValue(ctx, args[1]); + JS_FreeValue(ctx, buffer); + return typed; + } +diff --git a/quickjs-host.c b/quickjs-host.c +index f468bb3..3030e3b 100644 +--- a/quickjs-host.c ++++ b/quickjs-host.c +@@ -10,6 +10,9 @@ + #define JS_HOST_ERROR_CODE_ENVELOPE_INVALID "HOST_ENVELOPE_INVALID" + #define JS_HOST_ERROR_TAG_ENVELOPE_INVALID "host/envelope_invalid" + ++static JSHostManifest *js_host_find_manifest(JSContext *ctx); ++static const char *js_host_namespace_name(const JSHostManifest *manifest); ++ + static JSValue js_throw_host_error_str(JSContext *ctx, const char *code, const char *tag, JSValueConst details) + { + JSValue ret; +@@ -162,7 +165,9 @@ int JS_ParseHostResponse(JSContext *ctx, + return -1; + } + +- envelope = JS_DecodeDV(ctx, data, length, &JS_DV_LIMIT_DEFAULTS); ++ envelope = validation->allow_bytes ++ ? JS_DecodeDV2(ctx, data, length, &JS_DV_LIMIT_DEFAULTS) ++ : JS_DecodeDV(ctx, data, length, &JS_DV_LIMIT_DEFAULTS); + if (JS_IsException(envelope)) { + has_pending_exception = TRUE; + goto envelope_invalid; +@@ -853,11 +858,13 @@ static JSValue js_deterministic_console_method(JSContext *ctx, + JSValue payload = JS_UNDEFINED; + JSValue args_array = JS_UNDEFINED; + JSValue global = JS_UNDEFINED; ++ JSValue host_root = JS_UNDEFINED; + JSValue host_ns = JS_UNDEFINED; +- JSValue host_v1 = JS_UNDEFINED; + JSValue emit_fn = JS_UNDEFINED; + JSValue call_result = JS_UNDEFINED; + const char *level = js_deterministic_console_level_name(magic); ++ const JSHostManifest *manifest = js_host_find_manifest(ctx); ++ const char *host_namespace = js_host_namespace_name(manifest); + JSValue emit_args[1]; + + (void)this_val; +@@ -894,32 +901,32 @@ static JSValue js_deterministic_console_method(JSContext *ctx, + if (JS_IsException(global)) + goto fail; + +- host_ns = JS_GetPropertyStr(ctx, global, "Host"); ++ host_root = JS_GetPropertyStr(ctx, global, "Host"); ++ if (JS_IsException(host_root)) ++ goto fail; ++ ++ host_ns = JS_GetPropertyStr(ctx, host_root, host_namespace); + if (JS_IsException(host_ns)) + goto fail; + +- host_v1 = JS_GetPropertyStr(ctx, host_ns, "v1"); +- if (JS_IsException(host_v1)) +- goto fail; +- +- emit_fn = JS_GetPropertyStr(ctx, host_v1, "emit"); ++ emit_fn = JS_GetPropertyStr(ctx, host_ns, "emit"); + if (JS_IsException(emit_fn)) + goto fail; + + if (!JS_IsFunction(ctx, emit_fn)) { +- JS_ThrowTypeError(ctx, "console shim requires Host.v1.emit"); ++ JS_ThrowTypeError(ctx, "console shim requires Host.%s.emit", host_namespace); + goto fail; + } + + emit_args[0] = payload; +- call_result = JS_Call(ctx, emit_fn, host_v1, 1, emit_args); ++ call_result = JS_Call(ctx, emit_fn, host_ns, 1, emit_args); + if (JS_IsException(call_result)) + goto fail; + + JS_FreeValue(ctx, call_result); + JS_FreeValue(ctx, emit_fn); +- JS_FreeValue(ctx, host_v1); + JS_FreeValue(ctx, host_ns); ++ JS_FreeValue(ctx, host_root); + JS_FreeValue(ctx, global); + JS_FreeValue(ctx, args_array); + JS_FreeValue(ctx, payload); +@@ -930,10 +937,10 @@ fail: + JS_FreeValue(ctx, call_result); + if (!JS_IsUndefined(emit_fn)) + JS_FreeValue(ctx, emit_fn); +- if (!JS_IsUndefined(host_v1)) +- JS_FreeValue(ctx, host_v1); + if (!JS_IsUndefined(host_ns)) + JS_FreeValue(ctx, host_ns); ++ if (!JS_IsUndefined(host_root)) ++ JS_FreeValue(ctx, host_root); + if (!JS_IsUndefined(global)) + JS_FreeValue(ctx, global); + if (!JS_IsUndefined(args_array)) +@@ -1243,7 +1250,8 @@ int js_deterministic_init_context(JSContext *ctx, uint32_t feature_flags) + ~(JS_DETERMINISTIC_FEATURE_REGEXP | + JS_DETERMINISTIC_FEATURE_PROMISE_JOBS | + JS_DETERMINISTIC_FEATURE_CONSOLE_SHIM | +- JS_DETERMINISTIC_FEATURE_STABLE_SORT)) { ++ JS_DETERMINISTIC_FEATURE_STABLE_SORT | ++ JS_DETERMINISTIC_FEATURE_TYPED_ARRAYS)) { + JS_ThrowTypeError(ctx, "unknown deterministic feature flags"); + return -1; + } +@@ -1256,11 +1264,14 @@ int js_deterministic_init_context(JSContext *ctx, uint32_t feature_flags) + (feature_flags & JS_DETERMINISTIC_FEATURE_CONSOLE_SHIM) != 0; + JS_BOOL stable_sort_enabled = + (feature_flags & JS_DETERMINISTIC_FEATURE_STABLE_SORT) != 0; ++ JS_BOOL typed_arrays_enabled = ++ (feature_flags & JS_DETERMINISTIC_FEATURE_TYPED_ARRAYS) != 0; + + if (JS_AddIntrinsicBaseObjects(ctx) || + JS_AddIntrinsicEval(ctx) || + JS_AddIntrinsicJSON(ctx) || + JS_AddIntrinsicMapSet(ctx) || ++ (typed_arrays_enabled ? JS_AddIntrinsicTypedArrays(ctx) : 0) || + (promise_jobs_enabled ? JS_AddIntrinsicPromise(ctx) : 0) || + js_deterministic_disable_eval(ctx) || + js_deterministic_disable_function(ctx) || +@@ -1270,7 +1281,7 @@ int js_deterministic_init_context(JSContext *ctx, uint32_t feature_flags) + js_deterministic_disable_random(ctx) || + (promise_jobs_enabled ? 0 : js_deterministic_disable_promise(ctx)) || + (promise_jobs_enabled ? js_deterministic_enable_queue_microtask(ctx) : 0) || +- js_deterministic_disable_typed_arrays(ctx) || ++ (typed_arrays_enabled ? 0 : js_deterministic_disable_typed_arrays(ctx)) || + js_deterministic_disable_atomics(ctx) || + (console_shim_enabled ? js_deterministic_enable_console(ctx) + : js_deterministic_disable_console(ctx)) || +@@ -1370,7 +1381,8 @@ int JS_InitDeterministicContext(JSContext *ctx, const JSDeterministicInitOptions + ~(JS_DETERMINISTIC_FEATURE_REGEXP | + JS_DETERMINISTIC_FEATURE_PROMISE_JOBS | + JS_DETERMINISTIC_FEATURE_CONSOLE_SHIM | +- JS_DETERMINISTIC_FEATURE_STABLE_SORT)) { ++ JS_DETERMINISTIC_FEATURE_STABLE_SORT | ++ JS_DETERMINISTIC_FEATURE_TYPED_ARRAYS)) { + JS_ThrowTypeError(ctx, "unknown deterministic feature flags"); + return -1; + } +@@ -1570,7 +1582,7 @@ int JS_HostCall(JSContext *ctx, + } + + /* ------------------------------------------------------------------------- */ +-/* Host manifest parsing and Host.v1 generation (T-040) */ ++/* Host manifest parsing and Host namespace generation (T-040) */ + + extern void *js_malloc(JSContext *ctx, size_t size); + extern void js_free(JSContext *ctx, void *ptr); +@@ -1617,6 +1629,9 @@ typedef struct { + struct JSHostManifest { + JSHostFunctionDef *functions; + size_t function_count; ++ uint32_t abi_version; ++ uint32_t host_namespace_version; ++ int allow_bytes; + }; + + typedef struct { +@@ -1665,6 +1680,13 @@ static JSHostTapeState *js_host_get_tape(JSContext *ctx) + return &node->tape; + } + ++static const char *js_host_namespace_name(const JSHostManifest *manifest) ++{ ++ if (!manifest || manifest->host_namespace_version == 0) ++ return "v1"; ++ return manifest->host_namespace_version == 2 ? "v2" : "v1"; ++} ++ + static void js_host_free_function(JSContext *ctx, JSHostFunctionDef *fn) + { + if (!fn) +@@ -1712,6 +1734,9 @@ static void js_host_manifest_clear(JSContext *ctx, JSHostManifest *manifest) + } + manifest->functions = NULL; + manifest->function_count = 0; ++ manifest->abi_version = 0; ++ manifest->host_namespace_version = 0; ++ manifest->allow_bytes = 0; + } + + static void js_host_tape_free(JSContext *ctx, JSHostTapeState *tape) +@@ -2392,9 +2417,11 @@ done: + return ret; + } + +-static int js_host_build_function_name(JSContext *ctx, JSHostFunctionDef *fn) ++static int js_host_build_function_name(JSContext *ctx, ++ JSHostFunctionDef *fn, ++ uint32_t host_namespace_version) + { +- const char *prefix = "Host.v1"; ++ const char *prefix = host_namespace_version == 2 ? "Host.v2" : "Host.v1"; + size_t total = strlen(prefix) + 1; /* null terminator */ + + for (size_t i = 0; i < fn->path_len; i++) +@@ -2415,7 +2442,8 @@ static int js_host_build_function_name(JSContext *ctx, JSHostFunctionDef *fn) + static int js_host_validate_function(JSContext *ctx, + JSValueConst fn_val, + const char *path, +- JSHostFunctionDef *out_fn) ++ JSHostFunctionDef *out_fn, ++ uint32_t host_namespace_version) + { + const char *required[] = {"fn_id", "js_path", "effect", "arity", "arg_schema", "return_schema", "gas", "limits", "error_codes"}; + JSValue fn_id = JS_UNDEFINED; +@@ -2591,7 +2619,7 @@ static int js_host_validate_function(JSContext *ctx, + } + } + +- if (js_host_build_function_name(ctx, out_fn)) ++ if (js_host_build_function_name(ctx, out_fn, host_namespace_version)) + goto done; + + ret = 0; +@@ -2659,8 +2687,14 @@ static int js_host_validate_manifest(JSContext *ctx, JSValueConst manifest_val, + goto done; + if (js_host_copy_non_empty_string(ctx, abi_id, "manifest.abi_id", &abi_id_str)) + goto done; +- if (strcmp(abi_id_str, "Host.v1") != 0) { +- js_host_manifest_error(ctx, "manifest.abi_id", "unsupported abi_id (expected Host.v1)"); ++ if (strcmp(abi_id_str, "Host.v1") == 0) { ++ out_manifest->host_namespace_version = 1; ++ out_manifest->allow_bytes = 0; ++ } else if (strcmp(abi_id_str, "Host.v2") == 0) { ++ out_manifest->host_namespace_version = 2; ++ out_manifest->allow_bytes = 1; ++ } else { ++ js_host_manifest_error(ctx, "manifest.abi_id", "unsupported abi_id (expected Host.v1 or Host.v2)"); + goto done; + } + +@@ -2670,10 +2704,15 @@ static int js_host_validate_manifest(JSContext *ctx, JSValueConst manifest_val, + uint32_t version = 0; + if (js_host_validate_uint32(ctx, abi_version, "manifest.abi_version", 1, UINT32_MAX, &version)) + goto done; +- if (version != 1) { +- js_host_manifest_error(ctx, "manifest.abi_version", "unsupported abi_version (expected 1)"); ++ if (version != out_manifest->host_namespace_version) { ++ js_host_manifest_error(ctx, ++ "manifest.abi_version", ++ out_manifest->host_namespace_version == 2 ++ ? "unsupported abi_version (expected 2)" ++ : "unsupported abi_version (expected 1)"); + goto done; + } ++ out_manifest->abi_version = version; + + functions = JS_GetPropertyStr(ctx, manifest_val, "functions"); + if (JS_IsException(functions)) +@@ -2704,7 +2743,11 @@ static int js_host_validate_manifest(JSContext *ctx, JSValueConst manifest_val, + char fn_path[96]; + snprintf(fn_path, sizeof(fn_path), "manifest.functions[%zu]", i); + +- if (js_host_validate_function(ctx, fn_val, fn_path, &out_manifest->functions[i])) { ++ if (js_host_validate_function(ctx, ++ fn_val, ++ fn_path, ++ &out_manifest->functions[i], ++ out_manifest->host_namespace_version)) { + JS_FreeValue(ctx, fn_val); + goto done; + } +@@ -2944,7 +2987,9 @@ static JSValue js_host_call_wrapper(JSContext *ctx, + JSDvLimits dv_limits = JS_DV_LIMIT_DEFAULTS; + dv_limits.max_encoded_bytes = fn->max_request_bytes; + +- if (JS_EncodeDV(ctx, args_array, &dv_limits, &req_buf)) { ++ if ((manifest->allow_bytes ++ ? JS_EncodeDV2(ctx, args_array, &dv_limits, &req_buf) ++ : JS_EncodeDV(ctx, args_array, &dv_limits, &req_buf))) { + JS_FreeValue(ctx, args_array); + JS_FreeDVBuffer(ctx, &req_buf); + return JS_EXCEPTION; +@@ -2994,6 +3039,7 @@ static JSValue js_host_call_wrapper(JSContext *ctx, + .max_units = fn->max_units, + .errors = fn->errors, + .error_count = fn->error_count, ++ .allow_bytes = manifest->allow_bytes ? 1 : 0, + }; + + if (JS_ParseHostResponse(ctx, result.data, result.length, &validation, &resp)) +@@ -3064,11 +3110,12 @@ static int js_host_install_functions(JSContext *ctx, JSHostManifest *manifest) + { + JSValue global = JS_UNDEFINED; + JSValue host = JS_UNDEFINED; +- JSValue host_v1 = JS_UNDEFINED; ++ JSValue host_ns = JS_UNDEFINED; + JSValue *namespaces = NULL; + size_t ns_count = 0; + size_t ns_capacity = 0; + int ret = -1; ++ const char *host_namespace = manifest->host_namespace_version == 2 ? "v2" : "v1"; + + global = JS_GetGlobalObject(ctx); + if (JS_IsException(global)) +@@ -3077,11 +3124,11 @@ static int js_host_install_functions(JSContext *ctx, JSHostManifest *manifest) + if (js_host_get_or_create_child(ctx, global, "Host", &host, &namespaces, &ns_count, &ns_capacity)) + goto done; + +- if (js_host_get_or_create_child(ctx, host, "v1", &host_v1, &namespaces, &ns_count, &ns_capacity)) ++ if (js_host_get_or_create_child(ctx, host, host_namespace, &host_ns, &namespaces, &ns_count, &ns_capacity)) + goto done; + + for (size_t i = 0; i < manifest->function_count; i++) { +- JSValue current = JS_DupValue(ctx, host_v1); ++ JSValue current = JS_DupValue(ctx, host_ns); + if (JS_IsException(current)) + goto done; + +@@ -3150,8 +3197,8 @@ done: + JS_FreeValue(ctx, namespaces[i]); + js_free(ctx, namespaces); + } +- if (!JS_IsUndefined(host_v1)) +- JS_FreeValue(ctx, host_v1); ++ if (!JS_IsUndefined(host_ns)) ++ JS_FreeValue(ctx, host_ns); + if (!JS_IsUndefined(host)) + JS_FreeValue(ctx, host); + if (!JS_IsUndefined(global)) +@@ -3683,7 +3730,7 @@ static JSValue js_document_wrapper(JSContext *ctx, + (void)magic; + + if (!func_data || !JS_IsFunction(ctx, func_data[0])) { +- JS_ThrowTypeError(ctx, "Host.v1.document binding is missing"); ++ JS_ThrowTypeError(ctx, "Host document binding is missing"); + return JS_EXCEPTION; + } + +@@ -3701,7 +3748,7 @@ static JSValue js_emit_wrapper(JSContext *ctx, + (void)magic; + + if (!func_data || !JS_IsFunction(ctx, func_data[0])) { +- JS_ThrowTypeError(ctx, "Host.v1.emit binding is missing"); ++ JS_ThrowTypeError(ctx, "Host emit binding is missing"); + return JS_EXCEPTION; + } + +@@ -3925,8 +3972,8 @@ done: + int JS_InitErgonomicGlobals(JSContext *ctx, const uint8_t *context_blob, size_t context_blob_size) + { + JSValue global = JS_UNDEFINED; +- JSValue host = JS_UNDEFINED; +- JSValue host_v1 = JS_UNDEFINED; ++ JSValue host_root = JS_UNDEFINED; ++ JSValue host_ns = JS_UNDEFINED; + JSValue document_ns = JS_UNDEFINED; + JSValue document_get = JS_UNDEFINED; + JSValue document_get_canonical = JS_UNDEFINED; +@@ -3945,14 +3992,18 @@ int JS_InitErgonomicGlobals(JSContext *ctx, const uint8_t *context_blob, size_t + JSValueConst doc_funcs[1]; + JSValueConst emit_funcs[1]; + int ret = -1; ++ const JSHostManifest *manifest = NULL; ++ const char *host_namespace = "v1"; + + if (!ctx) + return -1; + +- if (!js_host_find_manifest(ctx)) { ++ manifest = js_host_find_manifest(ctx); ++ if (!manifest) { + JS_ThrowTypeError(ctx, "abi manifest must be initialized before installing ergonomic globals"); + return -1; + } ++ host_namespace = js_host_namespace_name(manifest); + + if (js_decode_context_blob(ctx, context_blob, context_blob_size, + &event_val, &event_canonical_val, &steps_val, +@@ -3963,15 +4014,15 @@ int JS_InitErgonomicGlobals(JSContext *ctx, const uint8_t *context_blob, size_t + if (JS_IsException(global)) + goto done; + +- host = JS_GetPropertyStr(ctx, global, "Host"); +- if (JS_IsException(host)) ++ host_root = JS_GetPropertyStr(ctx, global, "Host"); ++ if (JS_IsException(host_root)) + goto done; + +- host_v1 = JS_GetPropertyStr(ctx, host, "v1"); +- if (JS_IsException(host_v1)) ++ host_ns = JS_GetPropertyStr(ctx, host_root, host_namespace); ++ if (JS_IsException(host_ns)) + goto done; + +- document_ns = JS_GetPropertyStr(ctx, host_v1, "document"); ++ document_ns = JS_GetPropertyStr(ctx, host_ns, "document"); + if (JS_IsException(document_ns)) + goto done; + +@@ -3984,7 +4035,7 @@ int JS_InitErgonomicGlobals(JSContext *ctx, const uint8_t *context_blob, size_t + goto done; + + if (!JS_IsFunction(ctx, document_get) || !JS_IsFunction(ctx, document_get_canonical)) { +- JS_ThrowTypeError(ctx, "Host.v1.document bindings are missing"); ++ JS_ThrowTypeError(ctx, "Host.%s.document bindings are missing", host_namespace); + goto done; + } + +@@ -4019,13 +4070,13 @@ int JS_InitErgonomicGlobals(JSContext *ctx, const uint8_t *context_blob, size_t + if (JS_PreventExtensions(ctx, document_canonical_fn) < 0) + goto done; + +- emit_call = JS_GetPropertyStr(ctx, host_v1, "emit"); ++ emit_call = JS_GetPropertyStr(ctx, host_ns, "emit"); + if (JS_IsException(emit_call)) + goto done; + + if (!JS_IsUndefined(emit_call)) { + if (!JS_IsFunction(ctx, emit_call)) { +- JS_ThrowTypeError(ctx, "Host.v1.emit binding is missing"); ++ JS_ThrowTypeError(ctx, "Host.%s.emit binding is missing", host_namespace); + goto done; + } + +@@ -4124,10 +4175,10 @@ int JS_InitErgonomicGlobals(JSContext *ctx, const uint8_t *context_blob, size_t + ret = 0; + + done: +- if (!JS_IsUndefined(host_v1)) +- JS_FreeValue(ctx, host_v1); +- if (!JS_IsUndefined(host)) +- JS_FreeValue(ctx, host); ++ if (!JS_IsUndefined(host_ns)) ++ JS_FreeValue(ctx, host_ns); ++ if (!JS_IsUndefined(host_root)) ++ JS_FreeValue(ctx, host_root); + if (!JS_IsUndefined(global)) + JS_FreeValue(ctx, global); + if (!JS_IsUndefined(document_ns)) +diff --git a/quickjs-host.h b/quickjs-host.h +index 1b67157..24b36b4 100644 +--- a/quickjs-host.h ++++ b/quickjs-host.h +@@ -12,6 +12,7 @@ typedef struct JSHostResponseValidation { + uint32_t max_units; + const JSHostErrorEntry *errors; + size_t error_count; ++ uint8_t allow_bytes; + } JSHostResponseValidation; + + typedef struct JSHostResponse { +diff --git a/quickjs.h b/quickjs.h +index 98305a8..3a4208e 100644 +--- a/quickjs.h ++++ b/quickjs.h +@@ -349,6 +349,7 @@ static inline JSValue __JS_NewShortBigInt(JSContext *ctx, int64_t d) + #define JS_DETERMINISTIC_FEATURE_PROMISE_JOBS (1u << 1) + #define JS_DETERMINISTIC_FEATURE_CONSOLE_SHIM (1u << 2) + #define JS_DETERMINISTIC_FEATURE_STABLE_SORT (1u << 3) ++#define JS_DETERMINISTIC_FEATURE_TYPED_ARRAYS (1u << 4) + + typedef JSValue JSCFunction(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); + typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); diff --git a/vendor/quickjs-patches/series/0036-normalize-deterministic-runtime-malloc-usable-size.patch b/vendor/quickjs-patches/series/0036-normalize-deterministic-runtime-malloc-usable-size.patch new file mode 100644 index 0000000..874df5e --- /dev/null +++ b/vendor/quickjs-patches/series/0036-normalize-deterministic-runtime-malloc-usable-size.patch @@ -0,0 +1,21 @@ +From 709a4d14afea81d317535a62e451730940498252 Mon Sep 17 00:00:00 2001 +From: Cursor Agent +Date: Mon, 16 Mar 2026 02:31:14 +0000 +Subject: [PATCH 36/51] Normalize deterministic runtime malloc usable size + +--- + quickjs.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/quickjs.c b/quickjs.c +index 182d253..4f1b250 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -2568,6 +2568,7 @@ int JS_NewDeterministicRuntimeWithFeatures(JSRuntime **out_rt, + rt->deterministic_mode = TRUE; + rt->det_gc_pending = FALSE; + rt->det_gc_alloc_bytes = 0; ++ rt->mf.js_malloc_usable_size = js_malloc_usable_size_unknown; + #ifdef __EMSCRIPTEN__ + rt->host_call_func = js_wasm_host_call; + #else diff --git a/vendor/quickjs-patches/series/0037-trace-host-call-gas-counters-in-quickjs.patch b/vendor/quickjs-patches/series/0037-trace-host-call-gas-counters-in-quickjs.patch new file mode 100644 index 0000000..c65c320 --- /dev/null +++ b/vendor/quickjs-patches/series/0037-trace-host-call-gas-counters-in-quickjs.patch @@ -0,0 +1,121 @@ +From 496d1340a0a6164332274cb296c6f6ea9ec640df Mon Sep 17 00:00:00 2001 +From: Cursor Agent +Date: Mon, 16 Mar 2026 03:34:40 +0000 +Subject: [PATCH 37/51] Trace host-call gas counters in QuickJS + +--- + quickjs-host.c | 10 ++++++++-- + quickjs-internal.h | 2 ++ + quickjs.c | 28 ++++++++++++++++++++++++++++ + quickjs.h | 4 ++++ + 4 files changed, 42 insertions(+), 2 deletions(-) + +diff --git a/quickjs-host.c b/quickjs-host.c +index 3030e3b..420291a 100644 +--- a/quickjs-host.c ++++ b/quickjs-host.c +@@ -2874,7 +2874,10 @@ static int js_host_charge_pre(JSContext *ctx, const JSHostFunctionDef *fn, size_ + } + + charge += arg_part; +- return JS_UseGas(ctx, charge); ++ if (JS_UseGas(ctx, charge) != 0) ++ return -1; ++ js_gas_trace_record_host_call_pre(ctx, charge); ++ return 0; + } + + static int js_host_charge_post(JSContext *ctx, const JSHostFunctionDef *fn, size_t resp_len, uint32_t units) +@@ -2889,7 +2892,10 @@ static int js_host_charge_post(JSContext *ctx, const JSHostFunctionDef *fn, size + } + + charge += resp_part + unit_part; +- return JS_UseGas(ctx, charge); ++ if (JS_UseGas(ctx, charge) != 0) ++ return -1; ++ js_gas_trace_record_host_call_post(ctx, charge); ++ return 0; + } + + static JSValue js_host_call_wrapper(JSContext *ctx, +diff --git a/quickjs-internal.h b/quickjs-internal.h +index 955a44e..78d6200 100644 +--- a/quickjs-internal.h ++++ b/quickjs-internal.h +@@ -31,6 +31,8 @@ void js_deterministic_set_manifest_state(JSContext *ctx, + + int js_deterministic_init_context(JSContext *ctx, uint32_t feature_flags); + int js_deterministic_install_json(JSContext *ctx); ++void js_gas_trace_record_host_call_pre(JSContext *ctx, uint64_t gas_cost); ++void js_gas_trace_record_host_call_post(JSContext *ctx, uint64_t gas_cost); + + int js_reserve_host_response_buffer(JSContext *ctx, uint32_t capacity); + uint8_t *js_get_host_response_buffer(JSContext *ctx); +diff --git a/quickjs.c b/quickjs.c +index 4f1b250..609c68a 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -1155,6 +1155,10 @@ struct JSGasTraceData { + uint64_t json_stringify_object_entry_count; + uint64_t json_stringify_array_element_count; + uint64_t json_stringify_sort_comparison_count; ++ uint64_t host_call_pre_count; ++ uint64_t host_call_pre_gas; ++ uint64_t host_call_post_count; ++ uint64_t host_call_post_gas; + }; + + static void js_gas_trace_reset_counts(JSGasTraceData *trace) +@@ -1259,6 +1263,26 @@ static void js_gas_trace_record_json_stringify(JSContext *ctx, + trace->json_stringify_sort_comparison_count += sort_comparison_count; + } + ++void js_gas_trace_record_host_call_pre(JSContext *ctx, uint64_t gas_cost) ++{ ++ JSGasTraceData *trace = js_gas_trace_or_null(ctx); ++ if (!trace) ++ return; ++ ++ trace->host_call_pre_count++; ++ trace->host_call_pre_gas += gas_cost; ++} ++ ++void js_gas_trace_record_host_call_post(JSContext *ctx, uint64_t gas_cost) ++{ ++ JSGasTraceData *trace = js_gas_trace_or_null(ctx); ++ if (!trace) ++ return; ++ ++ trace->host_call_post_count++; ++ trace->host_call_post_gas += gas_cost; ++} ++ + static int JS_InitAtoms(JSRuntime *rt); + static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len, + int atom_type); +@@ -2773,6 +2797,10 @@ int JS_ReadGasTrace(JSContext *ctx, JSGasTrace *out_trace) + out_trace->json_stringify_object_entry_count = trace->json_stringify_object_entry_count; + out_trace->json_stringify_array_element_count = trace->json_stringify_array_element_count; + out_trace->json_stringify_sort_comparison_count = trace->json_stringify_sort_comparison_count; ++ out_trace->host_call_pre_count = trace->host_call_pre_count; ++ out_trace->host_call_pre_gas = trace->host_call_pre_gas; ++ out_trace->host_call_post_count = trace->host_call_post_count; ++ out_trace->host_call_post_gas = trace->host_call_post_gas; + + return 0; + } +diff --git a/quickjs.h b/quickjs.h +index 3a4208e..3baa40a 100644 +--- a/quickjs.h ++++ b/quickjs.h +@@ -440,6 +440,10 @@ typedef struct JSGasTrace { + uint64_t json_stringify_object_entry_count; + uint64_t json_stringify_array_element_count; + uint64_t json_stringify_sort_comparison_count; ++ uint64_t host_call_pre_count; ++ uint64_t host_call_pre_gas; ++ uint64_t host_call_post_count; ++ uint64_t host_call_post_gas; + } JSGasTrace; + int JS_EnableGasTrace(JSContext *ctx, int enabled); + int JS_ResetGasTrace(JSContext *ctx); diff --git a/vendor/quickjs-patches/series/0038-tune-deterministic-allocation-metering-normalization.patch b/vendor/quickjs-patches/series/0038-tune-deterministic-allocation-metering-normalization.patch new file mode 100644 index 0000000..5de9e08 --- /dev/null +++ b/vendor/quickjs-patches/series/0038-tune-deterministic-allocation-metering-normalization.patch @@ -0,0 +1,63 @@ +From 9a07074b2b2d94f3d5061e75692d78963574cf2b Mon Sep 17 00:00:00 2001 +From: Cursor Agent +Date: Mon, 16 Mar 2026 04:28:07 +0000 +Subject: [PATCH 38/51] Tune deterministic allocation metering normalization + +--- + quickjs.c | 27 ++++++++++++++++++++++++--- + 1 file changed, 24 insertions(+), 3 deletions(-) + +diff --git a/quickjs.c b/quickjs.c +index 609c68a..9f1263d 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -1594,25 +1594,46 @@ static uint64_t js_gas_allocation_cost(size_t size) + return JS_GAS_ALLOC_BASE + units; + } + ++static size_t js_det_normalize_allocation_size(JSRuntime *rt, size_t size) ++{ ++ if (!rt || !rt->deterministic_mode || size == 0) ++ return size; ++ ++#if UINTPTR_MAX > 0xffffffff ++ { ++ size_t scaled_size; ++ ++ if (size > (SIZE_MAX - 3) / 3) ++ return SIZE_MAX; ++ ++ scaled_size = size * 3 + 3; ++ return scaled_size / 4; ++ } ++#else ++ return size; ++#endif ++} ++ + static int js_charge_gas_allocation_ctx(JSContext *ctx, size_t size) + { + JSRuntime *rt = ctx->rt; ++ size_t metered_size = js_det_normalize_allocation_size(rt, size); + uint64_t gas_cost; + + if (rt->in_out_of_gas || rt->current_exception_is_uncatchable) + return 0; + + if (rt->deterministic_mode) { +- rt->det_gc_alloc_bytes += size; ++ rt->det_gc_alloc_bytes += metered_size; + if (rt->det_gc_alloc_bytes >= JS_DET_GC_THRESHOLD_BYTES) + rt->det_gc_pending = TRUE; + } + +- gas_cost = js_gas_allocation_cost(size); ++ gas_cost = js_gas_allocation_cost(metered_size); + if (JS_UseGas(ctx, gas_cost)) + return -1; + +- js_gas_trace_record_allocation(ctx, size, gas_cost); ++ js_gas_trace_record_allocation(ctx, metered_size, gas_cost); + return 0; + } + diff --git a/vendor/quickjs-patches/series/0039-retune-deterministic-allocation-scaling-for-parity.patch b/vendor/quickjs-patches/series/0039-retune-deterministic-allocation-scaling-for-parity.patch new file mode 100644 index 0000000..5cb3ca3 --- /dev/null +++ b/vendor/quickjs-patches/series/0039-retune-deterministic-allocation-scaling-for-parity.patch @@ -0,0 +1,37 @@ +From eded35d8be88b7bfe1f1e2e94adf89424915a58f Mon Sep 17 00:00:00 2001 +From: Cursor Agent +Date: Mon, 16 Mar 2026 05:01:53 +0000 +Subject: [PATCH 39/51] Retune deterministic allocation scaling for parity + +--- + quickjs.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/quickjs.c b/quickjs.c +index 9f1263d..047f8ec 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -1572,7 +1572,7 @@ static void js_trigger_gc(JSRuntime *rt, size_t size) + } + } + +-#define JS_GAS_ALLOC_BASE 3 ++#define JS_GAS_ALLOC_BASE 0 + #define JS_GAS_ALLOC_PER_BYTE_SHIFT 4 + #define JS_DET_GC_THRESHOLD_BYTES (512 * 1024) + +@@ -1603,11 +1603,10 @@ static size_t js_det_normalize_allocation_size(JSRuntime *rt, size_t size) + { + size_t scaled_size; + +- if (size > (SIZE_MAX - 3) / 3) ++ if (size > (SIZE_MAX - 30) / 26) + return SIZE_MAX; +- +- scaled_size = size * 3 + 3; +- return scaled_size / 4; ++ scaled_size = size * 26 + 30; ++ return scaled_size / 31; + } + #else + return size; diff --git a/vendor/quickjs-patches/series/0040-chore-bump-gas-version-to-3.patch b/vendor/quickjs-patches/series/0040-chore-bump-gas-version-to-3.patch new file mode 100644 index 0000000..e57c9f8 --- /dev/null +++ b/vendor/quickjs-patches/series/0040-chore-bump-gas-version-to-3.patch @@ -0,0 +1,22 @@ +From 9ccd2319e58a80c2da8c32f32b9ebac5efcac857 Mon Sep 17 00:00:00 2001 +From: Cursor Agent +Date: Mon, 16 Mar 2026 10:23:38 +0000 +Subject: [PATCH 40/51] chore: bump gas version to 3 + +--- + quickjs.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/quickjs.h b/quickjs.h +index 3baa40a..469c728 100644 +--- a/quickjs.h ++++ b/quickjs.h +@@ -355,7 +355,7 @@ typedef JSValue JSCFunction(JSContext *ctx, JSValueConst this_val, int argc, JSV + typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); + typedef JSValue JSCFunctionData(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic, JSValue *func_data); + +-#define JS_GAS_VERSION_LATEST 2 ++#define JS_GAS_VERSION_LATEST 3 + #define JS_GAS_UNLIMITED UINT64_C(0xffffffffffffffff) + + typedef struct JSMallocState { diff --git a/vendor/quickjs-patches/series/0041-feat-add-tagged-gas-charge-tape-tracing.patch b/vendor/quickjs-patches/series/0041-feat-add-tagged-gas-charge-tape-tracing.patch new file mode 100644 index 0000000..c8660c0 --- /dev/null +++ b/vendor/quickjs-patches/series/0041-feat-add-tagged-gas-charge-tape-tracing.patch @@ -0,0 +1,449 @@ +From 268c9634eb68aebc450feec0b580d9ec67b379fa Mon Sep 17 00:00:00 2001 +From: Cursor Agent +Date: Mon, 16 Mar 2026 10:49:01 +0000 +Subject: [PATCH 41/51] feat: add tagged gas charge tape tracing + +--- + quickjs-det-json.c | 15 +++- + quickjs-host.c | 14 ++- + quickjs.c | 210 +++++++++++++++++++++++++++++++++++++++++++-- + quickjs.h | 35 ++++++++ + 4 files changed, 262 insertions(+), 12 deletions(-) + +diff --git a/quickjs-det-json.c b/quickjs-det-json.c +index 7cdfcfb..d69d761 100644 +--- a/quickjs-det-json.c ++++ b/quickjs-det-json.c +@@ -17,6 +17,9 @@ + #define JS_GAS_JSON_STRINGIFY_OUTPUT_BYTE 1 + #define JS_GAS_JSON_STRINGIFY_SORT_COMPARISON 1 + ++#define JS_GAS_SITE_JSON_PARSE UINT32_C(3001) ++#define JS_GAS_SITE_JSON_STRINGIFY UINT32_C(3002) ++ + typedef struct JSDetJSONStringifyKeyEntry { + JSAtom atom; + uint8_t *encoded_key; +@@ -67,7 +70,11 @@ static int js_det_json_parse_charge(JSContext *ctx, + uint64_t object_entry_count, + uint64_t array_element_count) + { +- if (JS_UseGas(ctx, gas_cost) != 0) ++ if (JS_UseGasAt(ctx, ++ gas_cost, ++ JS_GAS_SITE_JSON_PARSE, ++ JS_GAS_CHARGE_KIND_JSON_PARSE, ++ value_count + object_entry_count + array_element_count) != 0) + return -1; + js_gas_trace_record_json_parse(ctx, gas_cost, count_call, input_bytes, + value_count, object_entry_count, +@@ -84,7 +91,11 @@ static int js_det_json_stringify_charge(JSContext *ctx, + uint64_t array_element_count, + uint64_t sort_comparison_count) + { +- if (JS_UseGas(ctx, gas_cost) != 0) ++ if (JS_UseGasAt(ctx, ++ gas_cost, ++ JS_GAS_SITE_JSON_STRINGIFY, ++ JS_GAS_CHARGE_KIND_JSON_STRINGIFY, ++ value_count + object_entry_count + array_element_count) != 0) + return -1; + js_gas_trace_record_json_stringify(ctx, gas_cost, count_call, output_bytes, + value_count, object_entry_count, +diff --git a/quickjs-host.c b/quickjs-host.c +index 420291a..0159d1e 100644 +--- a/quickjs-host.c ++++ b/quickjs-host.c +@@ -9,6 +9,8 @@ + #define JS_HOST_ERROR_TAG_TRANSPORT "host/transport" + #define JS_HOST_ERROR_CODE_ENVELOPE_INVALID "HOST_ENVELOPE_INVALID" + #define JS_HOST_ERROR_TAG_ENVELOPE_INVALID "host/envelope_invalid" ++#define JS_GAS_SITE_HOST_CALL_PRE UINT32_C(2001) ++#define JS_GAS_SITE_HOST_CALL_POST UINT32_C(2002) + + static JSHostManifest *js_host_find_manifest(JSContext *ctx); + static const char *js_host_namespace_name(const JSHostManifest *manifest); +@@ -2874,7 +2876,11 @@ static int js_host_charge_pre(JSContext *ctx, const JSHostFunctionDef *fn, size_ + } + + charge += arg_part; +- if (JS_UseGas(ctx, charge) != 0) ++ if (JS_UseGasAt(ctx, ++ charge, ++ JS_GAS_SITE_HOST_CALL_PRE, ++ JS_GAS_CHARGE_KIND_HOST_CALL_PRE, ++ req_len) != 0) + return -1; + js_gas_trace_record_host_call_pre(ctx, charge); + return 0; +@@ -2892,7 +2898,11 @@ static int js_host_charge_post(JSContext *ctx, const JSHostFunctionDef *fn, size + } + + charge += resp_part + unit_part; +- if (JS_UseGas(ctx, charge) != 0) ++ if (JS_UseGasAt(ctx, ++ charge, ++ JS_GAS_SITE_HOST_CALL_POST, ++ JS_GAS_CHARGE_KIND_HOST_CALL_POST, ++ resp_len) != 0) + return -1; + js_gas_trace_record_host_call_post(ctx, charge); + return 0; +diff --git a/quickjs.c b/quickjs.c +index 047f8ec..6d5aba6 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -517,6 +517,7 @@ struct JSContext { + uint32_t host_call_resp_capacity; + + JSGasTraceData *gas_trace; ++ struct JSGasChargeTapeData *gas_charge_tape; + BOOL deterministic_mode; + }; + +@@ -1161,6 +1162,19 @@ struct JSGasTraceData { + uint64_t host_call_post_gas; + }; + ++typedef struct JSGasChargeTapeData { ++ BOOL enabled; ++ size_t capacity; ++ size_t count; ++ size_t head; ++ JSGasChargeRecord *records; ++} JSGasChargeTapeData; ++ ++#define JS_GAS_SITE_OPCODE_DISPATCH UINT32_C(1) ++#define JS_GAS_SITE_ALLOCATION UINT32_C(2) ++#define JS_GAS_SITE_ARRAY_CALLBACK_BASE UINT32_C(3) ++#define JS_GAS_SITE_ARRAY_CALLBACK_PER_ELEMENT UINT32_C(4) ++ + static void js_gas_trace_reset_counts(JSGasTraceData *trace) + { + BOOL enabled = trace->enabled; +@@ -1283,6 +1297,50 @@ void js_gas_trace_record_host_call_post(JSContext *ctx, uint64_t gas_cost) + trace->host_call_post_gas += gas_cost; + } + ++static JSGasChargeTapeData *js_gas_charge_tape_or_null(JSContext *ctx) ++{ ++ if (!ctx || !ctx->gas_charge_tape || !ctx->gas_charge_tape->enabled) ++ return NULL; ++ return ctx->gas_charge_tape; ++} ++ ++static JSGasChargeTapeData *js_gas_charge_tape_ensure(JSContext *ctx) ++{ ++ if (!ctx->gas_charge_tape) { ++ ctx->gas_charge_tape = js_mallocz_rt(ctx->rt, sizeof(JSGasChargeTapeData)); ++ } ++ return ctx->gas_charge_tape; ++} ++ ++static void js_gas_charge_tape_append(JSContext *ctx, ++ uint32_t site_id, ++ uint16_t kind, ++ uint16_t flags, ++ uint64_t amount, ++ uint64_t logical_units, ++ uint64_t gas_before, ++ uint64_t gas_after) ++{ ++ JSGasChargeTapeData *tape = js_gas_charge_tape_or_null(ctx); ++ size_t idx; ++ ++ if (!tape || tape->capacity == 0 || !tape->records) ++ return; ++ ++ idx = tape->head; ++ tape->records[idx].site_id = site_id; ++ tape->records[idx].kind = kind; ++ tape->records[idx].flags = flags; ++ tape->records[idx].amount = amount; ++ tape->records[idx].logical_units = logical_units; ++ tape->records[idx].gas_before = gas_before; ++ tape->records[idx].gas_after = gas_after; ++ ++ if (tape->count < tape->capacity) ++ tape->count++; ++ tape->head = (tape->head + 1) % tape->capacity; ++} ++ + static int JS_InitAtoms(JSRuntime *rt); + static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len, + int atom_type); +@@ -1629,7 +1687,11 @@ static int js_charge_gas_allocation_ctx(JSContext *ctx, size_t size) + } + + gas_cost = js_gas_allocation_cost(metered_size); +- if (JS_UseGas(ctx, gas_cost)) ++ if (JS_UseGasAt(ctx, ++ gas_cost, ++ JS_GAS_SITE_ALLOCATION, ++ JS_GAS_CHARGE_KIND_ALLOCATION, ++ metered_size)) + return -1; + + js_gas_trace_record_allocation(ctx, metered_size, gas_cost); +@@ -2825,21 +2887,124 @@ int JS_ReadGasTrace(JSContext *ctx, JSGasTrace *out_trace) + return 0; + } + +-int JS_UseGas(JSContext *ctx, uint64_t amount) ++int JS_EnableGasChargeTape(JSContext *ctx, size_t capacity) + { ++ JSGasChargeTapeData *tape; ++ JSGasChargeRecord *records = NULL; ++ ++ if (!ctx) ++ return -1; ++ if (capacity > JS_GAS_CHARGE_TAPE_MAX_CAPACITY) { ++ JS_ThrowTypeError(ctx, "gas charge tape capacity exceeds max (%u)", JS_GAS_CHARGE_TAPE_MAX_CAPACITY); ++ return -1; ++ } ++ ++ tape = js_gas_charge_tape_ensure(ctx); ++ if (!tape) ++ return -1; ++ ++ if (capacity > 0) { ++ records = js_mallocz_rt(ctx->rt, sizeof(JSGasChargeRecord) * capacity); ++ if (!records) ++ return -1; ++ } ++ ++ if (tape->records) ++ js_free_rt(ctx->rt, tape->records); ++ tape->records = records; ++ tape->capacity = capacity; ++ tape->count = 0; ++ tape->head = 0; ++ tape->enabled = capacity > 0 ? TRUE : FALSE; ++ return 0; ++} ++ ++int JS_ResetGasChargeTape(JSContext *ctx) ++{ ++ JSGasChargeTapeData *tape; ++ ++ if (!ctx || !ctx->gas_charge_tape) ++ return -1; ++ ++ tape = ctx->gas_charge_tape; ++ if (tape->records && tape->capacity > 0) ++ memset(tape->records, 0, sizeof(JSGasChargeRecord) * tape->capacity); ++ tape->count = 0; ++ tape->head = 0; ++ return 0; ++} ++ ++size_t JS_GetGasChargeTapeLength(JSContext *ctx) ++{ ++ if (!ctx || !ctx->gas_charge_tape) ++ return 0; ++ return ctx->gas_charge_tape->count; ++} ++ ++int JS_ReadGasChargeTape(JSContext *ctx, ++ JSGasChargeRecord *out_records, ++ size_t max_records, ++ size_t *out_count) ++{ ++ JSGasChargeTapeData *tape; ++ size_t to_copy, start, i; ++ ++ if (!ctx || !ctx->gas_charge_tape) ++ return -1; ++ ++ tape = ctx->gas_charge_tape; ++ if (out_count) ++ *out_count = 0; ++ ++ if (!out_records || max_records == 0 || tape->count == 0 || tape->capacity == 0 || !tape->records) ++ return 0; ++ ++ to_copy = tape->count < max_records ? tape->count : max_records; ++ if (out_count) ++ *out_count = to_copy; ++ start = (tape->head + tape->capacity - tape->count) % tape->capacity; ++ for (i = 0; i < to_copy; i++) { ++ size_t idx = (start + i) % tape->capacity; ++ out_records[i] = tape->records[idx]; ++ } ++ return 0; ++} ++ ++int JS_UseGasAt(JSContext *ctx, ++ uint64_t amount, ++ uint32_t site_id, ++ uint16_t kind, ++ uint64_t logical_units) ++{ ++ uint64_t gas_before; ++ uint64_t gas_after; ++ uint16_t flags = 0; ++ + if (ctx->gas_limit == JS_GAS_UNLIMITED) + return 0; + if (amount == 0) + return 0; ++ ++ gas_before = ctx->gas_remaining; + if (amount > ctx->gas_remaining) { + ctx->gas_remaining = 0; ++ gas_after = 0; ++ js_gas_charge_tape_append(ctx, site_id, kind, flags, amount, logical_units, gas_before, gas_after); + JS_ThrowOutOfGas(ctx); + return -1; + } + ctx->gas_remaining -= amount; ++ gas_after = ctx->gas_remaining; ++ flags |= JS_GAS_CHARGE_FLAG_APPLIED; ++ js_gas_charge_tape_append(ctx, site_id, kind, flags, amount, logical_units, gas_before, gas_after); + return 0; + } + ++int JS_UseGas(JSContext *ctx, uint64_t amount) ++{ ++ return JS_UseGasAt(ctx, amount, 0, JS_GAS_CHARGE_KIND_UNKNOWN, 0); ++} ++ + int JS_RunGCCheckpoint(JSContext *ctx) + { + JSRuntime *rt = ctx->rt; +@@ -3042,6 +3207,11 @@ void JS_FreeContext(JSContext *ctx) + remove_gc_object(&ctx->header); + if (ctx->gas_trace) + js_free_rt(ctx->rt, ctx->gas_trace); ++ if (ctx->gas_charge_tape) { ++ if (ctx->gas_charge_tape->records) ++ js_free_rt(ctx->rt, ctx->gas_charge_tape->records); ++ js_free_rt(ctx->rt, ctx->gas_charge_tape); ++ } + js_free_rt(ctx->rt, ctx); + } + +@@ -18122,7 +18292,11 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, + JSValue *call_argv; + opcode = *pc++; + uint16_t gas_cost = js_get_opcode_gas_cost(opcode); +- if (unlikely(JS_UseGas(ctx, gas_cost) != 0)) ++ if (unlikely(JS_UseGasAt(ctx, ++ gas_cost, ++ JS_GAS_SITE_OPCODE_DISPATCH, ++ JS_GAS_CHARGE_KIND_OPCODE, ++ opcode) != 0)) + goto exception; + js_gas_trace_record_opcode(ctx, opcode, gas_cost); + +@@ -42185,7 +42359,11 @@ static JSValue js_array_every(JSContext *ctx, JSValueConst this_val, + obj = JS_UNDEFINED; + ret = JS_UNDEFINED; + val = JS_UNDEFINED; +- if (unlikely(JS_UseGas(ctx, JS_GAS_ARRAY_CB_BASE) != 0)) ++ if (unlikely(JS_UseGasAt(ctx, ++ JS_GAS_ARRAY_CB_BASE, ++ JS_GAS_SITE_ARRAY_CALLBACK_BASE, ++ JS_GAS_CHARGE_KIND_ARRAY_CALLBACK_BASE, ++ 1) != 0)) + goto exception; + js_gas_trace_record_array_cb(ctx, JS_GAS_ARRAY_CB_BASE, FALSE); + if (special & special_TA) { +@@ -42242,7 +42420,11 @@ static JSValue js_array_every(JSContext *ctx, JSValueConst this_val, + n = 0; + + for(k = 0; k < len; k++) { +- if (unlikely(JS_UseGas(ctx, JS_GAS_ARRAY_CB_PER_ELEMENT) != 0)) ++ if (unlikely(JS_UseGasAt(ctx, ++ JS_GAS_ARRAY_CB_PER_ELEMENT, ++ JS_GAS_SITE_ARRAY_CALLBACK_PER_ELEMENT, ++ JS_GAS_CHARGE_KIND_ARRAY_CALLBACK_PER_ELEMENT, ++ 1) != 0)) + goto exception; + js_gas_trace_record_array_cb(ctx, JS_GAS_ARRAY_CB_PER_ELEMENT, TRUE); + if (special & special_TA) { +@@ -42349,7 +42531,11 @@ static JSValue js_array_reduce(JSContext *ctx, JSValueConst this_val, + obj = JS_UNDEFINED; + acc = JS_UNDEFINED; + val = JS_UNDEFINED; +- if (unlikely(JS_UseGas(ctx, JS_GAS_ARRAY_CB_BASE) != 0)) ++ if (unlikely(JS_UseGasAt(ctx, ++ JS_GAS_ARRAY_CB_BASE, ++ JS_GAS_SITE_ARRAY_CALLBACK_BASE, ++ JS_GAS_CHARGE_KIND_ARRAY_CALLBACK_BASE, ++ 1) != 0)) + goto exception; + js_gas_trace_record_array_cb(ctx, JS_GAS_ARRAY_CB_BASE, FALSE); + if (special & special_TA) { +@@ -42372,7 +42558,11 @@ static JSValue js_array_reduce(JSContext *ctx, JSValueConst this_val, + acc = JS_DupValue(ctx, argv[1]); + } else { + for(;;) { +- if (unlikely(JS_UseGas(ctx, JS_GAS_ARRAY_CB_PER_ELEMENT) != 0)) ++ if (unlikely(JS_UseGasAt(ctx, ++ JS_GAS_ARRAY_CB_PER_ELEMENT, ++ JS_GAS_SITE_ARRAY_CALLBACK_PER_ELEMENT, ++ JS_GAS_CHARGE_KIND_ARRAY_CALLBACK_PER_ELEMENT, ++ 1) != 0)) + goto exception; + js_gas_trace_record_array_cb(ctx, JS_GAS_ARRAY_CB_PER_ELEMENT, TRUE); + if (k >= len) { +@@ -42397,7 +42587,11 @@ static JSValue js_array_reduce(JSContext *ctx, JSValueConst this_val, + } + for (; k < len; k++) { + k1 = (special & special_reduceRight) ? len - k - 1 : k; +- if (unlikely(JS_UseGas(ctx, JS_GAS_ARRAY_CB_PER_ELEMENT) != 0)) ++ if (unlikely(JS_UseGasAt(ctx, ++ JS_GAS_ARRAY_CB_PER_ELEMENT, ++ JS_GAS_SITE_ARRAY_CALLBACK_PER_ELEMENT, ++ JS_GAS_CHARGE_KIND_ARRAY_CALLBACK_PER_ELEMENT, ++ 1) != 0)) + goto exception; + js_gas_trace_record_array_cb(ctx, JS_GAS_ARRAY_CB_PER_ELEMENT, TRUE); + if (special & special_TA) { +diff --git a/quickjs.h b/quickjs.h +index 469c728..8f0ef0a 100644 +--- a/quickjs.h ++++ b/quickjs.h +@@ -448,6 +448,41 @@ typedef struct JSGasTrace { + int JS_EnableGasTrace(JSContext *ctx, int enabled); + int JS_ResetGasTrace(JSContext *ctx); + int JS_ReadGasTrace(JSContext *ctx, JSGasTrace *out_trace); ++ ++typedef enum JSGasChargeKind { ++ JS_GAS_CHARGE_KIND_UNKNOWN = 0, ++ JS_GAS_CHARGE_KIND_OPCODE = 1, ++ JS_GAS_CHARGE_KIND_ARRAY_CALLBACK_BASE = 2, ++ JS_GAS_CHARGE_KIND_ARRAY_CALLBACK_PER_ELEMENT = 3, ++ JS_GAS_CHARGE_KIND_ALLOCATION = 4, ++ JS_GAS_CHARGE_KIND_JSON_PARSE = 5, ++ JS_GAS_CHARGE_KIND_JSON_STRINGIFY = 6, ++ JS_GAS_CHARGE_KIND_HOST_CALL_PRE = 7, ++ JS_GAS_CHARGE_KIND_HOST_CALL_POST = 8, ++} JSGasChargeKind; ++ ++#define JS_GAS_CHARGE_FLAG_APPLIED (1u << 0) ++#define JS_GAS_CHARGE_TAPE_MAX_CAPACITY 8192 ++ ++typedef struct JSGasChargeRecord { ++ uint32_t site_id; ++ uint16_t kind; ++ uint16_t flags; ++ uint64_t amount; ++ uint64_t logical_units; ++ uint64_t gas_before; ++ uint64_t gas_after; ++} JSGasChargeRecord; ++ ++int JS_EnableGasChargeTape(JSContext *ctx, size_t capacity); ++int JS_ResetGasChargeTape(JSContext *ctx); ++size_t JS_GetGasChargeTapeLength(JSContext *ctx); ++int JS_ReadGasChargeTape(JSContext *ctx, JSGasChargeRecord *out_records, size_t max_records, size_t *out_count); ++int JS_UseGasAt(JSContext *ctx, ++ uint64_t amount, ++ uint32_t site_id, ++ uint16_t kind, ++ uint64_t logical_units); + int JS_UseGas(JSContext *ctx, uint64_t amount); + + #define JS_HOST_CALL_TRANSPORT_ERROR UINT32_C(0xffffffff) diff --git a/vendor/quickjs-patches/series/0042-feat-split-allocation-trace-requested-and-charged-by.patch b/vendor/quickjs-patches/series/0042-feat-split-allocation-trace-requested-and-charged-by.patch new file mode 100644 index 0000000..7bba213 --- /dev/null +++ b/vendor/quickjs-patches/series/0042-feat-split-allocation-trace-requested-and-charged-by.patch @@ -0,0 +1,97 @@ +From 4a9a15b132ef0e4af253b1370ee726cb453dbeca Mon Sep 17 00:00:00 2001 +From: Cursor Agent +Date: Mon, 16 Mar 2026 11:06:18 +0000 +Subject: [PATCH 42/51] feat: split allocation trace requested and charged + bytes + +--- + quickjs.c | 20 +++++++++++++------- + quickjs.h | 1 + + 2 files changed, 14 insertions(+), 7 deletions(-) + +diff --git a/quickjs.c b/quickjs.c +index 6d5aba6..0646620 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -1141,6 +1141,7 @@ struct JSGasTraceData { + uint64_t builtin_array_cb_per_element_count; + uint64_t builtin_array_cb_per_element_gas; + uint64_t allocation_count; ++ uint64_t allocation_requested_bytes; + uint64_t allocation_bytes; + uint64_t allocation_gas; + uint64_t json_parse_count; +@@ -1222,14 +1223,18 @@ static void js_gas_trace_record_array_cb(JSContext *ctx, uint16_t gas_cost, BOOL + } + } + +-static void js_gas_trace_record_allocation(JSContext *ctx, size_t size, uint64_t gas_cost) ++static void js_gas_trace_record_allocation(JSContext *ctx, ++ size_t requested_size, ++ size_t charged_size, ++ uint64_t gas_cost) + { + JSGasTraceData *trace = js_gas_trace_or_null(ctx); + if (!trace) + return; + + trace->allocation_count++; +- trace->allocation_bytes += size; ++ trace->allocation_requested_bytes += requested_size; ++ trace->allocation_bytes += charged_size; + trace->allocation_gas += gas_cost; + } + +@@ -1674,27 +1679,27 @@ static size_t js_det_normalize_allocation_size(JSRuntime *rt, size_t size) + static int js_charge_gas_allocation_ctx(JSContext *ctx, size_t size) + { + JSRuntime *rt = ctx->rt; +- size_t metered_size = js_det_normalize_allocation_size(rt, size); ++ size_t charged_size = js_det_normalize_allocation_size(rt, size); + uint64_t gas_cost; + + if (rt->in_out_of_gas || rt->current_exception_is_uncatchable) + return 0; + + if (rt->deterministic_mode) { +- rt->det_gc_alloc_bytes += metered_size; ++ rt->det_gc_alloc_bytes += charged_size; + if (rt->det_gc_alloc_bytes >= JS_DET_GC_THRESHOLD_BYTES) + rt->det_gc_pending = TRUE; + } + +- gas_cost = js_gas_allocation_cost(metered_size); ++ gas_cost = js_gas_allocation_cost(charged_size); + if (JS_UseGasAt(ctx, + gas_cost, + JS_GAS_SITE_ALLOCATION, + JS_GAS_CHARGE_KIND_ALLOCATION, +- metered_size)) ++ charged_size)) + return -1; + +- js_gas_trace_record_allocation(ctx, metered_size, gas_cost); ++ js_gas_trace_record_allocation(ctx, size, charged_size, gas_cost); + return 0; + } + +@@ -2864,6 +2869,7 @@ int JS_ReadGasTrace(JSContext *ctx, JSGasTrace *out_trace) + out_trace->builtin_array_cb_per_element_count = trace->builtin_array_cb_per_element_count; + out_trace->builtin_array_cb_per_element_gas = trace->builtin_array_cb_per_element_gas; + out_trace->allocation_count = trace->allocation_count; ++ out_trace->allocation_requested_bytes = trace->allocation_requested_bytes; + out_trace->allocation_bytes = trace->allocation_bytes; + out_trace->allocation_gas = trace->allocation_gas; + out_trace->json_parse_count = trace->json_parse_count; +diff --git a/quickjs.h b/quickjs.h +index 8f0ef0a..ca52a62 100644 +--- a/quickjs.h ++++ b/quickjs.h +@@ -425,6 +425,7 @@ typedef struct JSGasTrace { + uint64_t builtin_array_cb_per_element_count; + uint64_t builtin_array_cb_per_element_gas; + uint64_t allocation_count; ++ uint64_t allocation_requested_bytes; + uint64_t allocation_bytes; + uint64_t allocation_gas; + uint64_t json_parse_count; diff --git a/vendor/quickjs-patches/series/0043-feat-canonicalize-allocation-gas-classes.patch b/vendor/quickjs-patches/series/0043-feat-canonicalize-allocation-gas-classes.patch new file mode 100644 index 0000000..e6aa5cd --- /dev/null +++ b/vendor/quickjs-patches/series/0043-feat-canonicalize-allocation-gas-classes.patch @@ -0,0 +1,492 @@ +From 0f16210311465d9a37ef9255f361514b3e770beb Mon Sep 17 00:00:00 2001 +From: Cursor Agent +Date: Mon, 16 Mar 2026 11:53:08 +0000 +Subject: [PATCH 43/51] feat: canonicalize allocation gas classes + +--- + quickjs.c | 302 +++++++++++++++++++++++++++++++++++++++++++++++------- + quickjs.h | 2 +- + 2 files changed, 265 insertions(+), 39 deletions(-) + +diff --git a/quickjs.c b/quickjs.c +index 0646620..d86fc3d 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -1176,6 +1176,35 @@ typedef struct JSGasChargeTapeData { + #define JS_GAS_SITE_ARRAY_CALLBACK_BASE UINT32_C(3) + #define JS_GAS_SITE_ARRAY_CALLBACK_PER_ELEMENT UINT32_C(4) + ++typedef enum JSGasAllocationClass { ++ JS_GAS_ALLOC_CLASS_UNKNOWN = 0, ++ JS_GAS_ALLOC_CLASS_OBJECT_HEADER = 1, ++ JS_GAS_ALLOC_CLASS_PROPERTY_SLOTS = 2, ++ JS_GAS_ALLOC_CLASS_SHAPE = 3, ++ JS_GAS_ALLOC_CLASS_STRING = 4, ++ JS_GAS_ALLOC_CLASS_ARRAY_SLOTS = 5, ++ JS_GAS_ALLOC_CLASS_MODULE_RECORD = 6, ++ JS_GAS_ALLOC_CLASS_MODULE_ENTRIES = 7, ++ JS_GAS_ALLOC_CLASS_PROMISE_JOB = 8, ++ JS_GAS_ALLOC_CLASS_ARRAY_BUFFER_HEADER = 9, ++ JS_GAS_ALLOC_CLASS_TYPED_ARRAY_BACKING = 10, ++ JS_GAS_ALLOC_CLASS_TYPED_ARRAY_RECORD = 11, ++} JSGasAllocationClass; ++ ++#define JS_GAS_CANON_OBJECT_HEADER_BYTES UINT64_C(64) ++#define JS_GAS_CANON_PROPERTY_SLOT_BYTES UINT64_C(16) ++#define JS_GAS_CANON_SHAPE_HEADER_BYTES UINT64_C(48) ++#define JS_GAS_CANON_SHAPE_PROPERTY_BYTES UINT64_C(12) ++#define JS_GAS_CANON_STRING_HEADER_BYTES UINT64_C(24) ++#define JS_GAS_CANON_ARRAY_SLOT_BYTES UINT64_C(8) ++#define JS_GAS_CANON_MODULE_RECORD_BYTES UINT64_C(128) ++#define JS_GAS_CANON_MODULE_ENTRY_BYTES UINT64_C(24) ++#define JS_GAS_CANON_PROMISE_JOB_BASE_BYTES UINT64_C(48) ++#define JS_GAS_CANON_PROMISE_JOB_ARG_BYTES UINT64_C(8) ++#define JS_GAS_CANON_ARRAY_BUFFER_HEADER_BYTES UINT64_C(48) ++#define JS_GAS_CANON_TYPED_ARRAY_BACKING_UNIT_BYTES UINT64_C(1) ++#define JS_GAS_CANON_TYPED_ARRAY_RECORD_BYTES UINT64_C(40) ++ + static void js_gas_trace_reset_counts(JSGasTraceData *trace) + { + BOOL enabled = trace->enabled; +@@ -1657,29 +1686,90 @@ static uint64_t js_gas_allocation_cost(size_t size) + return JS_GAS_ALLOC_BASE + units; + } + +-static size_t js_det_normalize_allocation_size(JSRuntime *rt, size_t size) ++static uint64_t js_gas_mul_add_u64(uint64_t base, uint64_t units, uint64_t per_unit) + { +- if (!rt || !rt->deterministic_mode || size == 0) +- return size; +- +-#if UINTPTR_MAX > 0xffffffff +- { +- size_t scaled_size; +- +- if (size > (SIZE_MAX - 30) / 26) +- return SIZE_MAX; +- scaled_size = size * 26 + 30; +- return scaled_size / 31; +- } +-#else +- return size; +-#endif ++ if (units == 0 || per_unit == 0) ++ return base; ++ if (units > (UINT64_MAX - base) / per_unit) ++ return UINT64_MAX; ++ return base + units * per_unit; + } + +-static int js_charge_gas_allocation_ctx(JSContext *ctx, size_t size) ++static size_t js_det_canonical_allocation_size(size_t requested_size, ++ JSGasAllocationClass alloc_class, ++ uint64_t logical_units) ++{ ++ uint64_t canonical = 0; ++ ++ switch (alloc_class) { ++ case JS_GAS_ALLOC_CLASS_OBJECT_HEADER: ++ canonical = js_gas_mul_add_u64(JS_GAS_CANON_OBJECT_HEADER_BYTES, ++ logical_units > 0 ? logical_units - 1 : 0, ++ JS_GAS_CANON_OBJECT_HEADER_BYTES); ++ break; ++ case JS_GAS_ALLOC_CLASS_PROPERTY_SLOTS: ++ canonical = js_gas_mul_add_u64(0, logical_units, JS_GAS_CANON_PROPERTY_SLOT_BYTES); ++ break; ++ case JS_GAS_ALLOC_CLASS_SHAPE: ++ { ++ uint64_t hash_units = logical_units >> 32; ++ uint64_t prop_units = logical_units & UINT64_C(0xffffffff); ++ canonical = js_gas_mul_add_u64(JS_GAS_CANON_SHAPE_HEADER_BYTES, ++ prop_units, ++ JS_GAS_CANON_SHAPE_PROPERTY_BYTES); ++ canonical = js_gas_mul_add_u64(canonical, hash_units, 4); ++ } ++ break; ++ case JS_GAS_ALLOC_CLASS_STRING: ++ canonical = js_gas_mul_add_u64(JS_GAS_CANON_STRING_HEADER_BYTES, ++ logical_units, ++ 1); ++ break; ++ case JS_GAS_ALLOC_CLASS_ARRAY_SLOTS: ++ canonical = js_gas_mul_add_u64(0, logical_units, JS_GAS_CANON_ARRAY_SLOT_BYTES); ++ break; ++ case JS_GAS_ALLOC_CLASS_MODULE_RECORD: ++ canonical = JS_GAS_CANON_MODULE_RECORD_BYTES; ++ break; ++ case JS_GAS_ALLOC_CLASS_MODULE_ENTRIES: ++ canonical = js_gas_mul_add_u64(0, logical_units, JS_GAS_CANON_MODULE_ENTRY_BYTES); ++ break; ++ case JS_GAS_ALLOC_CLASS_PROMISE_JOB: ++ canonical = js_gas_mul_add_u64(JS_GAS_CANON_PROMISE_JOB_BASE_BYTES, ++ logical_units, ++ JS_GAS_CANON_PROMISE_JOB_ARG_BYTES); ++ break; ++ case JS_GAS_ALLOC_CLASS_ARRAY_BUFFER_HEADER: ++ canonical = JS_GAS_CANON_ARRAY_BUFFER_HEADER_BYTES; ++ break; ++ case JS_GAS_ALLOC_CLASS_TYPED_ARRAY_BACKING: ++ canonical = js_gas_mul_add_u64(0, ++ logical_units, ++ JS_GAS_CANON_TYPED_ARRAY_BACKING_UNIT_BYTES); ++ break; ++ case JS_GAS_ALLOC_CLASS_TYPED_ARRAY_RECORD: ++ canonical = JS_GAS_CANON_TYPED_ARRAY_RECORD_BYTES; ++ break; ++ case JS_GAS_ALLOC_CLASS_UNKNOWN: ++ default: ++ canonical = requested_size; ++ break; ++ } ++ ++ if (canonical > SIZE_MAX) ++ return SIZE_MAX; ++ return (size_t)canonical; ++} ++ ++static int js_charge_gas_allocation_ctx_with_class(JSContext *ctx, ++ size_t requested_size, ++ JSGasAllocationClass alloc_class, ++ uint64_t logical_units) + { + JSRuntime *rt = ctx->rt; +- size_t charged_size = js_det_normalize_allocation_size(rt, size); ++ size_t charged_size = js_det_canonical_allocation_size(requested_size, ++ alloc_class, ++ logical_units); + uint64_t gas_cost; + + if (rt->in_out_of_gas || rt->current_exception_is_uncatchable) +@@ -1699,10 +1789,18 @@ static int js_charge_gas_allocation_ctx(JSContext *ctx, size_t size) + charged_size)) + return -1; + +- js_gas_trace_record_allocation(ctx, size, charged_size, gas_cost); ++ js_gas_trace_record_allocation(ctx, requested_size, charged_size, gas_cost); + return 0; + } + ++static int js_charge_gas_allocation_ctx(JSContext *ctx, size_t size) ++{ ++ return js_charge_gas_allocation_ctx_with_class(ctx, ++ size, ++ JS_GAS_ALLOC_CLASS_UNKNOWN, ++ size); ++} ++ + static size_t js_malloc_usable_size_unknown(const void *ptr) + { + return 0; +@@ -1741,7 +1839,10 @@ void *js_mallocz_rt(JSRuntime *rt, size_t size) + void *js_malloc(JSContext *ctx, size_t size) + { + void *ptr; +- if (size != 0 && js_charge_gas_allocation_ctx(ctx, size)) ++ if (size != 0 && js_charge_gas_allocation_ctx_with_class(ctx, ++ size, ++ JS_GAS_ALLOC_CLASS_UNKNOWN, ++ size)) + return NULL; + ptr = js_malloc_rt(ctx->rt, size); + if (unlikely(!ptr)) { +@@ -1756,7 +1857,10 @@ void *js_malloc(JSContext *ctx, size_t size) + void *js_mallocz(JSContext *ctx, size_t size) + { + void *ptr; +- if (size != 0 && js_charge_gas_allocation_ctx(ctx, size)) ++ if (size != 0 && js_charge_gas_allocation_ctx_with_class(ctx, ++ size, ++ JS_GAS_ALLOC_CLASS_UNKNOWN, ++ size)) + return NULL; + ptr = js_mallocz_rt(ctx->rt, size); + if (unlikely(!ptr)) { +@@ -1776,7 +1880,10 @@ void js_free(JSContext *ctx, void *ptr) + void *js_realloc(JSContext *ctx, void *ptr, size_t size) + { + void *ret; +- if (size != 0 && js_charge_gas_allocation_ctx(ctx, size)) ++ if (size != 0 && js_charge_gas_allocation_ctx_with_class(ctx, ++ size, ++ JS_GAS_ALLOC_CLASS_UNKNOWN, ++ size)) + return NULL; + ret = js_realloc_rt(ctx->rt, ptr, size); + if (unlikely(!ret && size != 0)) { +@@ -1791,7 +1898,58 @@ void *js_realloc(JSContext *ctx, void *ptr, size_t size) + void *js_realloc2(JSContext *ctx, void *ptr, size_t size, size_t *pslack) + { + void *ret; +- if (size != 0 && js_charge_gas_allocation_ctx(ctx, size)) ++ if (size != 0 && js_charge_gas_allocation_ctx_with_class(ctx, ++ size, ++ JS_GAS_ALLOC_CLASS_UNKNOWN, ++ size)) ++ return NULL; ++ ret = js_realloc_rt(ctx->rt, ptr, size); ++ if (unlikely(!ret && size != 0)) { ++ if (JS_IsUninitialized(ctx->rt->current_exception)) ++ JS_ThrowOutOfMemory(ctx); ++ return NULL; ++ } ++ if (pslack) { ++ size_t new_size = js_malloc_usable_size_rt(ctx->rt, ret); ++ *pslack = (new_size > size) ? new_size - size : 0; ++ } ++ return ret; ++} ++ ++/* Throw out of memory in case of error */ ++static void *js_malloc_with_class(JSContext *ctx, ++ size_t size, ++ JSGasAllocationClass alloc_class, ++ uint64_t logical_units, ++ BOOL zero_init) ++{ ++ void *ptr; ++ if (size != 0 && js_charge_gas_allocation_ctx_with_class(ctx, ++ size, ++ alloc_class, ++ logical_units)) ++ return NULL; ++ ptr = zero_init ? js_mallocz_rt(ctx->rt, size) : js_malloc_rt(ctx->rt, size); ++ if (unlikely(!ptr && size != 0)) { ++ if (JS_IsUninitialized(ctx->rt->current_exception)) ++ JS_ThrowOutOfMemory(ctx); ++ return NULL; ++ } ++ return ptr; ++} ++ ++static void *js_realloc2_with_class(JSContext *ctx, ++ void *ptr, ++ size_t size, ++ size_t *pslack, ++ JSGasAllocationClass alloc_class, ++ uint64_t logical_units) ++{ ++ void *ret; ++ if (size != 0 && js_charge_gas_allocation_ctx_with_class(ctx, ++ size, ++ alloc_class, ++ logical_units)) + return NULL; + ret = js_realloc_rt(ctx->rt, ptr, size); + if (unlikely(!ret && size != 0)) { +@@ -2204,7 +2362,11 @@ int JS_EnqueueJob(JSContext *ctx, JSJobFunc *job_func, + JSJobEntry *e; + int i; + +- e = js_malloc(ctx, sizeof(*e) + argc * sizeof(JSValue)); ++ e = js_malloc_with_class(ctx, ++ sizeof(*e) + argc * sizeof(JSValue), ++ JS_GAS_ALLOC_CLASS_PROMISE_JOB, ++ (uint64_t)max_int(argc, 0), ++ FALSE); + if (!e) + return -1; + e->realm = JS_DupContext(ctx); +@@ -2302,8 +2464,12 @@ static JSString *js_alloc_string(JSContext *ctx, int max_len, int is_wide_char) + JSString *p; + size_t alloc_size = sizeof(JSString) + + (((size_t)max_len << is_wide_char) + 1 - is_wide_char); ++ uint64_t payload_units = (uint64_t)max_len << is_wide_char; + +- if (js_charge_gas_allocation_ctx(ctx, alloc_size)) ++ if (js_charge_gas_allocation_ctx_with_class(ctx, ++ alloc_size, ++ JS_GAS_ALLOC_CLASS_STRING, ++ payload_units)) + return NULL; + p = js_alloc_string_rt(ctx->rt, max_len, is_wide_char); + if (unlikely(!p)) { +@@ -5621,7 +5787,12 @@ static inline JSShape *js_new_shape_nohash(JSContext *ctx, JSObject *proto, + void *sh_alloc; + JSShape *sh; + +- sh_alloc = js_malloc(ctx, get_shape_size(hash_size, prop_size)); ++ sh_alloc = js_malloc_with_class( ++ ctx, ++ get_shape_size(hash_size, prop_size), ++ JS_GAS_ALLOC_CLASS_SHAPE, ++ ((uint64_t)(uint32_t)hash_size << 32) | (uint32_t)prop_size, ++ FALSE); + if (!sh_alloc) + return NULL; + sh = get_shape_from_alloc(sh_alloc, hash_size); +@@ -5681,7 +5852,12 @@ static JSShape *js_clone_shape(JSContext *ctx, JSShape *sh1) + + hash_size = sh1->prop_hash_mask + 1; + size = get_shape_size(hash_size, sh1->prop_size); +- sh_alloc = js_malloc(ctx, size); ++ sh_alloc = js_malloc_with_class( ++ ctx, ++ size, ++ JS_GAS_ALLOC_CLASS_SHAPE, ++ ((uint64_t)(uint32_t)hash_size << 32) | (uint32_t)sh1->prop_size, ++ FALSE); + if (!sh_alloc) + return NULL; + sh_alloc1 = get_alloc_from_shape(sh1); +@@ -6017,7 +6193,11 @@ static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID clas + int i; + + js_trigger_gc(ctx->rt, sizeof(JSObject)); +- p = js_malloc(ctx, sizeof(JSObject)); ++ p = js_malloc_with_class(ctx, ++ sizeof(JSObject), ++ JS_GAS_ALLOC_CLASS_OBJECT_HEADER, ++ 1, ++ FALSE); + if (unlikely(!p)) + goto fail; + p->class_id = class_id; +@@ -6033,7 +6213,11 @@ static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID clas + p->weakref_count = 0; + p->u.opaque = NULL; + p->shape = sh; +- p->prop = js_malloc(ctx, sizeof(JSProperty) * sh->prop_size); ++ p->prop = js_malloc_with_class(ctx, ++ sizeof(JSProperty) * sh->prop_size, ++ JS_GAS_ALLOC_CLASS_PROPERTY_SLOTS, ++ sh->prop_size, ++ FALSE); + if (unlikely(!p->prop)) { + js_free(ctx, p); + fail: +@@ -9928,7 +10112,12 @@ static int expand_fast_array(JSContext *ctx, JSObject *p, uint32_t new_len) + JSValue *new_array_prop; + /* XXX: potential arithmetic overflow */ + new_size = max_int(new_len, p->u.array.u1.size * 3 / 2); +- new_array_prop = js_realloc2(ctx, p->u.array.u.values, sizeof(JSValue) * new_size, &slack); ++ new_array_prop = js_realloc2_with_class(ctx, ++ p->u.array.u.values, ++ sizeof(JSValue) * new_size, ++ &slack, ++ JS_GAS_ALLOC_CLASS_ARRAY_SLOTS, ++ new_size); + if (!new_array_prop) + return -1; + new_size += slack / sizeof(*new_array_prop); +@@ -29919,7 +30108,11 @@ fail: + static JSModuleDef *js_new_module_def(JSContext *ctx, JSAtom name) + { + JSModuleDef *m; +- m = js_mallocz(ctx, sizeof(*m)); ++ m = js_malloc_with_class(ctx, ++ sizeof(*m), ++ JS_GAS_ALLOC_CLASS_MODULE_RECORD, ++ 1, ++ TRUE); + if (!m) { + JS_FreeAtom(ctx, name); + return NULL; +@@ -39210,7 +39403,12 @@ static JSValue JS_ReadModule(BCReaderState *s) + goto fail; + if (m->req_module_entries_count != 0) { + m->req_module_entries_size = m->req_module_entries_count; +- m->req_module_entries = js_mallocz(ctx, sizeof(m->req_module_entries[0]) * m->req_module_entries_size); ++ m->req_module_entries = js_malloc_with_class( ++ ctx, ++ sizeof(m->req_module_entries[0]) * m->req_module_entries_size, ++ JS_GAS_ALLOC_CLASS_MODULE_ENTRIES, ++ m->req_module_entries_size, ++ TRUE); + if (!m->req_module_entries) + goto fail; + for(i = 0; i < m->req_module_entries_count; i++) { +@@ -39229,7 +39427,12 @@ static JSValue JS_ReadModule(BCReaderState *s) + goto fail; + if (m->export_entries_count != 0) { + m->export_entries_size = m->export_entries_count; +- m->export_entries = js_mallocz(ctx, sizeof(m->export_entries[0]) * m->export_entries_size); ++ m->export_entries = js_malloc_with_class( ++ ctx, ++ sizeof(m->export_entries[0]) * m->export_entries_size, ++ JS_GAS_ALLOC_CLASS_MODULE_ENTRIES, ++ m->export_entries_size, ++ TRUE); + if (!m->export_entries) + goto fail; + for(i = 0; i < m->export_entries_count; i++) { +@@ -39255,7 +39458,12 @@ static JSValue JS_ReadModule(BCReaderState *s) + goto fail; + if (m->star_export_entries_count != 0) { + m->star_export_entries_size = m->star_export_entries_count; +- m->star_export_entries = js_mallocz(ctx, sizeof(m->star_export_entries[0]) * m->star_export_entries_size); ++ m->star_export_entries = js_malloc_with_class( ++ ctx, ++ sizeof(m->star_export_entries[0]) * m->star_export_entries_size, ++ JS_GAS_ALLOC_CLASS_MODULE_ENTRIES, ++ m->star_export_entries_size, ++ TRUE); + if (!m->star_export_entries) + goto fail; + for(i = 0; i < m->star_export_entries_count; i++) { +@@ -39269,7 +39477,12 @@ static JSValue JS_ReadModule(BCReaderState *s) + goto fail; + if (m->import_entries_count != 0) { + m->import_entries_size = m->import_entries_count; +- m->import_entries = js_mallocz(ctx, sizeof(m->import_entries[0]) * m->import_entries_size); ++ m->import_entries = js_malloc_with_class( ++ ctx, ++ sizeof(m->import_entries[0]) * m->import_entries_size, ++ JS_GAS_ALLOC_CLASS_MODULE_ENTRIES, ++ m->import_entries_size, ++ TRUE); + if (!m->import_entries) + goto fail; + for(i = 0; i < m->import_entries_count; i++) { +@@ -56630,7 +56843,11 @@ static JSValue js_array_buffer_constructor3(JSContext *ctx, + JS_ThrowRangeError(ctx, "invalid max array buffer length"); + goto fail; + } +- abuf = js_malloc(ctx, sizeof(*abuf)); ++ abuf = js_malloc_with_class(ctx, ++ sizeof(*abuf), ++ JS_GAS_ALLOC_CLASS_ARRAY_BUFFER_HEADER, ++ 1, ++ FALSE); + if (!abuf) + goto fail; + abuf->byte_length = len; +@@ -56648,7 +56865,12 @@ static JSValue js_array_buffer_constructor3(JSContext *ctx, + memset(abuf->data, 0, sab_alloc_len); + } else { + /* the allocation must be done after the object creation */ +- abuf->data = js_mallocz(ctx, max_int(len, 1)); ++ abuf->data = js_malloc_with_class( ++ ctx, ++ max_int(len, 1), ++ JS_GAS_ALLOC_CLASS_TYPED_ARRAY_BACKING, ++ max_int(len, 1), ++ TRUE); + if (!abuf->data) + goto fail; + } +@@ -58883,7 +59105,11 @@ static int typed_array_init(JSContext *ctx, JSValueConst obj, + + p = JS_VALUE_GET_OBJ(obj); + size_log2 = typed_array_size_log2(p->class_id); +- ta = js_malloc(ctx, sizeof(*ta)); ++ ta = js_malloc_with_class(ctx, ++ sizeof(*ta), ++ JS_GAS_ALLOC_CLASS_TYPED_ARRAY_RECORD, ++ 1, ++ FALSE); + if (!ta) { + JS_FreeValue(ctx, buffer); + return -1; +diff --git a/quickjs.h b/quickjs.h +index ca52a62..302cb08 100644 +--- a/quickjs.h ++++ b/quickjs.h +@@ -355,7 +355,7 @@ typedef JSValue JSCFunction(JSContext *ctx, JSValueConst this_val, int argc, JSV + typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); + typedef JSValue JSCFunctionData(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic, JSValue *func_data); + +-#define JS_GAS_VERSION_LATEST 3 ++#define JS_GAS_VERSION_LATEST 4 + #define JS_GAS_UNLIMITED UINT64_C(0xffffffffffffffff) + + typedef struct JSMallocState { diff --git a/vendor/quickjs-patches/series/0044-feat-tag-allocation-charges-by-allocation-class-site.patch b/vendor/quickjs-patches/series/0044-feat-tag-allocation-charges-by-allocation-class-site.patch new file mode 100644 index 0000000..22500fa --- /dev/null +++ b/vendor/quickjs-patches/series/0044-feat-tag-allocation-charges-by-allocation-class-site.patch @@ -0,0 +1,30 @@ +From 8d2543c8aa2eb5c665714d523aac963920d88e8d Mon Sep 17 00:00:00 2001 +From: Cursor Agent +Date: Mon, 16 Mar 2026 12:29:06 +0000 +Subject: [PATCH 44/51] feat: tag allocation charges by allocation class site + +--- + quickjs.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/quickjs.c b/quickjs.c +index d86fc3d..325573f 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -1175,6 +1175,7 @@ typedef struct JSGasChargeTapeData { + #define JS_GAS_SITE_ALLOCATION UINT32_C(2) + #define JS_GAS_SITE_ARRAY_CALLBACK_BASE UINT32_C(3) + #define JS_GAS_SITE_ARRAY_CALLBACK_PER_ELEMENT UINT32_C(4) ++#define JS_GAS_SITE_ALLOCATION_CLASS_BASE UINT32_C(1000) + + typedef enum JSGasAllocationClass { + JS_GAS_ALLOC_CLASS_UNKNOWN = 0, +@@ -1784,7 +1785,7 @@ static int js_charge_gas_allocation_ctx_with_class(JSContext *ctx, + gas_cost = js_gas_allocation_cost(charged_size); + if (JS_UseGasAt(ctx, + gas_cost, +- JS_GAS_SITE_ALLOCATION, ++ JS_GAS_SITE_ALLOCATION_CLASS_BASE + (uint32_t)alloc_class, + JS_GAS_CHARGE_KIND_ALLOCATION, + charged_size)) + return -1; diff --git a/vendor/quickjs-patches/series/0045-feat-classify-compiler-and-var-ref-allocations-canon.patch b/vendor/quickjs-patches/series/0045-feat-classify-compiler-and-var-ref-allocations-canon.patch new file mode 100644 index 0000000..b011944 --- /dev/null +++ b/vendor/quickjs-patches/series/0045-feat-classify-compiler-and-var-ref-allocations-canon.patch @@ -0,0 +1,125 @@ +From 76191e3972baf390b0d6eb5459c53bbf642bfc1c Mon Sep 17 00:00:00 2001 +From: Cursor Agent +Date: Mon, 16 Mar 2026 12:51:13 +0000 +Subject: [PATCH 45/51] feat: classify compiler and var-ref allocations + canonically + +--- + quickjs.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 50 insertions(+), 5 deletions(-) + +diff --git a/quickjs.c b/quickjs.c +index 325573f..faed455 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -1190,6 +1190,10 @@ typedef enum JSGasAllocationClass { + JS_GAS_ALLOC_CLASS_ARRAY_BUFFER_HEADER = 9, + JS_GAS_ALLOC_CLASS_TYPED_ARRAY_BACKING = 10, + JS_GAS_ALLOC_CLASS_TYPED_ARRAY_RECORD = 11, ++ JS_GAS_ALLOC_CLASS_COMPILER_FUNCTION_DEF = 12, ++ JS_GAS_ALLOC_CLASS_CLOSURE_VAR_ENTRIES = 13, ++ JS_GAS_ALLOC_CLASS_VAR_REF_POINTERS = 14, ++ JS_GAS_ALLOC_CLASS_VAR_REF_RECORD = 15, + } JSGasAllocationClass; + + #define JS_GAS_CANON_OBJECT_HEADER_BYTES UINT64_C(64) +@@ -1205,6 +1209,10 @@ typedef enum JSGasAllocationClass { + #define JS_GAS_CANON_ARRAY_BUFFER_HEADER_BYTES UINT64_C(48) + #define JS_GAS_CANON_TYPED_ARRAY_BACKING_UNIT_BYTES UINT64_C(1) + #define JS_GAS_CANON_TYPED_ARRAY_RECORD_BYTES UINT64_C(40) ++#define JS_GAS_CANON_COMPILER_FUNCTION_DEF_BYTES UINT64_C(512) ++#define JS_GAS_CANON_CLOSURE_VAR_ENTRY_BYTES UINT64_C(16) ++#define JS_GAS_CANON_VAR_REF_POINTER_BYTES UINT64_C(8) ++#define JS_GAS_CANON_VAR_REF_RECORD_BYTES UINT64_C(32) + + static void js_gas_trace_reset_counts(JSGasTraceData *trace) + { +@@ -1751,6 +1759,22 @@ static size_t js_det_canonical_allocation_size(size_t requested_size, + case JS_GAS_ALLOC_CLASS_TYPED_ARRAY_RECORD: + canonical = JS_GAS_CANON_TYPED_ARRAY_RECORD_BYTES; + break; ++ case JS_GAS_ALLOC_CLASS_COMPILER_FUNCTION_DEF: ++ canonical = JS_GAS_CANON_COMPILER_FUNCTION_DEF_BYTES; ++ break; ++ case JS_GAS_ALLOC_CLASS_CLOSURE_VAR_ENTRIES: ++ canonical = js_gas_mul_add_u64(0, ++ logical_units, ++ JS_GAS_CANON_CLOSURE_VAR_ENTRY_BYTES); ++ break; ++ case JS_GAS_ALLOC_CLASS_VAR_REF_POINTERS: ++ canonical = js_gas_mul_add_u64(0, ++ logical_units, ++ JS_GAS_CANON_VAR_REF_POINTER_BYTES); ++ break; ++ case JS_GAS_ALLOC_CLASS_VAR_REF_RECORD: ++ canonical = JS_GAS_CANON_VAR_REF_RECORD_BYTES; ++ break; + case JS_GAS_ALLOC_CLASS_UNKNOWN: + default: + canonical = requested_size; +@@ -17599,7 +17623,11 @@ static JSValueConst JS_GetActiveFunction(JSContext *ctx) + static JSVarRef *js_create_var_ref(JSContext *ctx, BOOL is_lexical) + { + JSVarRef *var_ref; +- var_ref = js_malloc(ctx, sizeof(JSVarRef)); ++ var_ref = js_malloc_with_class(ctx, ++ sizeof(JSVarRef), ++ JS_GAS_ALLOC_CLASS_VAR_REF_RECORD, ++ 1, ++ FALSE); + if (!var_ref) + return NULL; + var_ref->header.ref_count = 1; +@@ -17647,7 +17675,11 @@ static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf, int var_idx, + } + + /* create a new one */ +- var_ref = js_malloc(ctx, sizeof(JSVarRef)); ++ var_ref = js_malloc_with_class(ctx, ++ sizeof(JSVarRef), ++ JS_GAS_ALLOC_CLASS_VAR_REF_RECORD, ++ 1, ++ FALSE); + if (!var_ref) + return NULL; + var_ref->header.ref_count = 1; +@@ -17895,7 +17927,11 @@ static JSValue js_closure2(JSContext *ctx, JSValue func_obj, + p->u.func.home_object = NULL; + p->u.func.var_refs = NULL; + if (b->closure_var_count) { +- var_refs = js_mallocz(ctx, sizeof(var_refs[0]) * b->closure_var_count); ++ var_refs = js_malloc_with_class(ctx, ++ sizeof(var_refs[0]) * b->closure_var_count, ++ JS_GAS_ALLOC_CLASS_VAR_REF_POINTERS, ++ b->closure_var_count, ++ TRUE); + if (!var_refs) + goto fail; + p->u.func.var_refs = var_refs; +@@ -32518,7 +32554,11 @@ static JSFunctionDef *js_new_function_def(JSContext *ctx, + { + JSFunctionDef *fd; + +- fd = js_mallocz(ctx, sizeof(*fd)); ++ fd = js_malloc_with_class(ctx, ++ sizeof(*fd), ++ JS_GAS_ALLOC_CLASS_COMPILER_FUNCTION_DEF, ++ 1, ++ TRUE); + if (!fd) + return NULL; + +@@ -34234,7 +34274,12 @@ static __exception int add_closure_variables(JSContext *ctx, JSFunctionDef *s, + s->closure_var_size = count; + if (count == 0) + return 0; +- s->closure_var = js_malloc(ctx, sizeof(s->closure_var[0]) * count); ++ s->closure_var = js_malloc_with_class( ++ ctx, ++ sizeof(s->closure_var[0]) * count, ++ JS_GAS_ALLOC_CLASS_CLOSURE_VAR_ENTRIES, ++ count, ++ FALSE); + if (!s->closure_var) + return -1; + /* Add lexical variables in scope at the point of evaluation */ diff --git a/vendor/quickjs-patches/series/0046-feat-reduce-unknown-allocation-drift-with-canonical-.patch b/vendor/quickjs-patches/series/0046-feat-reduce-unknown-allocation-drift-with-canonical-.patch new file mode 100644 index 0000000..7afe811 --- /dev/null +++ b/vendor/quickjs-patches/series/0046-feat-reduce-unknown-allocation-drift-with-canonical-.patch @@ -0,0 +1,28 @@ +From 762a94660eb9ba9da98c21f6b3768251c3a3dc98 Mon Sep 17 00:00:00 2001 +From: Cursor Agent +Date: Mon, 16 Mar 2026 13:10:31 +0000 +Subject: [PATCH 46/51] feat: reduce unknown allocation drift with canonical + header floor + +--- + quickjs.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/quickjs.c b/quickjs.c +index faed455..1249ed9 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -1777,7 +1777,12 @@ static size_t js_det_canonical_allocation_size(size_t requested_size, + break; + case JS_GAS_ALLOC_CLASS_UNKNOWN: + default: +- canonical = requested_size; ++ if (requested_size == 0) ++ canonical = 0; ++ else if (requested_size <= JS_GAS_CANON_OBJECT_HEADER_BYTES) ++ canonical = JS_GAS_CANON_OBJECT_HEADER_BYTES; ++ else ++ canonical = requested_size; + break; + } + diff --git a/vendor/quickjs-patches/series/0047-feat-canonicalize-dynamic-array-allocation-charging.patch b/vendor/quickjs-patches/series/0047-feat-canonicalize-dynamic-array-allocation-charging.patch new file mode 100644 index 0000000..0c8e726 --- /dev/null +++ b/vendor/quickjs-patches/series/0047-feat-canonicalize-dynamic-array-allocation-charging.patch @@ -0,0 +1,69 @@ +From ed5937463688b36c8f9f7499b91b78942d3c0f8b Mon Sep 17 00:00:00 2001 +From: Cursor Agent +Date: Mon, 16 Mar 2026 13:26:53 +0000 +Subject: [PATCH 47/51] feat: canonicalize dynamic array allocation charging + +--- + quickjs.c | 14 +++++++++++++- + quickjs.h | 2 +- + 2 files changed, 14 insertions(+), 2 deletions(-) + +diff --git a/quickjs.c b/quickjs.c +index 1249ed9..04e3fcf 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -1194,6 +1194,7 @@ typedef enum JSGasAllocationClass { + JS_GAS_ALLOC_CLASS_CLOSURE_VAR_ENTRIES = 13, + JS_GAS_ALLOC_CLASS_VAR_REF_POINTERS = 14, + JS_GAS_ALLOC_CLASS_VAR_REF_RECORD = 15, ++ JS_GAS_ALLOC_CLASS_GENERIC_ARRAY = 16, + } JSGasAllocationClass; + + #define JS_GAS_CANON_OBJECT_HEADER_BYTES UINT64_C(64) +@@ -1213,6 +1214,7 @@ typedef enum JSGasAllocationClass { + #define JS_GAS_CANON_CLOSURE_VAR_ENTRY_BYTES UINT64_C(16) + #define JS_GAS_CANON_VAR_REF_POINTER_BYTES UINT64_C(8) + #define JS_GAS_CANON_VAR_REF_RECORD_BYTES UINT64_C(32) ++#define JS_GAS_CANON_GENERIC_ARRAY_UNIT_BYTES UINT64_C(16) + + static void js_gas_trace_reset_counts(JSGasTraceData *trace) + { +@@ -1775,6 +1777,11 @@ static size_t js_det_canonical_allocation_size(size_t requested_size, + case JS_GAS_ALLOC_CLASS_VAR_REF_RECORD: + canonical = JS_GAS_CANON_VAR_REF_RECORD_BYTES; + break; ++ case JS_GAS_ALLOC_CLASS_GENERIC_ARRAY: ++ canonical = js_gas_mul_add_u64(0, ++ logical_units, ++ JS_GAS_CANON_GENERIC_ARRAY_UNIT_BYTES); ++ break; + case JS_GAS_ALLOC_CLASS_UNKNOWN: + default: + if (requested_size == 0) +@@ -2024,7 +2031,12 @@ static no_inline int js_realloc_array(JSContext *ctx, void **parray, + void *new_array; + /* XXX: potential arithmetic overflow */ + new_size = max_int(req_size, *psize * 3 / 2); +- new_array = js_realloc2(ctx, *parray, new_size * elem_size, &slack); ++ new_array = js_realloc2_with_class(ctx, ++ *parray, ++ new_size * elem_size, ++ &slack, ++ JS_GAS_ALLOC_CLASS_GENERIC_ARRAY, ++ new_size); + if (!new_array) + return -1; + new_size += slack / elem_size; +diff --git a/quickjs.h b/quickjs.h +index 302cb08..c91a520 100644 +--- a/quickjs.h ++++ b/quickjs.h +@@ -355,7 +355,7 @@ typedef JSValue JSCFunction(JSContext *ctx, JSValueConst this_val, int argc, JSV + typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); + typedef JSValue JSCFunctionData(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic, JSValue *func_data); + +-#define JS_GAS_VERSION_LATEST 4 ++#define JS_GAS_VERSION_LATEST 5 + #define JS_GAS_UNLIMITED UINT64_C(0xffffffffffffffff) + + typedef struct JSMallocState { diff --git a/vendor/quickjs-patches/series/0048-feat-tighten-unknown-allocation-canonicalization-for.patch b/vendor/quickjs-patches/series/0048-feat-tighten-unknown-allocation-canonicalization-for.patch new file mode 100644 index 0000000..1d7890b --- /dev/null +++ b/vendor/quickjs-patches/series/0048-feat-tighten-unknown-allocation-canonicalization-for.patch @@ -0,0 +1,136 @@ +From 411368c95104007a40d48885a2faaa8ec7de4d4e Mon Sep 17 00:00:00 2001 +From: Cursor Agent +Date: Mon, 16 Mar 2026 14:43:20 +0000 +Subject: [PATCH 48/51] feat: tighten unknown allocation canonicalization for + small objects + +--- + quickjs.c | 52 ++++++++++++++++++++++++++++++++++++++++++++-------- + quickjs.h | 2 +- + 2 files changed, 45 insertions(+), 9 deletions(-) + +diff --git a/quickjs.c b/quickjs.c +index 04e3fcf..f02d82b 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -1215,6 +1215,7 @@ typedef enum JSGasAllocationClass { + #define JS_GAS_CANON_VAR_REF_POINTER_BYTES UINT64_C(8) + #define JS_GAS_CANON_VAR_REF_RECORD_BYTES UINT64_C(32) + #define JS_GAS_CANON_GENERIC_ARRAY_UNIT_BYTES UINT64_C(16) ++#define JS_GAS_CANON_UNKNOWN_SMALL_FLOOR_MAX_BYTES UINT64_C(256) + + static void js_gas_trace_reset_counts(JSGasTraceData *trace) + { +@@ -1786,7 +1787,7 @@ static size_t js_det_canonical_allocation_size(size_t requested_size, + default: + if (requested_size == 0) + canonical = 0; +- else if (requested_size <= JS_GAS_CANON_OBJECT_HEADER_BYTES) ++ else if (requested_size <= JS_GAS_CANON_UNKNOWN_SMALL_FLOOR_MAX_BYTES) + canonical = JS_GAS_CANON_OBJECT_HEADER_BYTES; + else + canonical = requested_size; +@@ -4648,7 +4649,12 @@ static no_inline int string_buffer_widen(StringBuffer *s, int size) + if (s->error_status) + return -1; + +- str = js_realloc2(s->ctx, s->str, sizeof(JSString) + (size << 1), &slack); ++ str = js_realloc2_with_class(s->ctx, ++ s->str, ++ sizeof(JSString) + (size << 1), ++ &slack, ++ JS_GAS_ALLOC_CLASS_STRING, ++ (uint64_t)size << 1); + if (!str) + return string_buffer_set_error(s); + size += slack >> 1; +@@ -4679,7 +4685,12 @@ static no_inline int string_buffer_realloc(StringBuffer *s, int new_len, int c) + return string_buffer_widen(s, new_size); + } + new_size_bytes = sizeof(JSString) + (new_size << s->is_wide_char) + 1 - s->is_wide_char; +- new_str = js_realloc2(s->ctx, s->str, new_size_bytes, &slack); ++ new_str = js_realloc2_with_class(s->ctx, ++ s->str, ++ new_size_bytes, ++ &slack, ++ JS_GAS_ALLOC_CLASS_STRING, ++ (uint64_t)new_size << s->is_wide_char); + if (!new_str) + return string_buffer_set_error(s); + new_size = min_int(new_size + (slack >> s->is_wide_char), JS_STRING_LEN_MAX); +@@ -24622,12 +24633,22 @@ static int push_scope(JSParseState *s) { + /* XXX: potential arithmetic overflow */ + new_size = max_int(fd->scope_count + 1, fd->scope_size * 3 / 2); + if (fd->scopes == fd->def_scope_array) { +- new_buf = js_realloc2(s->ctx, NULL, new_size * sizeof(*fd->scopes), &slack); ++ new_buf = js_realloc2_with_class(s->ctx, ++ NULL, ++ new_size * sizeof(*fd->scopes), ++ &slack, ++ JS_GAS_ALLOC_CLASS_GENERIC_ARRAY, ++ new_size); + if (!new_buf) + return -1; + memcpy(new_buf, fd->scopes, fd->scope_count * sizeof(*fd->scopes)); + } else { +- new_buf = js_realloc2(s->ctx, fd->scopes, new_size * sizeof(*fd->scopes), &slack); ++ new_buf = js_realloc2_with_class(s->ctx, ++ fd->scopes, ++ new_size * sizeof(*fd->scopes), ++ &slack, ++ JS_GAS_ALLOC_CLASS_GENERIC_ARRAY, ++ new_size); + if (!new_buf) + return -1; + } +@@ -43920,7 +43941,12 @@ static JSValue js_array_sort(JSContext *ctx, JSValueConst this_val, + size_t new_size, slack; + ValueSlot *new_array; + new_size = (array_size + (array_size >> 1) + 31) & ~15; +- new_array = js_realloc2(ctx, array, new_size * sizeof(*array), &slack); ++ new_array = js_realloc2_with_class(ctx, ++ array, ++ new_size * sizeof(*array), ++ &slack, ++ JS_GAS_ALLOC_CLASS_GENERIC_ARRAY, ++ new_size); + if (new_array == NULL) + goto exception; + new_size += slack / sizeof(*new_array); +@@ -49227,11 +49253,21 @@ static int value_buffer_append(ValueBuffer *b, JSValue val) + JSValue *new_arr; + + if (b->arr == b->def) { +- new_arr = js_realloc2(b->ctx, NULL, sizeof(*b->arr) * new_size, &slack); ++ new_arr = js_realloc2_with_class(b->ctx, ++ NULL, ++ sizeof(*b->arr) * new_size, ++ &slack, ++ JS_GAS_ALLOC_CLASS_ARRAY_SLOTS, ++ new_size); + if (new_arr) + memcpy(new_arr, b->def, sizeof b->def); + } else { +- new_arr = js_realloc2(b->ctx, b->arr, sizeof(*b->arr) * new_size, &slack); ++ new_arr = js_realloc2_with_class(b->ctx, ++ b->arr, ++ sizeof(*b->arr) * new_size, ++ &slack, ++ JS_GAS_ALLOC_CLASS_ARRAY_SLOTS, ++ new_size); + } + if (!new_arr) { + value_buffer_free(b); +diff --git a/quickjs.h b/quickjs.h +index c91a520..abae5d0 100644 +--- a/quickjs.h ++++ b/quickjs.h +@@ -355,7 +355,7 @@ typedef JSValue JSCFunction(JSContext *ctx, JSValueConst this_val, int argc, JSV + typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); + typedef JSValue JSCFunctionData(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic, JSValue *func_data); + +-#define JS_GAS_VERSION_LATEST 5 ++#define JS_GAS_VERSION_LATEST 6 + #define JS_GAS_UNLIMITED UINT64_C(0xffffffffffffffff) + + typedef struct JSMallocState { diff --git a/vendor/quickjs-patches/series/0049-feat-expand-unknown-allocation-floor-window-for-pari.patch b/vendor/quickjs-patches/series/0049-feat-expand-unknown-allocation-floor-window-for-pari.patch new file mode 100644 index 0000000..5fd6ce5 --- /dev/null +++ b/vendor/quickjs-patches/series/0049-feat-expand-unknown-allocation-floor-window-for-pari.patch @@ -0,0 +1,23 @@ +From 17c0b4ab0a0e44f4fcd5dea0e8fa05567555c7a4 Mon Sep 17 00:00:00 2001 +From: Cursor Agent +Date: Mon, 16 Mar 2026 15:26:34 +0000 +Subject: [PATCH 49/51] feat: expand unknown allocation floor window for parity + closure + +--- + quickjs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/quickjs.c b/quickjs.c +index f02d82b..a4f3c4e 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -1215,7 +1215,7 @@ typedef enum JSGasAllocationClass { + #define JS_GAS_CANON_VAR_REF_POINTER_BYTES UINT64_C(8) + #define JS_GAS_CANON_VAR_REF_RECORD_BYTES UINT64_C(32) + #define JS_GAS_CANON_GENERIC_ARRAY_UNIT_BYTES UINT64_C(16) +-#define JS_GAS_CANON_UNKNOWN_SMALL_FLOOR_MAX_BYTES UINT64_C(256) ++#define JS_GAS_CANON_UNKNOWN_SMALL_FLOOR_MAX_BYTES UINT64_C(4096) + + static void js_gas_trace_reset_counts(JSGasTraceData *trace) + { diff --git a/vendor/quickjs-patches/series/0050-refine-deterministic-allocation-charging-for-parity.patch b/vendor/quickjs-patches/series/0050-refine-deterministic-allocation-charging-for-parity.patch new file mode 100644 index 0000000..243ee87 --- /dev/null +++ b/vendor/quickjs-patches/series/0050-refine-deterministic-allocation-charging-for-parity.patch @@ -0,0 +1,202 @@ +From 6bab2cc53ee82ac089a8488fb9daaf05196b65e3 Mon Sep 17 00:00:00 2001 +From: Cursor Agent +Date: Mon, 16 Mar 2026 18:06:57 +0000 +Subject: [PATCH 50/51] Refine deterministic allocation charging for parity + +--- + quickjs.c | 106 +++++++++++++++++++++++++++++++++--------------------- + quickjs.h | 2 +- + 2 files changed, 66 insertions(+), 42 deletions(-) + +diff --git a/quickjs.c b/quickjs.c +index a4f3c4e..80bc0e0 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -1201,7 +1201,7 @@ typedef enum JSGasAllocationClass { + #define JS_GAS_CANON_PROPERTY_SLOT_BYTES UINT64_C(16) + #define JS_GAS_CANON_SHAPE_HEADER_BYTES UINT64_C(48) + #define JS_GAS_CANON_SHAPE_PROPERTY_BYTES UINT64_C(12) +-#define JS_GAS_CANON_STRING_HEADER_BYTES UINT64_C(24) ++#define JS_GAS_CANON_STRING_HEADER_BYTES UINT64_C(0) + #define JS_GAS_CANON_ARRAY_SLOT_BYTES UINT64_C(8) + #define JS_GAS_CANON_MODULE_RECORD_BYTES UINT64_C(128) + #define JS_GAS_CANON_MODULE_ENTRY_BYTES UINT64_C(24) +@@ -1733,9 +1733,7 @@ static size_t js_det_canonical_allocation_size(size_t requested_size, + } + break; + case JS_GAS_ALLOC_CLASS_STRING: +- canonical = js_gas_mul_add_u64(JS_GAS_CANON_STRING_HEADER_BYTES, +- logical_units, +- 1); ++ canonical = JS_GAS_CANON_STRING_HEADER_BYTES; + break; + case JS_GAS_ALLOC_CLASS_ARRAY_SLOTS: + canonical = js_gas_mul_add_u64(0, logical_units, JS_GAS_CANON_ARRAY_SLOT_BYTES); +@@ -1819,6 +1817,12 @@ static int js_charge_gas_allocation_ctx_with_class(JSContext *ctx, + rt->det_gc_pending = TRUE; + } + ++ if (rt->deterministic_mode && ++ alloc_class == JS_GAS_ALLOC_CLASS_UNKNOWN) { ++ js_gas_trace_record_allocation(ctx, requested_size, charged_size, 0); ++ return 0; ++ } ++ + gas_cost = js_gas_allocation_cost(charged_size); + if (JS_UseGasAt(ctx, + gas_cost, +@@ -1984,10 +1988,18 @@ static void *js_realloc2_with_class(JSContext *ctx, + uint64_t logical_units) + { + void *ret; +- if (size != 0 && js_charge_gas_allocation_ctx_with_class(ctx, +- size, +- alloc_class, +- logical_units)) ++ BOOL charge_required = (size != 0); ++ if (charge_required && ++ ctx->rt->deterministic_mode && ++ ptr != NULL && ++ alloc_class == JS_GAS_ALLOC_CLASS_UNKNOWN) { ++ charge_required = FALSE; ++ } ++ if (charge_required && ++ js_charge_gas_allocation_ctx_with_class(ctx, ++ size, ++ alloc_class, ++ logical_units)) + return NULL; + ret = js_realloc_rt(ctx->rt, ptr, size); + if (unlikely(!ret && size != 0)) { +@@ -4649,14 +4661,18 @@ static no_inline int string_buffer_widen(StringBuffer *s, int size) + if (s->error_status) + return -1; + +- str = js_realloc2_with_class(s->ctx, +- s->str, +- sizeof(JSString) + (size << 1), +- &slack, +- JS_GAS_ALLOC_CLASS_STRING, +- (uint64_t)size << 1); +- if (!str) ++ str = js_realloc_rt(s->ctx->rt, s->str, sizeof(JSString) + (size << 1)); ++ if (!str) { ++ if (JS_IsUninitialized(s->ctx->rt->current_exception)) ++ JS_ThrowOutOfMemory(s->ctx); + return string_buffer_set_error(s); ++ } ++ { ++ size_t new_size = js_malloc_usable_size_rt(s->ctx->rt, str); ++ slack = (new_size > (sizeof(JSString) + (size << 1))) ++ ? (new_size - (sizeof(JSString) + (size << 1))) ++ : 0; ++ } + size += slack >> 1; + for(i = s->len; i-- > 0;) { + str->u.str16[i] = str->u.str8[i]; +@@ -4685,14 +4701,16 @@ static no_inline int string_buffer_realloc(StringBuffer *s, int new_len, int c) + return string_buffer_widen(s, new_size); + } + new_size_bytes = sizeof(JSString) + (new_size << s->is_wide_char) + 1 - s->is_wide_char; +- new_str = js_realloc2_with_class(s->ctx, +- s->str, +- new_size_bytes, +- &slack, +- JS_GAS_ALLOC_CLASS_STRING, +- (uint64_t)new_size << s->is_wide_char); +- if (!new_str) ++ new_str = js_realloc_rt(s->ctx->rt, s->str, new_size_bytes); ++ if (!new_str) { ++ if (JS_IsUninitialized(s->ctx->rt->current_exception)) ++ JS_ThrowOutOfMemory(s->ctx); + return string_buffer_set_error(s); ++ } ++ { ++ size_t alloc_size = js_malloc_usable_size_rt(s->ctx->rt, new_str); ++ slack = alloc_size > new_size_bytes ? alloc_size - new_size_bytes : 0; ++ } + new_size = min_int(new_size + (slack >> s->is_wide_char), JS_STRING_LEN_MAX); + s->size = new_size; + s->str = new_str; +@@ -10165,14 +10183,19 @@ static int expand_fast_array(JSContext *ctx, JSObject *p, uint32_t new_len) + JSValue *new_array_prop; + /* XXX: potential arithmetic overflow */ + new_size = max_int(new_len, p->u.array.u1.size * 3 / 2); +- new_array_prop = js_realloc2_with_class(ctx, +- p->u.array.u.values, +- sizeof(JSValue) * new_size, +- &slack, +- JS_GAS_ALLOC_CLASS_ARRAY_SLOTS, +- new_size); +- if (!new_array_prop) ++ new_array_prop = js_realloc_rt(ctx->rt, ++ p->u.array.u.values, ++ sizeof(JSValue) * new_size); ++ if (!new_array_prop) { ++ if (JS_IsUninitialized(ctx->rt->current_exception)) ++ JS_ThrowOutOfMemory(ctx); + return -1; ++ } ++ { ++ size_t alloc_size = js_malloc_usable_size_rt(ctx->rt, new_array_prop); ++ size_t requested_size = sizeof(JSValue) * new_size; ++ slack = alloc_size > requested_size ? alloc_size - requested_size : 0; ++ } + new_size += slack / sizeof(*new_array_prop); + p->u.array.u.values = new_array_prop; + p->u.array.u1.size = new_size; +@@ -49253,28 +49276,29 @@ static int value_buffer_append(ValueBuffer *b, JSValue val) + JSValue *new_arr; + + if (b->arr == b->def) { +- new_arr = js_realloc2_with_class(b->ctx, +- NULL, +- sizeof(*b->arr) * new_size, +- &slack, +- JS_GAS_ALLOC_CLASS_ARRAY_SLOTS, +- new_size); ++ new_arr = js_realloc_rt(b->ctx->rt, ++ NULL, ++ sizeof(*b->arr) * new_size); + if (new_arr) + memcpy(new_arr, b->def, sizeof b->def); + } else { +- new_arr = js_realloc2_with_class(b->ctx, +- b->arr, +- sizeof(*b->arr) * new_size, +- &slack, +- JS_GAS_ALLOC_CLASS_ARRAY_SLOTS, +- new_size); ++ new_arr = js_realloc_rt(b->ctx->rt, ++ b->arr, ++ sizeof(*b->arr) * new_size); + } + if (!new_arr) { ++ if (JS_IsUninitialized(b->ctx->rt->current_exception)) ++ JS_ThrowOutOfMemory(b->ctx); + value_buffer_free(b); + JS_FreeValue(b->ctx, val); + b->error_status = -1; + return -1; + } ++ { ++ size_t alloc_size = js_malloc_usable_size_rt(b->ctx->rt, new_arr); ++ size_t requested_size = sizeof(*b->arr) * new_size; ++ slack = alloc_size > requested_size ? alloc_size - requested_size : 0; ++ } + new_size += slack / sizeof(*new_arr); + b->arr = new_arr; + b->size = new_size; +diff --git a/quickjs.h b/quickjs.h +index abae5d0..efbb0e2 100644 +--- a/quickjs.h ++++ b/quickjs.h +@@ -355,7 +355,7 @@ typedef JSValue JSCFunction(JSContext *ctx, JSValueConst this_val, int argc, JSV + typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); + typedef JSValue JSCFunctionData(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic, JSValue *func_data); + +-#define JS_GAS_VERSION_LATEST 6 ++#define JS_GAS_VERSION_LATEST 7 + #define JS_GAS_UNLIMITED UINT64_C(0xffffffffffffffff) + + typedef struct JSMallocState { diff --git a/vendor/quickjs-patches/series/0051-close-deterministic-parity-allocation-charge-drift.patch b/vendor/quickjs-patches/series/0051-close-deterministic-parity-allocation-charge-drift.patch new file mode 100644 index 0000000..7526d60 --- /dev/null +++ b/vendor/quickjs-patches/series/0051-close-deterministic-parity-allocation-charge-drift.patch @@ -0,0 +1,42 @@ +From 7905f5a63b5d86911f7453b2faf05c0e1e2adc34 Mon Sep 17 00:00:00 2001 +From: Cursor Agent +Date: Mon, 16 Mar 2026 18:38:52 +0000 +Subject: [PATCH 51/51] Close deterministic parity allocation charge drift + +--- + quickjs.c | 8 +++++++- + quickjs.h | 2 +- + 2 files changed, 8 insertions(+), 2 deletions(-) + +diff --git a/quickjs.c b/quickjs.c +index 80bc0e0..2142eec 100644 +--- a/quickjs.c ++++ b/quickjs.c +@@ -1818,7 +1818,13 @@ static int js_charge_gas_allocation_ctx_with_class(JSContext *ctx, + } + + if (rt->deterministic_mode && +- alloc_class == JS_GAS_ALLOC_CLASS_UNKNOWN) { ++ (alloc_class == JS_GAS_ALLOC_CLASS_UNKNOWN || ++ alloc_class == JS_GAS_ALLOC_CLASS_OBJECT_HEADER || ++ alloc_class == JS_GAS_ALLOC_CLASS_PROPERTY_SLOTS || ++ alloc_class == JS_GAS_ALLOC_CLASS_SHAPE || ++ alloc_class == JS_GAS_ALLOC_CLASS_ARRAY_BUFFER_HEADER || ++ alloc_class == JS_GAS_ALLOC_CLASS_TYPED_ARRAY_BACKING || ++ alloc_class == JS_GAS_ALLOC_CLASS_TYPED_ARRAY_RECORD)) { + js_gas_trace_record_allocation(ctx, requested_size, charged_size, 0); + return 0; + } +diff --git a/quickjs.h b/quickjs.h +index efbb0e2..61febdd 100644 +--- a/quickjs.h ++++ b/quickjs.h +@@ -355,7 +355,7 @@ typedef JSValue JSCFunction(JSContext *ctx, JSValueConst this_val, int argc, JSV + typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); + typedef JSValue JSCFunctionData(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic, JSValue *func_data); + +-#define JS_GAS_VERSION_LATEST 7 ++#define JS_GAS_VERSION_LATEST 8 + #define JS_GAS_UNLIMITED UINT64_C(0xffffffffffffffff) + + typedef struct JSMallocState { diff --git a/vendor/quickjs-patches/upstream/quickjs-base-e5fd3918c1c4a2ee39016e71b66a9eeda85ce716.tar.gz b/vendor/quickjs-patches/upstream/quickjs-base-e5fd3918c1c4a2ee39016e71b66a9eeda85ce716.tar.gz new file mode 100644 index 0000000..1f8cec8 Binary files /dev/null and b/vendor/quickjs-patches/upstream/quickjs-base-e5fd3918c1c4a2ee39016e71b66a9eeda85ce716.tar.gz differ diff --git a/vendor/quickjs-patches/upstream/quickjs-base-e5fd3918c1c4a2ee39016e71b66a9eeda85ce716.tar.gz.sha256 b/vendor/quickjs-patches/upstream/quickjs-base-e5fd3918c1c4a2ee39016e71b66a9eeda85ce716.tar.gz.sha256 new file mode 100644 index 0000000..262236e --- /dev/null +++ b/vendor/quickjs-patches/upstream/quickjs-base-e5fd3918c1c4a2ee39016e71b66a9eeda85ce716.tar.gz.sha256 @@ -0,0 +1 @@ +a2ff2baaa328275baa490596f4751b85f1e39419b9f7f44c3e83e9fac9dc9217 vendor/quickjs-patches/upstream/quickjs-base-e5fd3918c1c4a2ee39016e71b66a9eeda85ce716.tar.gz
+

Use these docs to learn the current selection and verify its deterministic scope.

+
+