diff --git a/.claude/hooks/direnv.sh b/.claude/hooks/direnv.sh new file mode 100755 index 0000000000..5826f4a24f --- /dev/null +++ b/.claude/hooks/direnv.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash +# Load the project's direnv/nix dev shell into the Claude Code session so Bash +# tool commands resolve flake-pinned tools (bun, nixfmt, ...) instead of system +# ones. No-op for anyone without direnv or an .envrc, so non-nix setups are +# unaffected. +# +# direnv only *approves* the .envrc; the actual env is exported into +# $CLAUDE_ENV_FILE, which Claude Code sources for every later Bash command. + +set -u + +# Nothing to export into without this; older Claude Code versions won't set it. +[ -n "${CLAUDE_ENV_FILE:-}" ] || exit 0 + +command -v direnv >/dev/null 2>&1 || exit 0 + +# Require an explicit project dir so we never approve/export a stray .envrc from +# some unrelated working directory. +[ -n "${CLAUDE_PROJECT_DIR:-}" ] || exit 0 +cd "$CLAUDE_PROJECT_DIR" || exit 0 +[ -f .envrc ] || exit 0 + +# Clear any inherited direnv state so `export` recomputes the full diff. Without +# this, a stale DIRENV_DIFF from the parent process makes direnv assume the env +# is already loaded and emit nothing. +unset DIRENV_DIR DIRENV_DIFF DIRENV_WATCHES DIRENV_FILE DIRENV_LAYOUT + +direnv allow . 2>/dev/null +direnv export bash >>"$CLAUDE_ENV_FILE" 2>/dev/null + +exit 0 diff --git a/.claude/settings.json b/.claude/settings.json index 8c4e5f038d..954f580759 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -1,23 +1,30 @@ { "$schema": "https://json.schemastore.org/claude-code-settings.json", + "hooks": { + "SessionStart": [ + { + "hooks": [ + { + "type": "command", + "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/direnv.sh" + } + ] + } + ] + }, "permissions": { "allow": [ - "Bash(ls:*)", - "Bash(grep:*)", - "Bash(find:*)", - "Bash(git status:*)", - "Bash(git diff:*)", - "Bash(git log:*)", - "Bash(git add:*)", - "Bash(git commit:*)", - "Bash(git push:*)", - "Bash(git pull:*)", - "Bash(git checkout:*)", - "Bash(git branch:*)", "Bash(just *)", "Bash(cargo *)", "Bash(bun *)", - "WebSearch" + "Bash(ffprobe:*)", + "Bash(rs/libmoq/build.sh:*)", + "WebFetch(domain:www.ietf.org)", + "WebFetch(domain:datatracker.ietf.org)", + "WebFetch(domain:docs.rs)", + "WebFetch(domain:moq-wg.github.io)", + "WebFetch(domain:moq.dev)", + "WebFetch(domain:doc.moq.dev)" ] } } diff --git a/.editorconfig b/.editorconfig index 82a15b8e86..f982778b08 100644 --- a/.editorconfig +++ b/.editorconfig @@ -23,3 +23,19 @@ indent_size = 2 [**.nix] indent_style = space indent_size = 2 + +# shfmt reads these natively. Match existing script style to keep +# the format pass minimal. +[*.sh] +indent_style = space +indent_size = 4 +switch_case_indent = true + +[demo/throttle/enable] +indent_style = space +indent_size = 4 +switch_case_indent = true + +# Skip vendored / build output trees when shfmt walks the repo. +[{node_modules,target,dist,.venv}/**] +ignore = true diff --git a/.env b/.env new file mode 100644 index 0000000000..99feaf1a31 --- /dev/null +++ b/.env @@ -0,0 +1,2 @@ +RUST_BACKTRACE=1 +RUST_LOG="debug" diff --git a/.envrc b/.envrc index b06bc5bb61..76439bd451 100644 --- a/.envrc +++ b/.envrc @@ -10,3 +10,13 @@ if ! has nix_direnv_version || ! nix_direnv_version 3.1.0; then source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/3.1.0/direnvrc" "sha256-yMJ2OVMzrFaDPn7q8nCBZFRYpL/f0RcHzhmw/i6btJM=" fi use_flake + +# Reclaim stale Nix store paths in the background, at most once per week. +# nix-direnv pins the current dev shell, so only older versions are freed. +if has nix-collect-garbage; then + _gc_stamp="$PWD/.direnv/nix-gc-stamp" + if [ ! -f "$_gc_stamp" ] || [ -n "$(find "$_gc_stamp" -mtime +7 2>/dev/null)" ]; then + touch "$_gc_stamp" + (nix-collect-garbage --delete-older-than 7d >/dev/null 2>&1 &) + fi +fi diff --git a/.github/actions/setup-packaging/action.yml b/.github/actions/setup-packaging/action.yml new file mode 100644 index 0000000000..c3e26e4c3c --- /dev/null +++ b/.github/actions/setup-packaging/action.yml @@ -0,0 +1,16 @@ +name: Set up packaging tools +description: Install Nix and prepend the .#packaging output bin/ to $PATH. + +runs: + using: composite + steps: + - uses: DeterminateSystems/nix-installer-action@00199f951aeb9404028a6e4b95ad42546f73296a # main + with: + determinate: false + - uses: DeterminateSystems/magic-nix-cache-action@908b263ff629f4cc17666315b7fd3ec127c6244d # main + + - name: Build packaging tools from flake + shell: bash + run: | + out=$(nix build --no-link --print-out-paths .#packaging) + echo "$out/bin" >> "$GITHUB_PATH" diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 6867e71eb1..6cd87d7879 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -9,3 +9,5 @@ updates: directory: "/" schedule: interval: "weekly" + cooldown: + default-days: 7 diff --git a/.github/homebrew/Formula/moq-cli.rb.tmpl b/.github/homebrew/Formula/moq-cli.rb.tmpl new file mode 100644 index 0000000000..2f92dcf94f --- /dev/null +++ b/.github/homebrew/Formula/moq-cli.rb.tmpl @@ -0,0 +1,36 @@ +class MoqCli < Formula + desc "CLI for publishing and subscribing to Media over QUIC broadcasts" + homepage "https://moq.dev" + version "__VERSION__" + license any_of: ["MIT", "Apache-2.0"] + + on_macos do + on_arm do + url "https://github.com/moq-dev/moq/releases/download/moq-cli-v#{version}/moq-cli-#{version}-aarch64-apple-darwin.tar.gz" + sha256 "__SHA256_AARCH64_APPLE_DARWIN__" + end + on_intel do + url "https://github.com/moq-dev/moq/releases/download/moq-cli-v#{version}/moq-cli-#{version}-x86_64-apple-darwin.tar.gz" + sha256 "__SHA256_X86_64_APPLE_DARWIN__" + end + end + + on_linux do + on_arm do + url "https://github.com/moq-dev/moq/releases/download/moq-cli-v#{version}/moq-cli-#{version}-aarch64-unknown-linux-gnu.tar.gz" + sha256 "__SHA256_AARCH64_UNKNOWN_LINUX_GNU__" + end + on_intel do + url "https://github.com/moq-dev/moq/releases/download/moq-cli-v#{version}/moq-cli-#{version}-x86_64-unknown-linux-gnu.tar.gz" + sha256 "__SHA256_X86_64_UNKNOWN_LINUX_GNU__" + end + end + + def install + bin.install "bin/moq-cli" + end + + test do + system bin/"moq-cli", "--help" + end +end diff --git a/.github/homebrew/Formula/moq-gst.rb.tmpl b/.github/homebrew/Formula/moq-gst.rb.tmpl new file mode 100644 index 0000000000..56c2c7c580 --- /dev/null +++ b/.github/homebrew/Formula/moq-gst.rb.tmpl @@ -0,0 +1,54 @@ +class MoqGst < Formula + desc "GStreamer plugin for publishing and subscribing to Media over QUIC" + homepage "https://moq.dev" + version "__VERSION__" + license any_of: ["MIT", "Apache-2.0"] + + depends_on "gstreamer" + + on_macos do + on_arm do + url "https://github.com/moq-dev/moq/releases/download/moq-gst-v#{version}/moq-gst-#{version}-aarch64-apple-darwin.tar.gz" + sha256 "__SHA256_AARCH64_APPLE_DARWIN__" + end + on_intel do + url "https://github.com/moq-dev/moq/releases/download/moq-gst-v#{version}/moq-gst-#{version}-x86_64-apple-darwin.tar.gz" + sha256 "__SHA256_X86_64_APPLE_DARWIN__" + end + end + + on_linux do + on_arm do + url "https://github.com/moq-dev/moq/releases/download/moq-gst-v#{version}/moq-gst-#{version}-aarch64-unknown-linux-gnu.tar.gz" + sha256 "__SHA256_AARCH64_UNKNOWN_LINUX_GNU__" + end + on_intel do + url "https://github.com/moq-dev/moq/releases/download/moq-gst-v#{version}/moq-gst-#{version}-x86_64-unknown-linux-gnu.tar.gz" + sha256 "__SHA256_X86_64_UNKNOWN_LINUX_GNU__" + end + end + + def install + lib.install Dir["lib/libgstmoq.*"] + end + + def caveats + <<~EOS + The moq GStreamer plugin is installed at: + #{opt_lib}/libgstmoq.#{OS.mac? ? "dylib" : "so"} + + For GStreamer to discover it, add this prefix to GST_PLUGIN_PATH: + export GST_PLUGIN_PATH="#{opt_lib}:$GST_PLUGIN_PATH" + + Then verify with: + gst-inspect-1.0 moq + EOS + end + + test do + plugin = OS.mac? ? "libgstmoq.dylib" : "libgstmoq.so" + assert_predicate lib/plugin, :exist? + ENV["GST_PLUGIN_PATH"] = lib + system Formula["gstreamer"].opt_bin/"gst-inspect-1.0", "moq" + end +end diff --git a/.github/homebrew/Formula/moq-relay.rb.tmpl b/.github/homebrew/Formula/moq-relay.rb.tmpl new file mode 100644 index 0000000000..808c971cec --- /dev/null +++ b/.github/homebrew/Formula/moq-relay.rb.tmpl @@ -0,0 +1,36 @@ +class MoqRelay < Formula + desc "Clusterable relay server for Media over QUIC" + homepage "https://moq.dev" + version "__VERSION__" + license any_of: ["MIT", "Apache-2.0"] + + on_macos do + on_arm do + url "https://github.com/moq-dev/moq/releases/download/moq-relay-v#{version}/moq-relay-#{version}-aarch64-apple-darwin.tar.gz" + sha256 "__SHA256_AARCH64_APPLE_DARWIN__" + end + on_intel do + url "https://github.com/moq-dev/moq/releases/download/moq-relay-v#{version}/moq-relay-#{version}-x86_64-apple-darwin.tar.gz" + sha256 "__SHA256_X86_64_APPLE_DARWIN__" + end + end + + on_linux do + on_arm do + url "https://github.com/moq-dev/moq/releases/download/moq-relay-v#{version}/moq-relay-#{version}-aarch64-unknown-linux-gnu.tar.gz" + sha256 "__SHA256_AARCH64_UNKNOWN_LINUX_GNU__" + end + on_intel do + url "https://github.com/moq-dev/moq/releases/download/moq-relay-v#{version}/moq-relay-#{version}-x86_64-unknown-linux-gnu.tar.gz" + sha256 "__SHA256_X86_64_UNKNOWN_LINUX_GNU__" + end + end + + def install + bin.install "bin/moq-relay" + end + + test do + system bin/"moq-relay", "--help" + end +end diff --git a/.github/homebrew/Formula/moq-token-cli.rb.tmpl b/.github/homebrew/Formula/moq-token-cli.rb.tmpl new file mode 100644 index 0000000000..96689723ec --- /dev/null +++ b/.github/homebrew/Formula/moq-token-cli.rb.tmpl @@ -0,0 +1,36 @@ +class MoqTokenCli < Formula + desc "JWT token generator and validator for moq-relay" + homepage "https://moq.dev" + version "__VERSION__" + license any_of: ["MIT", "Apache-2.0"] + + on_macos do + on_arm do + url "https://github.com/moq-dev/moq/releases/download/moq-token-cli-v#{version}/moq-token-cli-#{version}-aarch64-apple-darwin.tar.gz" + sha256 "__SHA256_AARCH64_APPLE_DARWIN__" + end + on_intel do + url "https://github.com/moq-dev/moq/releases/download/moq-token-cli-v#{version}/moq-token-cli-#{version}-x86_64-apple-darwin.tar.gz" + sha256 "__SHA256_X86_64_APPLE_DARWIN__" + end + end + + on_linux do + on_arm do + url "https://github.com/moq-dev/moq/releases/download/moq-token-cli-v#{version}/moq-token-cli-#{version}-aarch64-unknown-linux-gnu.tar.gz" + sha256 "__SHA256_AARCH64_UNKNOWN_LINUX_GNU__" + end + on_intel do + url "https://github.com/moq-dev/moq/releases/download/moq-token-cli-v#{version}/moq-token-cli-#{version}-x86_64-unknown-linux-gnu.tar.gz" + sha256 "__SHA256_X86_64_UNKNOWN_LINUX_GNU__" + end + end + + def install + bin.install "bin/moq-token-cli" + end + + test do + system bin/"moq-token-cli", "--help" + end +end diff --git a/.github/justfile b/.github/justfile new file mode 100644 index 0000000000..137021cfcf --- /dev/null +++ b/.github/justfile @@ -0,0 +1,9 @@ +set fallback + +# Lint GitHub Actions workflows. Silently skipped if actionlint is not installed. +check: + @if command -v actionlint >/dev/null 2>&1; then actionlint; fi + +# CI variant: actionlint is required (provided by the nix devShell). +ci: + actionlint diff --git a/.github/scripts/release.sh b/.github/scripts/release.sh new file mode 100755 index 0000000000..67cfb5cfef --- /dev/null +++ b/.github/scripts/release.sh @@ -0,0 +1,143 @@ +#!/usr/bin/env bash +# +# Shared release helpers for GitHub Actions workflows. +# Usage: +# release.sh parse-version — extract SemVer from GITHUB_REF given a tag prefix +# release.sh prev-tag — find the tag immediately before the current one +# release.sh create — create or update a GitHub release with artifacts +# release.sh read-version — read `version = "x.y.z"` from a manifest +# release.sh pypi-exists — check whether == is already on PyPI +# +# Environment: +# GITHUB_REF — set by GitHub Actions (e.g. refs/tags/moq-relay-v1.2.3) +# GITHUB_OUTPUT — set by GitHub Actions (for writing step outputs) +# GH_TOKEN — required for `create` subcommand + +set -euo pipefail + +# Parse a SemVer version from GITHUB_REF given a tag prefix. +# Writes version= to $GITHUB_OUTPUT. +parse_version() { + local prefix="$1" + local ref="${GITHUB_REF#refs/tags/}" + + if [[ "$ref" =~ ^${prefix}-v([0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?)$ ]]; then + local version="${BASH_REMATCH[1]}" + echo "version=${version}" >>"$GITHUB_OUTPUT" + echo "Parsed version: ${version}" + else + echo "Tag format not recognized: $ref (expected ${prefix}-v)" >&2 + exit 1 + fi +} + +# Find the tag immediately before the current one (by version sort order). +# Writes tag= to $GITHUB_OUTPUT. +prev_tag() { + local prefix="$1" + local current_tag="${GITHUB_REF#refs/tags/}" + + local prev + prev=$(git tag --list "${prefix}-v*" --sort=v:refname | + awk -v cur="$current_tag" '$0 == cur { print prev; found=1; exit } { prev=$0 } END { if (!found) print "" }') + + echo "tag=${prev}" >>"$GITHUB_OUTPUT" + echo "Previous tag: ${prev:-none}" +} + +# Create or update a GitHub release with artifacts. +# Args: +# Reads tag/title/prev_tag from environment or step outputs. +create_release() { + local artifacts_dir="$1" + local tag="${RELEASE_TAG:?RELEASE_TAG must be set}" + local title="${RELEASE_TITLE:?RELEASE_TITLE must be set}" + local prev_tag="${RELEASE_PREV_TAG:-}" + + if gh release view "$tag" >/dev/null 2>&1; then + echo "Release exists, updating assets and metadata..." + gh release upload "$tag" "$artifacts_dir"/* --clobber + if [ -n "$prev_tag" ]; then + gh release edit "$tag" --title "$title" --notes-start-tag "$prev_tag" + else + gh release edit "$tag" --title "$title" + fi + else + echo "Creating new release..." + if [ -n "$prev_tag" ]; then + gh release create "$tag" \ + --title "$title" \ + --generate-notes \ + --notes-start-tag "$prev_tag" \ + "$artifacts_dir"/* + else + gh release create "$tag" \ + --title "$title" \ + --generate-notes \ + "$artifacts_dir"/* + fi + fi +} + +# Read the static `version = "x.y.z"` from the [project] table of a +# pyproject.toml. Scoped to [project] so a `version` key in another table +# (e.g. a [tool.*] section) can't be picked up by mistake. Writes +# version= to $GITHUB_OUTPUT and stdout. +read_version() { + local manifest="$1" + local version + version=$(sed -n '/^\[project\]/,/^\[/{ + s/^[[:space:]]*version[[:space:]]*=[[:space:]]*"\([^"]*\)".*/\1/p + }' "$manifest" | head -n1) + if [[ -z "$version" ]]; then + echo "Could not read version from [project] in $manifest" >&2 + exit 1 + fi + if [[ -n "${GITHUB_OUTPUT:-}" ]]; then + echo "version=${version}" >>"$GITHUB_OUTPUT" + fi + echo "$version" +} + +# Check whether a distribution+version is already published on PyPI. This is the +# release gate (like release-plz checking the registry): the git tag is just a +# record, the registry is the source of truth. Writes exists=true|false to +# $GITHUB_OUTPUT. A non-200/404 response is treated as fatal rather than +# silently re-publishing. +pypi_exists() { + local dist="$1" + local version="$2" + local url="https://pypi.org/pypi/${dist}/${version}/json" + + # Retry transient failures so a network blip doesn't fail the release gate. + local code + code=$(curl -s -o /dev/null -w '%{http_code}' --max-time 10 --retry 3 --retry-connrefused "$url" 2>/dev/null || true) + + local exists + case "$code" in + 200) exists=true ;; + 404) exists=false ;; + *) + echo "Unexpected status $code querying $url" >&2 + exit 1 + ;; + esac + + if [[ -n "${GITHUB_OUTPUT:-}" ]]; then + echo "exists=${exists}" >>"$GITHUB_OUTPUT" + fi + echo "PyPI ${dist}==${version}: exists=${exists}" +} + +# Dispatch subcommands +case "${1:-}" in + parse-version) parse_version "$2" ;; + prev-tag) prev_tag "$2" ;; + create) create_release "$2" ;; + read-version) read_version "$2" ;; + pypi-exists) pypi_exists "$2" "$3" ;; + *) + echo "Usage: $0 {parse-version|prev-tag|create|read-version|pypi-exists} " >&2 + exit 1 + ;; +esac diff --git a/.github/scripts/render-formula.sh b/.github/scripts/render-formula.sh new file mode 100755 index 0000000000..e156144f70 --- /dev/null +++ b/.github/scripts/render-formula.sh @@ -0,0 +1,102 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Render a Homebrew formula template by substituting __VERSION__ and the +# four __SHA256___ placeholders. +# +# Usage: +# render-formula.sh \ +# --template \ +# --version \ +# --release-dir \ +# --crate \ +# --output +# +# The release dir must contain the four tarballs named like +# --.tar.gz for each of: +# aarch64-apple-darwin +# x86_64-apple-darwin +# aarch64-unknown-linux-gnu +# x86_64-unknown-linux-gnu + +TEMPLATE="" +VERSION="" +RELEASE_DIR="" +CRATE="" +OUTPUT="" + +while [[ $# -gt 0 ]]; do + case $1 in + --template | --version | --release-dir | --crate | --output) + if [[ $# -lt 2 ]]; then + echo "Error: $1 requires a value" >&2 + exit 1 + fi + case $1 in + --template) TEMPLATE="$2" ;; + --version) VERSION="$2" ;; + --release-dir) RELEASE_DIR="$2" ;; + --crate) CRATE="$2" ;; + --output) OUTPUT="$2" ;; + esac + shift 2 + ;; + -h | --help) + echo "Usage: $0 --template T --version V --release-dir D --crate C --output O" + exit 0 + ;; + *) + echo "Unknown option: $1" >&2 + exit 1 + ;; + esac +done + +for var in TEMPLATE VERSION RELEASE_DIR CRATE OUTPUT; do + if [[ -z "${!var}" ]]; then + echo "Error: --${var,,} is required" >&2 + exit 1 + fi +done + +if [[ ! -f "$TEMPLATE" ]]; then + echo "Error: template not found: $TEMPLATE" >&2 + exit 1 +fi + +targets=( + "aarch64-apple-darwin AARCH64_APPLE_DARWIN" + "x86_64-apple-darwin X86_64_APPLE_DARWIN" + "aarch64-unknown-linux-gnu AARCH64_UNKNOWN_LINUX_GNU" + "x86_64-unknown-linux-gnu X86_64_UNKNOWN_LINUX_GNU" +) + +# Read template once and apply all substitutions in-memory. +rendered=$(cat "$TEMPLATE") +rendered="${rendered//__VERSION__/$VERSION}" + +for entry in "${targets[@]}"; do + target="${entry%% *}" + placeholder="${entry##* }" + tarball="$RELEASE_DIR/$CRATE-$VERSION-$target.tar.gz" + + if [[ ! -f "$tarball" ]]; then + echo "Error: tarball not found: $tarball" >&2 + exit 1 + fi + + sha=$(sha256sum "$tarball" | awk '{print $1}') + echo " $target: $sha" + rendered="${rendered//__SHA256_${placeholder}__/$sha}" +done + +# Sanity check: no placeholders left. +if grep -q '__[A-Z0-9_]\+__' <<<"$rendered"; then + echo "Error: unsubstituted placeholders remain:" >&2 + grep -o '__[A-Z0-9_]\+__' <<<"$rendered" | sort -u >&2 + exit 1 +fi + +mkdir -p "$(dirname "$OUTPUT")" +printf '%s\n' "$rendered" >"$OUTPUT" +echo "Wrote: $OUTPUT" diff --git a/.github/scripts/trigger-repo-publish.sh b/.github/scripts/trigger-repo-publish.sh new file mode 100755 index 0000000000..5e4a371c7e --- /dev/null +++ b/.github/scripts/trigger-repo-publish.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# +# Trigger the apt-repo and rpm-repo workflows for a given release tag. +# Called from each per-binary release workflow after `gh release create`, +# because release:published events created via GITHUB_TOKEN don't cascade +# to other workflows automatically. +# +# Required env: +# GH_TOKEN GitHub token with workflow:write +# TAG Release tag, e.g. moq-relay-v1.2.3 + +set -euo pipefail + +TAG="${TAG:?TAG must be set}" + +echo "Dispatching apt-repo.yml for tag $TAG..." +gh workflow run apt-repo.yml -f "tag=$TAG" + +echo "Dispatching rpm-repo.yml for tag $TAG..." +gh workflow run rpm-repo.yml -f "tag=$TAG" diff --git a/.github/workflows/apt-repo.yml b/.github/workflows/apt-repo.yml new file mode 100644 index 0000000000..c8f96738e0 --- /dev/null +++ b/.github/workflows/apt-repo.yml @@ -0,0 +1,62 @@ +name: apt-repo + +# Mirrors .deb artifacts attached to a release into the apt.moq.dev repo. +# Invoked via workflow_dispatch from each per-binary release workflow's +# final job (gh workflow run apt-repo.yml -f tag=...), or manually. +# +# Note: we do NOT trigger on release:published because releases created +# with the default GITHUB_TOKEN don't cascade to other workflows. The +# per-binary workflows call us explicitly instead. + +on: + workflow_dispatch: + inputs: + tag: + description: "Release tag to ingest (e.g. moq-relay-v1.2.3)" + required: true + +permissions: + contents: read + +# Only one apt-repo job can mutate the bucket at a time. Concurrent +# invocations queue and run in order. +concurrency: + group: apt-repo + cancel-in-progress: false + +jobs: + publish: + name: Publish to apt.moq.dev + runs-on: ubuntu-22.04 + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Set up packaging tools + uses: ./.github/actions/setup-packaging + + - name: Download .deb assets from release + shell: bash + env: + GH_TOKEN: ${{ github.token }} + TAG: ${{ inputs.tag }} + run: | + mkdir -p artifacts + gh release download "$TAG" \ + --repo "${{ github.repository }}" \ + --dir artifacts \ + --pattern "*.deb" + ls -la artifacts/ + + - name: Publish to R2 + shell: bash + env: + ARTIFACTS_DIR: artifacts + R2_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }} + R2_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }} + R2_ACCOUNT_ID: ${{ secrets.R2_ACCOUNT_ID }} + SIGNING_KEY: ${{ secrets.SIGNING_KEY }} + SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }} + run: ./infra/apt/publish.sh diff --git a/.github/workflows/cachix.yml b/.github/workflows/cachix.yml index d2c317c54b..e3674b23e3 100644 --- a/.github/workflows/cachix.yml +++ b/.github/workflows/cachix.yml @@ -5,26 +5,66 @@ on: tags: - 'moq-relay-v*' - 'moq-token-cli-v*' - - 'hang-cli-v*' + - 'moq-cli-v*' + - 'moq-boy-v*' + - 'libmoq-v*' + - 'moq-gst-v*' jobs: - cache: - name: Build and push to Cachix - runs-on: ubuntu-latest + # Build and push only the package the tag names. The tag prefix + # (e.g. moq-relay) maps 1:1 to a flake attribute. + release: + name: Release (${{ matrix.os }}) + runs-on: ${{ matrix.os }} permissions: contents: read + strategy: + fail-fast: false + matrix: + os: + - ubuntu-latest + - macos-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + # Full-match REF_NAME against the same -v contract + # release.sh enforces, so a malformed tag fails fast instead of + # building under a trusted identity. + - name: Derive package from tag + id: pkg + env: + REF_NAME: ${{ github.ref_name }} + run: | + re='^(moq-relay|moq-cli|moq-token-cli|moq-boy|libmoq|moq-gst)-v([0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?)$' + if [[ ! "$REF_NAME" =~ $re ]]; then + echo "Tag format not recognized: $REF_NAME" >&2 + exit 1 + fi + echo "name=${BASH_REMATCH[1]}" >> "$GITHUB_OUTPUT" - - uses: DeterminateSystems/nix-installer-action@main - - uses: DeterminateSystems/magic-nix-cache-action@main + - uses: DeterminateSystems/nix-installer-action@00199f951aeb9404028a6e4b95ad42546f73296a # main + with: + determinate: false + - uses: DeterminateSystems/magic-nix-cache-action@908b263ff629f4cc17666315b7fd3ec127c6244d # main - - uses: cachix/cachix-action@v16 + - uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17 with: name: kixelated authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} - - run: nix build ./rs --print-build-logs - - - run: cachix push kixelated ./result + - name: Build and cache + env: + PACKAGE: ${{ steps.pkg.outputs.name }} + OS: ${{ matrix.os }} + run: | + nix build ".#$PACKAGE" --print-build-logs + cachix push kixelated ./result + # Pin so released paths are exempt from GC, otherwise a consumer + # pinning a few-weeks-old tag silently falls back to building once + # the cache GCs the path. keep-revisions bounds storage for the + # free plan; the pin name is per package+OS so each platform keeps + # its own last-N releases instead of clobbering the other's. + cachix pin kixelated "$PACKAGE-$OS" ./result --keep-revisions 10 diff --git a/.github/workflows/check-swift.yml b/.github/workflows/check-swift.yml new file mode 100644 index 0000000000..4d1dfc040e --- /dev/null +++ b/.github/workflows/check-swift.yml @@ -0,0 +1,45 @@ +name: Check Swift + +permissions: + id-token: write + contents: read + +# Swift coverage runs on its own macOS workflow because `swift test` needs +# the macOS toolchain. Gated on Swift sources and `rs/moq-ffi` (which +# Swift bundles via uniffi). +on: + pull_request: + paths: + - 'swift/**' + - 'rs/moq-ffi/**' + - 'justfile' + - '.github/workflows/check-swift.yml' + +concurrency: + group: check-swift-${{ github.ref }} + cancel-in-progress: true + +jobs: + check: + name: Check + runs-on: macos-latest + + steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - uses: DeterminateSystems/nix-installer-action@00199f951aeb9404028a6e4b95ad42546f73296a # main + with: + determinate: false + - uses: DeterminateSystems/magic-nix-cache-action@908b263ff629f4cc17666315b7fd3ec127c6244d # main + + - name: Rust Cache + uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 + with: + cache-on-failure: true + + # No FILES arg = force-run; the workflow's paths filter is + # already the gate for whether to fire at all. + - run: nix develop --command just swift ci diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 291aaec533..b8bc43ee55 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -6,7 +6,11 @@ permissions: on: pull_request: - branches: ["main"] + +# Cancel in-flight runs when a new commit lands on the same PR. +concurrency: + group: check-${{ github.ref }} + cancel-in-progress: true jobs: check: @@ -14,18 +18,30 @@ jobs: runs-on: ubuntu-latest steps: + - name: Free disk space + uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # main + with: + tool-cache: false + - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + # Full history so `just changed` can diff against origin/$GITHUB_BASE_REF. + fetch-depth: 0 - - uses: DeterminateSystems/nix-installer-action@main - - uses: DeterminateSystems/magic-nix-cache-action@main - - uses: DeterminateSystems/flake-checker-action@main + - uses: DeterminateSystems/nix-installer-action@00199f951aeb9404028a6e4b95ad42546f73296a # main + with: + determinate: false + - uses: DeterminateSystems/magic-nix-cache-action@908b263ff629f4cc17666315b7fd3ec127c6244d # main + - uses: DeterminateSystems/flake-checker-action@89c01715e5d0dfdc0a1bfe9d59891ee4945c1483 # main # Cache Rust dependencies and build artifacts - name: Rust Cache - uses: Swatinem/rust-cache@v2 + uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 with: cache-on-failure: true - # Run checks with cached dependencies - - run: nix develop --command just check-all + # `just ci` calls `just changed` internally to skip unchanged scopes. + - run: nix develop --command just ci + diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 01b3e80172..fb49c2d328 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -4,62 +4,105 @@ on: push: tags: - 'moq-relay-v*' - - 'moq-clock-v*' - # NOTE: The -cli is automatically removed - - 'hang-cli-v*' + - 'moq-cli-v*' - 'moq-token-cli-v*' env: - REGISTRY: docker.io/kixelated + REGISTRY: docker.io/moqdev jobs: - deploy: - name: Release - + parse: + name: Parse tag runs-on: ubuntu-latest - permissions: - contents: read - packages: write - id-token: write - + permissions: {} + outputs: + target: ${{ steps.parse.outputs.target }} + version: ${{ steps.parse.outputs.version }} steps: - - uses: actions/checkout@v6 - - # Figure out the docker image based on the tag - id: parse run: | ref=${GITHUB_REF#refs/tags/} if [[ "$ref" =~ ^([a-z-]+)-v([0-9.]+)$ ]]; then - full_target="${BASH_REMATCH[1]}" - version="${BASH_REMATCH[2]}" - # Strip "-cli" suffix from target if present - target="${full_target%-cli}" - echo "target=$target" >> $GITHUB_OUTPUT - echo "version=$version" >> $GITHUB_OUTPUT + echo "target=${BASH_REMATCH[1]}" >> "$GITHUB_OUTPUT" + echo "version=${BASH_REMATCH[2]}" >> "$GITHUB_OUTPUT" else echo "Tag format not recognized." >&2 exit 1 fi - # I'm paying for Depot for faster ARM builds. - - uses: depot/setup-action@v1 + build: + name: Build ${{ matrix.platform }} + needs: parse + strategy: + fail-fast: true + matrix: + include: + - platform: linux/amd64 + runner: ubuntu-latest + - platform: linux/arm64 + runner: ubuntu-24.04-arm + runs-on: ${{ matrix.runner }} + permissions: + contents: read + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 - # Login to docker.io - - uses: docker/login-action@v3 + - uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - # Build and push multi-arch Docker images using Depot - - uses: depot/build-push-action@v1 + # Build and push by digest. The manifest list is assembled in the merge job. + - id: build + uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0 with: - project: r257ctfqm6 context: . - push: true - # Make a smaller image by specifying the package to build + platforms: ${{ matrix.platform }} build-args: | - package=${{ steps.parse.outputs.target }} - tags: | - ${{ env.REGISTRY }}/${{ steps.parse.outputs.target }}:${{ steps.parse.outputs.version }} - ${{ env.REGISTRY }}/${{ steps.parse.outputs.target }}:latest - platforms: linux/amd64,linux/arm64 + package=${{ needs.parse.outputs.target }} + outputs: type=image,name=${{ env.REGISTRY }}/${{ needs.parse.outputs.target }},push-by-digest=true,name-canonical=true,push=true + + - name: Export digest + run: | + mkdir -p /tmp/digests + digest="${{ steps.build.outputs.digest }}" + touch "/tmp/digests/${digest#sha256:}" + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: digests-${{ strategy.job-index }} + path: /tmp/digests/* + if-no-files-found: error + retention-days: 1 + + merge: + name: Publish manifest + needs: [parse, build] + runs-on: ubuntu-latest + permissions: {} + steps: + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + path: /tmp/digests + pattern: digests-* + merge-multiple: true + + - uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 + + - uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Create manifest + working-directory: /tmp/digests + run: | + # shellcheck disable=SC2046 # intentional word-splitting: one arg per digest + docker buildx imagetools create \ + -t ${{ env.REGISTRY }}/${{ needs.parse.outputs.target }}:${{ needs.parse.outputs.version }} \ + -t ${{ env.REGISTRY }}/${{ needs.parse.outputs.target }}:latest \ + $(printf "${{ env.REGISTRY }}/${{ needs.parse.outputs.target }}@sha256:%s " *) diff --git a/.github/workflows/libmoq.yml b/.github/workflows/libmoq.yml index 185d227693..f6d6fd7f5f 100644 --- a/.github/workflows/libmoq.yml +++ b/.github/workflows/libmoq.yml @@ -4,9 +4,14 @@ on: push: tags: - "libmoq-v*" + pull_request: + paths: + - ".github/workflows/libmoq.yml" + - ".github/scripts/release.sh" + - "rs/libmoq/build.sh" permissions: - contents: write + contents: read jobs: build: @@ -19,39 +24,53 @@ jobs: include: - target: x86_64-unknown-linux-gnu os: ubuntu-latest + use_nix: true - target: aarch64-unknown-linux-gnu - os: ubuntu-latest + os: ubuntu-24.04-arm + use_nix: true - target: x86_64-apple-darwin os: macos-15-intel + use_nix: true - target: aarch64-apple-darwin os: macos-latest + use_nix: true - target: x86_64-pc-windows-msvc os: windows-latest + use_nix: false steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + fetch-depth: 0 + persist-credentials: false - - name: Install Rust - uses: dtolnay/rust-toolchain@stable + - name: Install Nix + if: matrix.use_nix + uses: DeterminateSystems/nix-installer-action@00199f951aeb9404028a6e4b95ad42546f73296a # main with: - targets: ${{ matrix.target }} + determinate: false + - name: Configure Nix cache + if: matrix.use_nix + uses: DeterminateSystems/magic-nix-cache-action@908b263ff629f4cc17666315b7fd3ec127c6244d # main - - name: Install cross-compilation tools (Linux ARM64) - if: matrix.target == 'aarch64-unknown-linux-gnu' - run: | - sudo apt-get update - sudo apt-get install -y gcc-aarch64-linux-gnu + - name: Install Rust (Windows) + if: '!matrix.use_nix' + uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable + with: + targets: ${{ matrix.target }} - name: Parse version id: parse shell: bash + env: + EVENT_NAME: ${{ github.event_name }} run: | - ref=${GITHUB_REF#refs/tags/} - if [[ "$ref" =~ ^libmoq-v([0-9.]+)$ ]]; then - echo "version=${BASH_REMATCH[1]}" >> $GITHUB_OUTPUT + if [[ "$EVENT_NAME" == "pull_request" ]]; then + CARGO_VERSION=$(grep '^version' rs/libmoq/Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/') + echo "version=$CARGO_VERSION" >> "$GITHUB_OUTPUT" + echo "Using version from Cargo.toml (PR dry-run): $CARGO_VERSION" else - echo "Tag format not recognized: $ref" >&2 - exit 1 + .github/scripts/release.sh parse-version libmoq fi - name: Build and package @@ -63,7 +82,7 @@ jobs: --output dist - name: Upload artifact - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: libmoq-${{ matrix.target }} path: dist/* @@ -72,28 +91,34 @@ jobs: name: Release needs: build runs-on: ubuntu-latest + if: github.event_name == 'push' + permissions: + contents: write steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + fetch-depth: 0 + persist-credentials: false + - name: Parse version id: parse - run: | - ref=${GITHUB_REF#refs/tags/} - if [[ "$ref" =~ ^libmoq-v([0-9.]+)$ ]]; then - echo "version=${BASH_REMATCH[1]}" >> $GITHUB_OUTPUT - else - echo "Tag format not recognized: $ref" >&2 - exit 1 - fi + run: .github/scripts/release.sh parse-version libmoq + + - name: Find previous tag + id: prev_tag + run: .github/scripts/release.sh prev-tag libmoq - name: Download artifacts - uses: actions/download-artifact@v7 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 with: path: artifacts merge-multiple: true - - name: Create release - uses: softprops/action-gh-release@v2 - with: - name: libmoq v${{ steps.parse.outputs.version }} - generate_release_notes: true - files: artifacts/* + - name: Create or update release + env: + GH_TOKEN: ${{ github.token }} + RELEASE_TAG: ${{ github.ref_name }} + RELEASE_TITLE: "libmoq v${{ steps.parse.outputs.version }}" + RELEASE_PREV_TAG: ${{ steps.prev_tag.outputs.tag }} + run: .github/scripts/release.sh create artifacts diff --git a/.github/workflows/moq-cli.yml b/.github/workflows/moq-cli.yml new file mode 100644 index 0000000000..5e0ebc9d71 --- /dev/null +++ b/.github/workflows/moq-cli.yml @@ -0,0 +1,236 @@ +name: moq-cli + +on: + push: + tags: + - "moq-cli-v*" + pull_request: + paths: + - ".github/workflows/moq-cli.yml" + - ".github/scripts/release.sh" + - "rs/scripts/package-binary.sh" + - "rs/scripts/scrub-macho.sh" + - "packaging/moq-cli/**" + - ".github/actions/setup-packaging/**" + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +permissions: + contents: read + +jobs: + build: + name: Build (${{ matrix.target }}) + runs-on: ${{ matrix.runs-on }} + + strategy: + fail-fast: false + matrix: + include: + - target: x86_64-unknown-linux-gnu + runs-on: ubuntu-22.04 + deb-arch: amd64 + rpm-arch: x86_64 + - target: aarch64-unknown-linux-gnu + runs-on: ubuntu-22.04-arm + deb-arch: arm64 + rpm-arch: aarch64 + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Install Rust + uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable + with: + targets: ${{ matrix.target }} + + - name: Parse version + id: parse + shell: bash + env: + EVENT_NAME: ${{ github.event_name }} + run: | + if [[ "$EVENT_NAME" == "pull_request" ]]; then + CARGO_VERSION=$(grep '^version' rs/moq-cli/Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/') + echo "version=$CARGO_VERSION" >> "$GITHUB_OUTPUT" + echo "Using version from Cargo.toml (PR dry-run): $CARGO_VERSION" + else + .github/scripts/release.sh parse-version moq-cli + fi + + - name: Set up packaging tools + uses: ./.github/actions/setup-packaging + + - name: Build (release, glibc 2.34) + shell: bash + # Pin to glibc 2.34 so one binary covers Ubuntu 22.04+ (.deb) + # and AlmaLinux/RHEL/Rocky 9+ (.rpm). + run: cargo zigbuild --release --target ${{ matrix.target }}.2.34 -p moq-cli + + - name: Rename binary + shell: bash + env: + TARGET: ${{ matrix.target }} + run: | + # The crate is named moq-cli but the .deb / .rpm and Homebrew + # formula present the binary as `moq`. Cargo produces + # target/release/moq-cli by default (no [[bin]] override), + # so make a sibling copy that the downstream packaging steps + # can point at without each one needing to know the rename. + cp "target/${TARGET}/release/moq-cli" "target/${TARGET}/release/moq" + + - name: Package bare binary + shell: bash + run: | + version="${{ steps.parse.outputs.version }}" + target="${{ matrix.target }}" + name="moq-cli-v${version}-${target}" + mkdir -p dist + cp "target/${target}/release/moq" "dist/${name}" + + - name: Package tarball (Homebrew) + shell: bash + env: + VERSION: ${{ steps.parse.outputs.version }} + TARGET: ${{ matrix.target }} + run: | + name="moq-cli-${VERSION}-${TARGET}" + mkdir -p "dist/${name}/bin" + cp "target/${TARGET}/release/moq-cli" "dist/${name}/bin/moq-cli" + cp LICENSE-MIT LICENSE-APACHE "dist/${name}/" + if [[ -f rs/moq-cli/README.md ]]; then + cp rs/moq-cli/README.md "dist/${name}/" + fi + (cd dist && tar -czvf "${name}.tar.gz" "${name}" && rm -rf "${name}") + + - name: Package .deb (Ubuntu 22.04 toolchain) + shell: bash + env: + VERSION: ${{ steps.parse.outputs.version }} + ARCH: ${{ matrix.deb-arch }} + BINARY_PATH: target/${{ matrix.target }}/release/moq + run: | + # nfpm doesn't expand ${VAR} in contents[].src or templating + # there either, so render the env vars in ourselves. + # shellcheck disable=SC2016 # envsubst varlist must be single-quoted + envsubst '$VERSION $ARCH $BINARY_PATH' \ + < packaging/moq-cli/nfpm.yaml > /tmp/nfpm.yaml + nfpm pkg --packager deb --config /tmp/nfpm.yaml --target dist/ + + - name: Package .rpm + shell: bash + env: + VERSION: ${{ steps.parse.outputs.version }} + ARCH: ${{ matrix.rpm-arch }} + BINARY_PATH: target/${{ matrix.target }}/release/moq + run: | + # shellcheck disable=SC2016 # envsubst varlist must be single-quoted + envsubst '$VERSION $ARCH $BINARY_PATH' \ + < packaging/moq-cli/nfpm.yaml > /tmp/nfpm.yaml + nfpm pkg --packager rpm --config /tmp/nfpm.yaml --target dist/ + + - name: Upload artifacts + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: moq-cli-${{ matrix.target }} + path: dist/* + + build-tarball-macos: + name: Build macOS tarball (${{ matrix.target }}) + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + matrix: + include: + - target: x86_64-apple-darwin + os: macos-15-intel + - target: aarch64-apple-darwin + os: macos-latest + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + fetch-depth: 0 + persist-credentials: false + + - uses: DeterminateSystems/nix-installer-action@00199f951aeb9404028a6e4b95ad42546f73296a # main + with: + determinate: false + - uses: DeterminateSystems/magic-nix-cache-action@908b263ff629f4cc17666315b7fd3ec127c6244d # main + + - name: Parse version + id: parse + shell: bash + env: + EVENT_NAME: ${{ github.event_name }} + run: | + if [[ "$EVENT_NAME" == "pull_request" ]]; then + CARGO_VERSION=$(grep '^version' rs/moq-cli/Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/') + echo "version=$CARGO_VERSION" >> "$GITHUB_OUTPUT" + echo "Using version from Cargo.toml (PR dry-run): $CARGO_VERSION" + else + .github/scripts/release.sh parse-version moq-cli + fi + + - name: Build and package tarball + shell: bash + run: | + ./rs/scripts/package-binary.sh \ + --crate moq-cli \ + --target ${{ matrix.target }} \ + --version ${{ steps.parse.outputs.version }} \ + --output dist + + - name: Upload artifact + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: moq-cli-${{ matrix.target }} + path: dist/* + + release: + name: Release + needs: [build, build-tarball-macos] + runs-on: ubuntu-latest + if: github.event_name == 'push' + permissions: + contents: write + actions: write + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + fetch-depth: 0 + persist-credentials: false + + - name: Parse version + id: parse + run: .github/scripts/release.sh parse-version moq-cli + + - name: Find previous tag + id: prev_tag + run: .github/scripts/release.sh prev-tag moq-cli + + - name: Download artifacts + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + path: artifacts + merge-multiple: true + + - name: Create or update release + env: + GH_TOKEN: ${{ github.token }} + RELEASE_TAG: ${{ github.ref_name }} + RELEASE_TITLE: "moq-cli v${{ steps.parse.outputs.version }}" + RELEASE_PREV_TAG: ${{ steps.prev_tag.outputs.tag }} + run: .github/scripts/release.sh create artifacts + + - name: Trigger apt/rpm repo publish + env: + GH_TOKEN: ${{ github.token }} + TAG: ${{ github.ref_name }} + run: .github/scripts/trigger-repo-publish.sh diff --git a/.github/workflows/moq-gst.yml b/.github/workflows/moq-gst.yml new file mode 100644 index 0000000000..de82ce5c38 --- /dev/null +++ b/.github/workflows/moq-gst.yml @@ -0,0 +1,219 @@ +name: moq-gst + +on: + push: + tags: + - "moq-gst-v*" + +permissions: + contents: read + +jobs: + build: + name: Build tarball (${{ matrix.target }}) + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + matrix: + include: + - target: x86_64-unknown-linux-gnu + os: ubuntu-latest + - target: aarch64-unknown-linux-gnu + os: ubuntu-24.04-arm + - target: x86_64-apple-darwin + os: macos-15-intel + - target: aarch64-apple-darwin + os: macos-latest + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + fetch-depth: 0 + persist-credentials: false + + - uses: DeterminateSystems/nix-installer-action@00199f951aeb9404028a6e4b95ad42546f73296a # main + with: + determinate: false + - uses: DeterminateSystems/magic-nix-cache-action@908b263ff629f4cc17666315b7fd3ec127c6244d # main + + - name: Parse version + id: parse + shell: bash + run: .github/scripts/release.sh parse-version moq-gst + + - name: Build and package (tarball) + shell: bash + env: + TARGET: ${{ matrix.target }} + VERSION: ${{ steps.parse.outputs.version }} + run: | + ./rs/moq-gst/build.sh \ + --target "$TARGET" \ + --version "$VERSION" \ + --output dist + + # Load the produced plugin against a system GStreamer the runner just + # installed (separate from the nix copy the build linked against). + # This is the customer-facing scenario: `nix build .#moq-gst` then + # `gst-inspect-1.0 moq`. If dyld/ld.so can't resolve the plugin's deps + # against the system GStreamer, this step fails. + - name: Install system GStreamer + shell: bash + run: | + if [[ "$RUNNER_OS" == "Linux" ]]; then + sudo apt-get update -qq + sudo apt-get install -y --no-install-recommends \ + gstreamer1.0-tools \ + gstreamer1.0-plugins-base \ + gstreamer1.0-plugins-good + else + brew install gstreamer + fi + + - name: Smoke test (gst-inspect against system GStreamer) + shell: bash + env: + TARGET: ${{ matrix.target }} + VERSION: ${{ steps.parse.outputs.version }} + run: | + set -euo pipefail + tar -xzf "dist/moq-gst-${VERSION}-${TARGET}.tar.gz" -C dist/ + ./rs/moq-gst/smoke.sh "dist/moq-gst-${VERSION}-${TARGET}/lib/gstreamer-1.0" + + - name: Upload artifact + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: moq-gst-${{ matrix.target }} + path: dist/*.tar.gz + + package: + name: Package .deb/.rpm (${{ matrix.target }}) + runs-on: ${{ matrix.runs-on }} + + strategy: + fail-fast: false + matrix: + include: + - target: x86_64-unknown-linux-gnu + runs-on: ubuntu-24.04 + deb-arch: amd64 + deb-multiarch: x86_64-linux-gnu + rpm-arch: x86_64 + - target: aarch64-unknown-linux-gnu + runs-on: ubuntu-24.04-arm + deb-arch: arm64 + deb-multiarch: aarch64-linux-gnu + rpm-arch: aarch64 + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Install Rust + uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable + with: + targets: ${{ matrix.target }} + + - name: Set up packaging tools + uses: ./.github/actions/setup-packaging + + - name: Parse version + id: parse + shell: bash + run: .github/scripts/release.sh parse-version moq-gst + + - name: Install GStreamer dev libraries + shell: bash + run: | + # Ubuntu 24.04 ships GStreamer 1.24, satisfying gstreamer-rs + # 0.23's 1.22+ headers requirement. Resulting .so dynamic-links + # to libgstreamer-1.0.so.0 (ABI-stable since 1.0). + sudo apt-get update -qq + sudo apt-get install -y --no-install-recommends \ + libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev + + - name: Build (release, glibc 2.34) + shell: bash + # Pin glibc to 2.34 so one .so covers Debian 12+/Ubuntu 22.04+ + # (.deb) and AlmaLinux/RHEL/Rocky 9+ (.rpm). + run: cargo zigbuild --release --target ${{ matrix.target }}.2.34 -p moq-gst + + - name: Package .deb + shell: bash + env: + VERSION: ${{ steps.parse.outputs.version }} + ARCH: ${{ matrix.deb-arch }} + PKG_NAME: gstreamer1.0-moq + PLUGIN_PATH: target/${{ matrix.target }}/release/libgstmoq.so + PLUGIN_DIR: /usr/lib/${{ matrix.deb-multiarch }}/gstreamer-1.0 + run: | + mkdir -p dist + # shellcheck disable=SC2016 # envsubst varlist must be single-quoted + envsubst '$VERSION $ARCH $PKG_NAME $PLUGIN_PATH $PLUGIN_DIR' \ + < packaging/moq-gst/nfpm.yaml > /tmp/nfpm.yaml + nfpm pkg --packager deb --config /tmp/nfpm.yaml --target dist/ + + - name: Package .rpm + shell: bash + env: + VERSION: ${{ steps.parse.outputs.version }} + ARCH: ${{ matrix.rpm-arch }} + PKG_NAME: gstreamer1-moq + PLUGIN_PATH: target/${{ matrix.target }}/release/libgstmoq.so + PLUGIN_DIR: /usr/lib64/gstreamer-1.0 + run: | + mkdir -p dist + # shellcheck disable=SC2016 # envsubst varlist must be single-quoted + envsubst '$VERSION $ARCH $PKG_NAME $PLUGIN_PATH $PLUGIN_DIR' \ + < packaging/moq-gst/nfpm.yaml > /tmp/nfpm.yaml + nfpm pkg --packager rpm --config /tmp/nfpm.yaml --target dist/ + + - name: Upload artifacts + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: moq-gst-pkg-${{ matrix.target }} + path: dist/* + + release: + name: Release + needs: [build, package] + runs-on: ubuntu-latest + permissions: + contents: write + actions: write + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + fetch-depth: 0 + persist-credentials: false + + - name: Parse version + id: parse + run: .github/scripts/release.sh parse-version moq-gst + + - name: Find previous tag + id: prev_tag + run: .github/scripts/release.sh prev-tag moq-gst + + - name: Download artifacts + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + path: artifacts + merge-multiple: true + + - name: Create or update release + env: + GH_TOKEN: ${{ github.token }} + RELEASE_TAG: ${{ github.ref_name }} + RELEASE_TITLE: "moq-gst v${{ steps.parse.outputs.version }}" + RELEASE_PREV_TAG: ${{ steps.prev_tag.outputs.tag }} + run: .github/scripts/release.sh create artifacts + + - name: Trigger apt/rpm repo publish + env: + GH_TOKEN: ${{ github.token }} + TAG: ${{ github.ref_name }} + run: .github/scripts/trigger-repo-publish.sh diff --git a/.github/workflows/moq-relay.yml b/.github/workflows/moq-relay.yml new file mode 100644 index 0000000000..2f5df0eb23 --- /dev/null +++ b/.github/workflows/moq-relay.yml @@ -0,0 +1,225 @@ +name: moq-relay + +on: + push: + tags: + - "moq-relay-v*" + pull_request: + paths: + - ".github/workflows/moq-relay.yml" + - ".github/scripts/release.sh" + - "rs/scripts/package-binary.sh" + - "rs/scripts/scrub-macho.sh" + - "packaging/moq-relay/**" + - ".github/actions/setup-packaging/**" + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +permissions: + contents: read + +jobs: + build: + name: Build (${{ matrix.target }}) + runs-on: ${{ matrix.runs-on }} + + strategy: + fail-fast: false + matrix: + include: + # Native runners. Each binary is built on the same arch it ships + # for, so the .deb/.rpm linkage matches the distro's glibc on the + # oldest LTS we support (Ubuntu 22.04 / AlmaLinux 9). + - target: x86_64-unknown-linux-gnu + runs-on: ubuntu-22.04 + deb-arch: amd64 + rpm-arch: x86_64 + - target: aarch64-unknown-linux-gnu + runs-on: ubuntu-22.04-arm + deb-arch: arm64 + rpm-arch: aarch64 + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Install Rust + uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable + with: + targets: ${{ matrix.target }} + + - name: Parse version + id: parse + shell: bash + env: + EVENT_NAME: ${{ github.event_name }} + run: | + if [[ "$EVENT_NAME" == "pull_request" ]]; then + CARGO_VERSION=$(grep '^version' rs/moq-relay/Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/') + echo "version=$CARGO_VERSION" >> "$GITHUB_OUTPUT" + echo "Using version from Cargo.toml (PR dry-run): $CARGO_VERSION" + else + .github/scripts/release.sh parse-version moq-relay + fi + + - name: Set up packaging tools + uses: ./.github/actions/setup-packaging + + - name: Build (release, glibc 2.34) + shell: bash + # Pin to glibc 2.34 so one binary covers Ubuntu 22.04+ (.deb) + # and AlmaLinux/RHEL/Rocky 9+ (.rpm). + run: cargo zigbuild --release --target ${{ matrix.target }}.2.34 -p moq-relay + + - name: Package bare binary + shell: bash + run: | + version="${{ steps.parse.outputs.version }}" + target="${{ matrix.target }}" + name="moq-relay-v${version}-${target}" + mkdir -p dist + cp "target/${target}/release/moq-relay" "dist/${name}" + + - name: Package tarball (Homebrew) + shell: bash + env: + VERSION: ${{ steps.parse.outputs.version }} + TARGET: ${{ matrix.target }} + run: | + name="moq-relay-${VERSION}-${TARGET}" + mkdir -p "dist/${name}/bin" + cp "target/${TARGET}/release/moq-relay" "dist/${name}/bin/moq-relay" + cp LICENSE-MIT LICENSE-APACHE "dist/${name}/" + if [[ -f rs/moq-relay/README.md ]]; then + cp rs/moq-relay/README.md "dist/${name}/" + fi + (cd dist && tar -czvf "${name}.tar.gz" "${name}" && rm -rf "${name}") + + - name: Package .deb (Ubuntu 22.04 toolchain, glibc 2.35) + shell: bash + env: + VERSION: ${{ steps.parse.outputs.version }} + ARCH: ${{ matrix.deb-arch }} + BINARY_PATH: target/${{ matrix.target }}/release/moq-relay + run: | + # shellcheck disable=SC2016 # envsubst varlist must be single-quoted + envsubst '$VERSION $ARCH $BINARY_PATH' \ + < packaging/moq-relay/nfpm.yaml > /tmp/nfpm.yaml + nfpm pkg --packager deb --config /tmp/nfpm.yaml --target dist/ + + - name: Package .rpm + shell: bash + env: + VERSION: ${{ steps.parse.outputs.version }} + ARCH: ${{ matrix.rpm-arch }} + BINARY_PATH: target/${{ matrix.target }}/release/moq-relay + run: | + # shellcheck disable=SC2016 # envsubst varlist must be single-quoted + envsubst '$VERSION $ARCH $BINARY_PATH' \ + < packaging/moq-relay/nfpm.yaml > /tmp/nfpm.yaml + nfpm pkg --packager rpm --config /tmp/nfpm.yaml --target dist/ + + - name: Upload artifacts + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: moq-relay-${{ matrix.target }} + path: dist/* + + build-tarball-macos: + name: Build macOS tarball (${{ matrix.target }}) + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + matrix: + include: + - target: x86_64-apple-darwin + os: macos-15-intel + - target: aarch64-apple-darwin + os: macos-latest + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + fetch-depth: 0 + persist-credentials: false + + - uses: DeterminateSystems/nix-installer-action@00199f951aeb9404028a6e4b95ad42546f73296a # main + with: + determinate: false + - uses: DeterminateSystems/magic-nix-cache-action@908b263ff629f4cc17666315b7fd3ec127c6244d # main + + - name: Parse version + id: parse + shell: bash + env: + EVENT_NAME: ${{ github.event_name }} + run: | + if [[ "$EVENT_NAME" == "pull_request" ]]; then + CARGO_VERSION=$(grep '^version' rs/moq-relay/Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/') + echo "version=$CARGO_VERSION" >> "$GITHUB_OUTPUT" + echo "Using version from Cargo.toml (PR dry-run): $CARGO_VERSION" + else + .github/scripts/release.sh parse-version moq-relay + fi + + - name: Build and package tarball + shell: bash + run: | + ./rs/scripts/package-binary.sh \ + --crate moq-relay \ + --target ${{ matrix.target }} \ + --version ${{ steps.parse.outputs.version }} \ + --output dist + + - name: Upload artifact + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: moq-relay-${{ matrix.target }} + path: dist/* + + release: + name: Release + needs: [build, build-tarball-macos] + runs-on: ubuntu-latest + if: github.event_name == 'push' + permissions: + contents: write + actions: write + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + fetch-depth: 0 + persist-credentials: false + + - name: Parse version + id: parse + run: .github/scripts/release.sh parse-version moq-relay + + - name: Find previous tag + id: prev_tag + run: .github/scripts/release.sh prev-tag moq-relay + + - name: Download artifacts + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + path: artifacts + merge-multiple: true + + - name: Create or update release + env: + GH_TOKEN: ${{ github.token }} + RELEASE_TAG: ${{ github.ref_name }} + RELEASE_TITLE: "moq-relay v${{ steps.parse.outputs.version }}" + RELEASE_PREV_TAG: ${{ steps.prev_tag.outputs.tag }} + run: .github/scripts/release.sh create artifacts + + - name: Trigger apt/rpm repo publish + env: + GH_TOKEN: ${{ github.token }} + TAG: ${{ github.ref_name }} + run: .github/scripts/trigger-repo-publish.sh diff --git a/.github/workflows/moq-token-cli.yml b/.github/workflows/moq-token-cli.yml new file mode 100644 index 0000000000..b5407edaba --- /dev/null +++ b/.github/workflows/moq-token-cli.yml @@ -0,0 +1,222 @@ +name: moq-token-cli + +on: + push: + tags: + - "moq-token-cli-v*" + pull_request: + paths: + - ".github/workflows/moq-token-cli.yml" + - ".github/scripts/release.sh" + - "rs/scripts/package-binary.sh" + - "rs/scripts/scrub-macho.sh" + - "packaging/moq-token-cli/**" + - ".github/actions/setup-packaging/**" + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +permissions: + contents: read + +jobs: + build: + name: Build (${{ matrix.target }}) + runs-on: ${{ matrix.runs-on }} + + strategy: + fail-fast: false + matrix: + include: + - target: x86_64-unknown-linux-gnu + runs-on: ubuntu-22.04 + deb-arch: amd64 + rpm-arch: x86_64 + - target: aarch64-unknown-linux-gnu + runs-on: ubuntu-22.04-arm + deb-arch: arm64 + rpm-arch: aarch64 + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Install Rust + uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable + with: + targets: ${{ matrix.target }} + + - name: Parse version + id: parse + shell: bash + env: + EVENT_NAME: ${{ github.event_name }} + run: | + if [[ "$EVENT_NAME" == "pull_request" ]]; then + CARGO_VERSION=$(grep '^version' rs/moq-token-cli/Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/') + echo "version=$CARGO_VERSION" >> "$GITHUB_OUTPUT" + echo "Using version from Cargo.toml (PR dry-run): $CARGO_VERSION" + else + .github/scripts/release.sh parse-version moq-token-cli + fi + + - name: Set up packaging tools + uses: ./.github/actions/setup-packaging + + - name: Build (release, glibc 2.34) + shell: bash + # Pin to glibc 2.34 so one binary covers Ubuntu 22.04+ (.deb) + # and AlmaLinux/RHEL/Rocky 9+ (.rpm). + run: cargo zigbuild --release --target ${{ matrix.target }}.2.34 -p moq-token-cli + + - name: Package bare binary + shell: bash + run: | + version="${{ steps.parse.outputs.version }}" + target="${{ matrix.target }}" + name="moq-token-cli-v${version}-${target}" + mkdir -p dist + cp "target/${target}/release/moq-token-cli" "dist/${name}" + + - name: Package tarball (Homebrew) + shell: bash + env: + VERSION: ${{ steps.parse.outputs.version }} + TARGET: ${{ matrix.target }} + run: | + name="moq-token-cli-${VERSION}-${TARGET}" + mkdir -p "dist/${name}/bin" + cp "target/${TARGET}/release/moq-token-cli" "dist/${name}/bin/moq-token-cli" + cp LICENSE-MIT LICENSE-APACHE "dist/${name}/" + if [[ -f rs/moq-token-cli/README.md ]]; then + cp rs/moq-token-cli/README.md "dist/${name}/" + fi + (cd dist && tar -czvf "${name}.tar.gz" "${name}" && rm -rf "${name}") + + - name: Package .deb (Ubuntu 22.04 toolchain) + shell: bash + env: + VERSION: ${{ steps.parse.outputs.version }} + ARCH: ${{ matrix.deb-arch }} + BINARY_PATH: target/${{ matrix.target }}/release/moq-token-cli + run: | + # shellcheck disable=SC2016 # envsubst varlist must be single-quoted + envsubst '$VERSION $ARCH $BINARY_PATH' \ + < packaging/moq-token-cli/nfpm.yaml > /tmp/nfpm.yaml + nfpm pkg --packager deb --config /tmp/nfpm.yaml --target dist/ + + - name: Package .rpm + shell: bash + env: + VERSION: ${{ steps.parse.outputs.version }} + ARCH: ${{ matrix.rpm-arch }} + BINARY_PATH: target/${{ matrix.target }}/release/moq-token-cli + run: | + # shellcheck disable=SC2016 # envsubst varlist must be single-quoted + envsubst '$VERSION $ARCH $BINARY_PATH' \ + < packaging/moq-token-cli/nfpm.yaml > /tmp/nfpm.yaml + nfpm pkg --packager rpm --config /tmp/nfpm.yaml --target dist/ + + - name: Upload artifacts + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: moq-token-cli-${{ matrix.target }} + path: dist/* + + build-tarball-macos: + name: Build macOS tarball (${{ matrix.target }}) + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + matrix: + include: + - target: x86_64-apple-darwin + os: macos-15-intel + - target: aarch64-apple-darwin + os: macos-latest + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + fetch-depth: 0 + persist-credentials: false + + - uses: DeterminateSystems/nix-installer-action@00199f951aeb9404028a6e4b95ad42546f73296a # main + with: + determinate: false + - uses: DeterminateSystems/magic-nix-cache-action@908b263ff629f4cc17666315b7fd3ec127c6244d # main + + - name: Parse version + id: parse + shell: bash + env: + EVENT_NAME: ${{ github.event_name }} + run: | + if [[ "$EVENT_NAME" == "pull_request" ]]; then + CARGO_VERSION=$(grep '^version' rs/moq-token-cli/Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/') + echo "version=$CARGO_VERSION" >> "$GITHUB_OUTPUT" + echo "Using version from Cargo.toml (PR dry-run): $CARGO_VERSION" + else + .github/scripts/release.sh parse-version moq-token-cli + fi + + - name: Build and package tarball + shell: bash + run: | + ./rs/scripts/package-binary.sh \ + --crate moq-token-cli \ + --target ${{ matrix.target }} \ + --version ${{ steps.parse.outputs.version }} \ + --output dist + + - name: Upload artifact + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: moq-token-cli-${{ matrix.target }} + path: dist/* + + release: + name: Release + needs: [build, build-tarball-macos] + runs-on: ubuntu-latest + if: github.event_name == 'push' + permissions: + contents: write + actions: write + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + fetch-depth: 0 + persist-credentials: false + + - name: Parse version + id: parse + run: .github/scripts/release.sh parse-version moq-token-cli + + - name: Find previous tag + id: prev_tag + run: .github/scripts/release.sh prev-tag moq-token-cli + + - name: Download artifacts + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + path: artifacts + merge-multiple: true + + - name: Create or update release + env: + GH_TOKEN: ${{ github.token }} + RELEASE_TAG: ${{ github.ref_name }} + RELEASE_TITLE: "moq-token-cli v${{ steps.parse.outputs.version }}" + RELEASE_PREV_TAG: ${{ steps.prev_tag.outputs.tag }} + run: .github/scripts/release.sh create artifacts + + - name: Trigger apt/rpm repo publish + env: + GH_TOKEN: ${{ github.token }} + TAG: ${{ github.ref_name }} + run: .github/scripts/trigger-repo-publish.sh diff --git a/.github/workflows/release-brew.yml b/.github/workflows/release-brew.yml new file mode 100644 index 0000000000..b7f0c54760 --- /dev/null +++ b/.github/workflows/release-brew.yml @@ -0,0 +1,233 @@ +name: release-brew + +# Renders the matching Homebrew formula template from +# .github/homebrew/Formula/ with the released version + tarball sha256s, +# then pushes the rendered formula to moq-dev/homebrew-tap (which Homebrew +# exposes as the `moq-dev/tap` tap). +# +# Triggered after a per-crate release workflow finishes successfully, so +# the GitHub Release assets are guaranteed to exist by the time we +# download them. +# +# Authenticates as the moq-bot GitHub App. The APP_ID and APP_PRIVATE_KEY +# repo secrets are already wired (see release-swift.yml). The minted +# installation token is scoped to moq-dev/homebrew-tap and expires in 1 +# hour. + +on: + workflow_run: + workflows: + - moq-relay + - moq-cli + - moq-token-cli + - moq-gst + types: + - completed + pull_request: + paths: + - ".github/workflows/release-brew.yml" + - ".github/scripts/render-formula.sh" + - ".github/homebrew/Formula/**" + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +permissions: + contents: read + +jobs: + dry-run: + name: Dry-run render all templates + if: github.event_name == 'pull_request' + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Render every template against synthetic tarballs + run: | + set -euo pipefail + mkdir -p fake-assets rendered + + shopt -s nullglob + templates=(.github/homebrew/Formula/*.rb.tmpl) + if (( ${#templates[@]} == 0 )); then + echo "No templates found under .github/homebrew/Formula/" >&2 + exit 1 + fi + + # Use a stable dummy version so any baked-in version assertions in + # the templates render deterministically. The sha256s differ per + # crate because the fake tarball content includes the crate name. + VERSION="0.0.0-dryrun" + + for tmpl in "${templates[@]}"; do + crate=$(basename "$tmpl" .rb.tmpl) + echo "::group::Render $crate" + rm -f fake-assets/* + for target in \ + aarch64-apple-darwin \ + x86_64-apple-darwin \ + aarch64-unknown-linux-gnu \ + x86_64-unknown-linux-gnu + do + printf 'fake %s %s\n' "$crate" "$target" \ + > "fake-assets/${crate}-${VERSION}-${target}.tar.gz" + done + + ./.github/scripts/render-formula.sh \ + --template "$tmpl" \ + --version "$VERSION" \ + --release-dir fake-assets \ + --crate "$crate" \ + --output "rendered/${crate}.rb" + + if grep -E '__[A-Z0-9_]+__' "rendered/${crate}.rb"; then + echo "Error: unsubstituted placeholders in rendered/${crate}.rb" >&2 + exit 1 + fi + + ruby -c "rendered/${crate}.rb" + echo "::endgroup::" + done + + publish: + name: Publish formula to homebrew-tap + if: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success' && startsWith(github.event.workflow_run.head_branch, 'moq-') }} + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Parse crate and version + id: parse + env: + TAG: ${{ github.event.workflow_run.head_branch }} + run: | + if [[ ! "$TAG" =~ ^(.+)-v([0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?)$ ]]; then + echo "Tag format not recognized: $TAG" >&2 + exit 1 + fi + crate="${BASH_REMATCH[1]}" + version="${BASH_REMATCH[2]}" + { + echo "crate=$crate" + echo "version=$version" + echo "tag=$TAG" + } >> "$GITHUB_OUTPUT" + echo "Crate: $crate" + echo "Version: $version" + + - name: Check template exists + env: + CRATE: ${{ steps.parse.outputs.crate }} + run: | + template=".github/homebrew/Formula/${CRATE}.rb.tmpl" + if [[ ! -f "$template" ]]; then + echo "No Homebrew template for crate: $CRATE (looked for $template)" >&2 + exit 1 + fi + + - name: Download release tarballs + env: + GH_TOKEN: ${{ github.token }} + TAG: ${{ steps.parse.outputs.tag }} + CRATE: ${{ steps.parse.outputs.crate }} + VERSION: ${{ steps.parse.outputs.version }} + run: | + mkdir -p release-assets + for target in \ + aarch64-apple-darwin \ + x86_64-apple-darwin \ + aarch64-unknown-linux-gnu \ + x86_64-unknown-linux-gnu + do + name="${CRATE}-${VERSION}-${target}.tar.gz" + echo "Downloading $name..." + gh release download "$TAG" \ + --repo "${{ github.repository }}" \ + --pattern "$name" \ + --dir release-assets + done + ls -la release-assets + + - name: Render formula + env: + CRATE: ${{ steps.parse.outputs.crate }} + VERSION: ${{ steps.parse.outputs.version }} + run: | + mkdir -p rendered + ./.github/scripts/render-formula.sh \ + --template ".github/homebrew/Formula/${CRATE}.rb.tmpl" \ + --version "$VERSION" \ + --release-dir release-assets \ + --crate "$CRATE" \ + --output "rendered/${CRATE}.rb" + echo "--- Rendered formula ---" + cat "rendered/${CRATE}.rb" + + - name: Generate moq-bot token + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3 + id: token + with: + app-id: ${{ secrets.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + owner: moq-dev + repositories: homebrew-tap + permission-contents: write + + - name: Checkout homebrew-tap + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + repository: moq-dev/homebrew-tap + token: ${{ steps.token.outputs.token }} + path: homebrew-tap + + - name: Commit and push formula + env: + CRATE: ${{ steps.parse.outputs.crate }} + VERSION: ${{ steps.parse.outputs.version }} + GIT_AUTHOR_NAME: moq-bot + GIT_AUTHOR_EMAIL: moq-bot[bot]@users.noreply.github.com + GIT_COMMITTER_NAME: moq-bot + GIT_COMMITTER_EMAIL: moq-bot[bot]@users.noreply.github.com + run: | + cd homebrew-tap + mkdir -p Formula + cp "../rendered/${CRATE}.rb" "Formula/${CRATE}.rb" + + # Seed a README the first time the tap repo receives a push. + if [[ ! -f README.md ]]; then + cat > README.md <<'EOF' + # moq Homebrew tap + + Homebrew formulae for the [moq](https://github.com/moq-dev/moq) workspace. + + ```bash + brew tap moq-dev/tap + brew install moq-dev/tap/moq-relay + brew install moq-dev/tap/moq-cli + brew install moq-dev/tap/moq-token-cli + brew install moq-dev/tap/moq-gst + ``` + + Formulae here are generated automatically by the + [release-brew workflow](https://github.com/moq-dev/moq/blob/main/.github/workflows/release-brew.yml) + in moq-dev/moq. Do not edit by hand; edit the templates under + `.github/homebrew/Formula/` in moq-dev/moq instead. + EOF + fi + + if git diff --quiet && [[ -z "$(git status --porcelain)" ]]; then + echo "No changes to commit (formula already up to date)." + exit 0 + fi + + git add Formula/ README.md + git commit -m "${CRATE}: bump to v${VERSION}" + git push diff --git a/.github/workflows/release-go.yml b/.github/workflows/release-go.yml new file mode 100644 index 0000000000..a22d4552b2 --- /dev/null +++ b/.github/workflows/release-go.yml @@ -0,0 +1,266 @@ +name: Release Go + +on: + push: + tags: + - "moq-ffi-v*" + pull_request: + paths: + - ".github/workflows/release-go.yml" + - ".github/scripts/release.sh" + - "go/scripts/package.sh" + - "go/scripts/publish.sh" + - "rs/moq-ffi/build.sh" + +permissions: + contents: read + +concurrency: + group: release-go + cancel-in-progress: false + +env: + UNIFFI_BINDGEN_GO_TAG: v0.7.1+v0.31.0 + +jobs: + parse-version: + name: Parse version + runs-on: ubuntu-latest + outputs: + version: ${{ steps.parse.outputs.version }} + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Parse version + id: parse + env: + EVENT_NAME: ${{ github.event_name }} + run: | + if [[ "$EVENT_NAME" == "pull_request" ]]; then + CARGO_VERSION=$(grep '^version' rs/moq-ffi/Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/') + echo "version=$CARGO_VERSION" >> "$GITHUB_OUTPUT" + echo "Using version from Cargo.toml (PR dry-run): $CARGO_VERSION" + else + .github/scripts/release.sh parse-version moq-ffi + fi + + build: + name: Build moq-ffi (${{ matrix.target }}) + needs: [parse-version] + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + matrix: + include: + - target: x86_64-unknown-linux-gnu + os: ubuntu-latest + - target: aarch64-unknown-linux-gnu + os: ubuntu-latest + - target: x86_64-apple-darwin + os: macos-latest + - target: aarch64-apple-darwin + os: macos-latest + - target: x86_64-pc-windows-msvc + os: windows-latest + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Install Rust + uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable + with: + targets: ${{ matrix.target }} + + - name: Rust cache + uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 + + - name: Install cross-compilation tools (Linux ARM64) + if: matrix.target == 'aarch64-unknown-linux-gnu' + run: | + sudo apt-get update + sudo apt-get install -y gcc-aarch64-linux-gnu + + - name: Build + shell: bash + env: + BUILD_TARGET: ${{ matrix.target }} + BUILD_VERSION: ${{ needs.parse-version.outputs.version }} + run: | + ./rs/moq-ffi/build.sh \ + --target "$BUILD_TARGET" \ + --version "$BUILD_VERSION" \ + --output dist + + - name: Upload lib + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: go-lib-${{ matrix.target }} + # package.sh expects /; upload just lib/ contents. + path: dist/moq-ffi-${{ needs.parse-version.outputs.version }}-${{ matrix.target }}/lib/ + + bindings: + name: Generate bindings + needs: [parse-version] + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Install Rust + uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable + + - name: Rust cache + uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 + + - name: Install uniffi-bindgen-go + run: | + cargo install uniffi-bindgen-go \ + --git https://github.com/NordSecurity/uniffi-bindgen-go \ + --tag "$UNIFFI_BINDGEN_GO_TAG" + + - name: Generate bindings + env: + BUILD_VERSION: ${{ needs.parse-version.outputs.version }} + run: | + ./rs/moq-ffi/build.sh \ + --bindings-only \ + --version "$BUILD_VERSION" \ + --output dist + + - name: Upload bindings + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: go-bindings + path: dist/bindings/go/ + + package: + name: Package + needs: [parse-version, build, bindings] + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Download per-target libs + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + path: libs-raw + pattern: go-lib-* + + - name: Flatten lib layout + run: | + mkdir -p libs + for dir in libs-raw/go-lib-*; do + target="${dir#libs-raw/go-lib-}" + mv "$dir" "libs/$target" + done + ls -la libs + + - name: Download bindings + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + name: go-bindings + path: bindings-raw + + - name: Flatten bindings layout + # uniffi-bindgen-go emits moq/{moq.go,moq.h} (some versions nest it + # under uniffi/). package.sh expects bindings/moq/. Copy the whole + # dir so the generated C header (moq.h, #include'd by moq.go's cgo + # preamble) travels with it. + run: | + if [[ -d bindings-raw/uniffi/moq ]]; then + cp -R bindings-raw/uniffi/moq bindings-moq + elif [[ -d bindings-raw/moq ]]; then + cp -R bindings-raw/moq bindings-moq + else + echo "Error: could not locate moq bindings dir under bindings-raw/" >&2 + find bindings-raw -type f + exit 1 + fi + mkdir -p bindings + mv bindings-moq bindings/moq + + - name: Package + env: + BUILD_VERSION: ${{ needs.parse-version.outputs.version }} + run: | + ./go/scripts/package.sh \ + --version "$BUILD_VERSION" \ + --lib-dir libs \ + --bindings-dir bindings \ + --output release-out + + - name: Upload Go module + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: go-package + path: release-out/* + + publish: + name: Publish to Go module mirror + needs: [package, parse-version] + runs-on: ubuntu-latest + if: github.event_name == 'push' + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Generate moq-bot token + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3 + id: token + with: + app-id: ${{ secrets.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + owner: moq-dev + repositories: moq-go + # Narrow the minted token to only what publish.sh needs. + permission-contents: write + + - name: Download package + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + name: go-package + path: go-out + + - name: Publish to moq-dev/moq-go mirror + env: + BUILD_VERSION: ${{ needs.parse-version.outputs.version }} + # Token is minted fresh per run, expires in 1 hour, never at rest. + GO_MIRROR_TOKEN: ${{ steps.token.outputs.token }} + GIT_AUTHOR_NAME: moq-bot + GIT_AUTHOR_EMAIL: moq-bot[bot]@users.noreply.github.com + run: ./go/scripts/publish.sh + + publish-dry-run: + name: Publish dry-run + needs: [package, parse-version] + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Download package + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + name: go-package + path: go-out + + - name: Dry-run publish to mirror + env: + BUILD_VERSION: ${{ needs.parse-version.outputs.version }} + run: ./go/scripts/publish.sh --dry-run diff --git a/.github/workflows/release-js.yml b/.github/workflows/release-js.yml new file mode 100644 index 0000000000..c13e20b0ff --- /dev/null +++ b/.github/workflows/release-js.yml @@ -0,0 +1,49 @@ +name: Release JS + +permissions: + contents: read + id-token: write + +on: + push: + branches: [main] + paths: + - 'js/**' + - '.github/workflows/release-js.yml' + pull_request: + paths: + - '.github/workflows/release-js.yml' + - 'js/common/release.ts' + +concurrency: + group: release-js + cancel-in-progress: false + +jobs: + release: + name: Release JS Packages + runs-on: ubuntu-latest + if: github.repository_owner == 'moq-dev' + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - uses: DeterminateSystems/nix-installer-action@00199f951aeb9404028a6e4b95ad42546f73296a # main + with: + determinate: false + - uses: DeterminateSystems/magic-nix-cache-action@908b263ff629f4cc17666315b7fd3ec127c6244d # main + + - name: Setup npm registry + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 + with: + registry-url: 'https://registry.npmjs.org' + + - name: Install dependencies + run: nix develop --command bun install --frozen-lockfile + + - name: Release packages + env: + DRY_RUN: ${{ github.event_name == 'pull_request' && 'true' || 'false' }} + run: nix develop --command bun --filter '*' release diff --git a/.github/workflows/release-kt.yml b/.github/workflows/release-kt.yml new file mode 100644 index 0000000000..39895ce8f8 --- /dev/null +++ b/.github/workflows/release-kt.yml @@ -0,0 +1,226 @@ +name: Release Kotlin + +on: + push: + tags: + - "moq-ffi-v*" + pull_request: + paths: + - ".github/workflows/release-kt.yml" + - ".github/scripts/release.sh" + - "kt/**" + - "rs/moq-ffi/build.sh" + +permissions: + contents: read + +concurrency: + group: release-kt + cancel-in-progress: false + +jobs: + parse-version: + name: Parse version + runs-on: ubuntu-latest + outputs: + version: ${{ steps.parse.outputs.version }} + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Parse version + id: parse + env: + EVENT_NAME: ${{ github.event_name }} + run: | + if [[ "$EVENT_NAME" == "pull_request" ]]; then + CARGO_VERSION=$(grep '^version' rs/moq-ffi/Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/') + echo "version=$CARGO_VERSION" >> "$GITHUB_OUTPUT" + echo "Using version from Cargo.toml (PR dry-run): $CARGO_VERSION" + else + .github/scripts/release.sh parse-version moq-ffi + fi + + build: + name: Build moq-ffi (${{ matrix.target }}) + needs: [parse-version] + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + matrix: + include: + # Android + - target: aarch64-linux-android + os: ubuntu-latest + - target: armv7-linux-androideabi + os: ubuntu-latest + - target: x86_64-linux-android + os: ubuntu-latest + # Desktop JVM + - target: x86_64-unknown-linux-gnu + os: ubuntu-latest + - target: aarch64-unknown-linux-gnu + os: ubuntu-latest + - target: universal-apple-darwin + os: macos-latest + - target: x86_64-pc-windows-msvc + os: windows-latest + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Install Rust + uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable + with: + targets: ${{ matrix.target == 'universal-apple-darwin' && 'x86_64-apple-darwin,aarch64-apple-darwin' || matrix.target }} + + - name: Rust cache + uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 + + - name: Install cross-compilation tools (Linux ARM64) + if: matrix.target == 'aarch64-unknown-linux-gnu' + run: | + sudo apt-get update + sudo apt-get install -y gcc-aarch64-linux-gnu + + - name: Install cargo-ndk (Android) + if: contains(matrix.target, 'android') + run: cargo install cargo-ndk + + - name: Build + shell: bash + env: + BUILD_TARGET: ${{ matrix.target }} + BUILD_VERSION: ${{ needs.parse-version.outputs.version }} + run: | + ./rs/moq-ffi/build.sh \ + --target "$BUILD_TARGET" \ + --version "$BUILD_VERSION" \ + --output dist + + - name: Upload lib + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: kotlin-lib-${{ matrix.target }} + # Upload only the lib/ contents; package.sh expects /. + path: dist/moq-ffi-${{ needs.parse-version.outputs.version }}-${{ matrix.target }}/lib/ + + bindings: + name: Generate bindings + needs: [parse-version] + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Install Rust + uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable + + - name: Rust cache + uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 + + - name: Generate bindings + env: + BUILD_VERSION: ${{ needs.parse-version.outputs.version }} + run: | + ./rs/moq-ffi/build.sh \ + --bindings-only \ + --version "$BUILD_VERSION" \ + --output dist + + - name: Upload bindings + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: kotlin-bindings + # Upload only the kotlin subdir. + path: dist/bindings/kotlin/ + + package: + name: Package and publish + needs: [parse-version, build, bindings] + runs-on: ubuntu-latest + env: + # Picked up by com.vanniktech.maven.publish via Gradle project properties. + ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.MAVEN_CENTRAL_USERNAME }} + ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.MAVEN_CENTRAL_PASSWORD }} + ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.SIGNING_KEY }} + ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.SIGNING_PASSWORD }} + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 + with: + distribution: temurin + java-version: "17" + + - name: Set up Android SDK + uses: android-actions/setup-android@40fd30fb8d7440372e1316f5d1809ec01dcd3699 # v4.0.1 + + - uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 + + - name: Download per-target libs + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + path: libs-raw + pattern: kotlin-lib-* + + - name: Flatten lib layout + run: | + mkdir -p libs + for dir in libs-raw/kotlin-lib-*; do + target="${dir#libs-raw/kotlin-lib-}" + mv "$dir" "libs/$target" + done + ls -la libs + + - name: Download bindings + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + name: kotlin-bindings + path: bindings + + - name: Stage native libs + bindings into the gradle module + env: + BUILD_VERSION: ${{ needs.parse-version.outputs.version }} + run: | + ./kt/scripts/package.sh \ + --version "$BUILD_VERSION" \ + --lib-dir libs \ + --bindings-dir bindings \ + --output release-out + + - name: Publish to Maven Central + if: github.event_name == 'push' + env: + MOQFFI_VERSION: ${{ needs.parse-version.outputs.version }} + run: | + gradle -p kt \ + -Pmoqffi.version="$MOQFFI_VERSION" \ + -Pandroid.enabled=true \ + :moq:publishAndReleaseToMavenCentral --no-configuration-cache + + - name: Publish to Maven Local (PR dry-run) + if: github.event_name == 'pull_request' + env: + MOQFFI_VERSION: ${{ needs.parse-version.outputs.version }} + run: | + gradle -p kt \ + -Pmoqffi.version="$MOQFFI_VERSION" \ + -Pandroid.enabled=true \ + :moq:publishToMavenLocal --no-configuration-cache + + - name: Upload local maven layout + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: kotlin-package + path: release-out/* diff --git a/.github/workflows/release-py-ffi.yml b/.github/workflows/release-py-ffi.yml new file mode 100644 index 0000000000..a9f8915639 --- /dev/null +++ b/.github/workflows/release-py-ffi.yml @@ -0,0 +1,165 @@ +name: Release Py FFI + +# Builds the `moq-ffi` wheel (raw uniffi bindings). Driven by the +# `moq-ffi-v*` tag that release-plz pushes when it bumps rs/moq-ffi/Cargo.toml. +# The wheel inherits its version from that same Cargo.toml (via maturin's +# dynamic version), so the moq-ffi package stays lockstep with the moq-ffi +# crate. The ergonomic `moq-rs` wrapper is released separately (release-py.yml). + +on: + push: + tags: + - "moq-ffi-v*" + pull_request: + paths: + - ".github/workflows/release-py-ffi.yml" + - ".github/scripts/release.sh" + +permissions: + contents: read + +# Scope by event + ref so a PR dry-run can't queue ahead of a tag publish. +concurrency: + group: release-py-ffi-${{ github.event_name }}-${{ github.ref }} + cancel-in-progress: false + +jobs: + parse-version: + name: Parse version + runs-on: ubuntu-latest + outputs: + version: ${{ steps.parse.outputs.version }} + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Parse version + id: parse + env: + EVENT_NAME: ${{ github.event_name }} + run: | + if [[ "$EVENT_NAME" == "pull_request" ]]; then + CARGO_VERSION=$(grep '^version' rs/moq-ffi/Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/') + echo "version=$CARGO_VERSION" >> "$GITHUB_OUTPUT" + echo "Using version from Cargo.toml (PR dry-run): $CARGO_VERSION" + else + .github/scripts/release.sh parse-version moq-ffi + fi + + # Maturin reads the wheel version from rs/moq-ffi/Cargo.toml (via + # `dynamic = ["version"]` in pyproject.toml). If a tag is pushed by + # hand without bumping Cargo.toml first, the wheel would ship with + # the previous version and PyPI would reject the duplicate upload. + - name: Verify Cargo.toml matches tag + if: github.event_name == 'push' + env: + TAG_VERSION: ${{ steps.parse.outputs.version }} + run: | + CARGO_VERSION=$(grep '^version' rs/moq-ffi/Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/') + if [[ "$TAG_VERSION" != "$CARGO_VERSION" ]]; then + echo "::error::Tag version ($TAG_VERSION) does not match rs/moq-ffi/Cargo.toml version ($CARGO_VERSION). Bump Cargo.toml before tagging." + exit 1 + fi + echo "Cargo.toml version matches tag: $TAG_VERSION" + + build: + name: Build wheels (${{ matrix.target }}) + needs: [parse-version] + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + matrix: + include: + - target: x86_64-unknown-linux-gnu + os: ubuntu-latest + - target: aarch64-unknown-linux-gnu + os: ubuntu-latest + # Use manylinux_2_28 for aarch64-linux to get a newer GCC. + # manylinux2014 ships GCC 4.8.5 which can't compile aws-lc-sys. + manylinux: 2_28 + # The cross image sets TARGET_CC/CXX which leaks into host builds. + before-script-linux: "unset TARGET_CC TARGET_CXX" + - target: x86_64-apple-darwin + os: macos-15-intel + - target: aarch64-apple-darwin + os: macos-latest + - target: x86_64-pc-windows-msvc + os: windows-latest + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 + with: + python-version: "3.12" + + - name: Build wheels + uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1 + with: + # py/moq-ffi/pyproject.toml drives the build; its [tool.maturin] + # block points at rs/moq-ffi/Cargo.toml. + working-directory: py/moq-ffi + args: --release --out dist + target: ${{ matrix.target }} + manylinux: ${{ matrix.manylinux || 'auto' }} + before-script-linux: ${{ matrix.before-script-linux || '' }} + + - name: Upload wheels + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: python-${{ matrix.target }} + path: py/moq-ffi/dist/*.whl + + sdist: + name: Build sdist + needs: [parse-version] + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 + with: + python-version: "3.12" + + - name: Build sdist + uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1 + with: + working-directory: py/moq-ffi + command: sdist + args: --out dist + + - name: Upload sdist + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: python-sdist + path: py/moq-ffi/dist/*.tar.gz + + publish: + name: Publish to PyPI + needs: [build, sdist] + runs-on: ubuntu-latest + if: github.event_name == 'push' + environment: + name: pypi + url: https://pypi.org/p/moq-ffi + permissions: + id-token: write + + steps: + - name: Download wheels + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + pattern: python-* + path: dist + merge-multiple: true + + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # release/v1 diff --git a/.github/workflows/release-py.yml b/.github/workflows/release-py.yml new file mode 100644 index 0000000000..baab2ae62f --- /dev/null +++ b/.github/workflows/release-py.yml @@ -0,0 +1,100 @@ +name: Release Py + +# Publishes the pure-python `moq-rs` wrapper wheel (import name `moq`) to PyPI. +# This is the package most callers install; the raw `moq-ffi` bindings it +# depends on are built separately (release-py-ffi.yml). +# +# Versioned independently of the moq-ffi crate: bump `version` in +# py/moq-rs/pyproject.toml by hand in a normal PR. On merge to main this reads +# that version and publishes only if it isn't already on PyPI. That registry +# check is the release gate (the same model release-plz uses for crates), so +# there's no separate tag to remember. The wrapper depends on `moq-ffi ~= 0.2.x` +# and floats to the latest compatible moq-ffi patch, so a moq-ffi patch needs no +# wrapper re-release. + +on: + push: + branches: + - main + paths: + - "py/moq-rs/**" + - ".github/workflows/release-py.yml" + - ".github/scripts/release.sh" + pull_request: + paths: + - "py/moq-rs/**" + - ".github/workflows/release-py.yml" + - ".github/scripts/release.sh" + +permissions: + contents: read + +# Separate PR builds from mainline publishes so a PR run can't queue ahead of +# (and delay) a release on main. +concurrency: + group: release-py-${{ github.event_name }}-${{ github.ref }} + cancel-in-progress: false + +jobs: + build: + name: Build wheel + sdist + runs-on: ubuntu-latest + if: ${{ github.repository_owner == 'moq-dev' }} + outputs: + version: ${{ steps.version.outputs.version }} + # On PRs we always "publish" into the dry-run sense (build only). On main + # we publish only when the version isn't already on PyPI. + publish: ${{ github.event_name == 'push' && steps.pypi.outputs.exists == 'false' }} + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Read version + id: version + run: .github/scripts/release.sh read-version py/moq-rs/pyproject.toml + + # The release gate: skip publishing a version that's already on PyPI + # (re-uploads are rejected anyway, but this keeps the run green and makes + # the no-op explicit). Runs on PRs too, as an informational dry-run. + - name: Check PyPI + id: pypi + env: + VERSION: ${{ steps.version.outputs.version }} + run: .github/scripts/release.sh pypi-exists moq-rs "$VERSION" + + - uses: DeterminateSystems/nix-installer-action@00199f951aeb9404028a6e4b95ad42546f73296a # main + with: + determinate: false + - uses: DeterminateSystems/magic-nix-cache-action@908b263ff629f4cc17666315b7fd3ec127c6244d # main + + - name: Build + run: nix develop --command just py package + + - name: Upload artifacts + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: python-wrapper + path: py/dist/* + + publish: + name: Publish to PyPI + needs: [build] + runs-on: ubuntu-latest + if: ${{ needs.build.outputs.publish == 'true' }} + environment: + name: pypi + url: https://pypi.org/p/moq-rs + permissions: + id-token: write + + steps: + - name: Download artifacts + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + name: python-wrapper + path: dist + + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # release/v1 diff --git a/.github/workflows/release-rs.yml b/.github/workflows/release-rs.yml new file mode 100644 index 0000000000..d60a2db114 --- /dev/null +++ b/.github/workflows/release-rs.yml @@ -0,0 +1,50 @@ +name: Release RS + +permissions: + pull-requests: write + contents: write + +# Only one release job can run at a time. +concurrency: + group: release-rs + cancel-in-progress: false + +on: + push: + branches: + - main + +jobs: + release: + name: Plz + + runs-on: ubuntu-latest + if: ${{ github.repository_owner == 'moq-dev' }} + + steps: + # Generating a GitHub token, so that PRs and tags created by + # the release-plz-action can trigger actions workflows. + - name: Generate GitHub token + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3 + id: generate-token + with: + app-id: ${{ secrets.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + fetch-depth: 0 + token: ${{ steps.generate-token.outputs.token }} + + # Install Nix for system dependencies (e.g. ffmpeg) + - uses: DeterminateSystems/nix-installer-action@00199f951aeb9404028a6e4b95ad42546f73296a # main + with: + determinate: false + - uses: DeterminateSystems/magic-nix-cache-action@908b263ff629f4cc17666315b7fd3ec127c6244d # main + + - name: Release + run: nix develop --command just rs release + env: + GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }} + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} diff --git a/.github/workflows/release-swift.yml b/.github/workflows/release-swift.yml new file mode 100644 index 0000000000..a0ede8712f --- /dev/null +++ b/.github/workflows/release-swift.yml @@ -0,0 +1,302 @@ +name: Release Swift + +on: + push: + tags: + - "moq-ffi-v*" + pull_request: + paths: + - ".github/workflows/release-swift.yml" + - ".github/scripts/release.sh" + - "swift/Package.swift.template" + - "swift/scripts/package.sh" + - "swift/scripts/publish.sh" + - "swift/scripts/verify.sh" + - "rs/moq-ffi/build.sh" + +permissions: + contents: read + +concurrency: + group: release-swift + cancel-in-progress: false + +jobs: + parse-version: + name: Parse version + runs-on: ubuntu-latest + outputs: + version: ${{ steps.parse.outputs.version }} + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Parse version + id: parse + env: + EVENT_NAME: ${{ github.event_name }} + run: | + if [[ "$EVENT_NAME" == "pull_request" ]]; then + CARGO_VERSION=$(grep '^version' rs/moq-ffi/Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/') + echo "version=$CARGO_VERSION" >> "$GITHUB_OUTPUT" + echo "Using version from Cargo.toml (PR dry-run): $CARGO_VERSION" + else + .github/scripts/release.sh parse-version moq-ffi + fi + + build: + name: Build moq-ffi (${{ matrix.target }}) + needs: [parse-version] + runs-on: macos-latest + + strategy: + fail-fast: false + matrix: + target: + - aarch64-apple-ios + - aarch64-apple-ios-sim + # x86_64-apple-ios is the Intel iOS simulator slice (Apple never + # shipped Intel iOS devices), still needed for Xcode users on + # Intel Macs running the simulator. + - x86_64-apple-ios + - universal-apple-darwin + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Install Rust + uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable + with: + targets: ${{ matrix.target == 'universal-apple-darwin' && 'x86_64-apple-darwin,aarch64-apple-darwin' || matrix.target }} + + - name: Rust cache + uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 + + - name: Build + shell: bash + env: + BUILD_TARGET: ${{ matrix.target }} + BUILD_VERSION: ${{ needs.parse-version.outputs.version }} + # Set iOS deployment target to avoid ___chkstk_darwin linker errors. + IPHONEOS_DEPLOYMENT_TARGET: ${{ contains(matrix.target, 'apple-ios') && '16.0' || '' }} + run: | + ./rs/moq-ffi/build.sh \ + --target "$BUILD_TARGET" \ + --version "$BUILD_VERSION" \ + --output dist + + - name: Upload lib + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: swift-lib-${{ matrix.target }} + path: dist/moq-ffi-${{ needs.parse-version.outputs.version }}-${{ matrix.target }}/lib/ + + bindings: + name: Generate bindings + needs: [parse-version] + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Install Rust + uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable + + - name: Rust cache + uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 + + - name: Generate bindings + env: + BUILD_VERSION: ${{ needs.parse-version.outputs.version }} + run: | + ./rs/moq-ffi/build.sh \ + --bindings-only \ + --version "$BUILD_VERSION" \ + --output dist + + - name: Upload bindings + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: swift-bindings + path: dist/bindings/swift/ + + package: + name: Package + needs: [parse-version, build, bindings] + runs-on: macos-latest + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Download per-target libs + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + path: libs-raw + pattern: swift-lib-* + + - name: Flatten lib layout + run: | + mkdir -p libs + for dir in libs-raw/swift-lib-*; do + target="${dir#libs-raw/swift-lib-}" + mv "$dir" "libs/$target" + done + ls -la libs + + - name: Download bindings + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + name: swift-bindings + path: bindings + + - name: Package + env: + BUILD_VERSION: ${{ needs.parse-version.outputs.version }} + run: | + ./swift/scripts/package.sh \ + --version "$BUILD_VERSION" \ + --lib-dir libs \ + --bindings-dir bindings \ + --output release-out + + - name: Upload Swift package + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: swift-package + path: release-out/* + + release: + # Attach MoqFFI.xcframework.zip (and the staged Swift package + # tarball) to the moq-ffi-v* GitHub release. The mirror's + # Package.swift binaryTarget URL points at this asset, so it must + # exist before any consumer resolves the SPM tag. + name: Attach assets to GitHub release + needs: [package, parse-version] + runs-on: ubuntu-latest + if: github.event_name == 'push' + permissions: + contents: write + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + fetch-depth: 0 + # No git operations here use the stored credential. gh CLI + # below picks up GH_TOKEN directly, so don't persist a + # contents-write token in .git/config. + persist-credentials: false + + - name: Find previous tag + id: prev_tag + run: .github/scripts/release.sh prev-tag moq-ffi + + - name: Download package + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + name: swift-package + path: artifacts + + - name: Create or update release + env: + GH_TOKEN: ${{ github.token }} + RELEASE_TAG: ${{ github.ref_name }} + RELEASE_TITLE: "moq-ffi v${{ needs.parse-version.outputs.version }}" + RELEASE_PREV_TAG: ${{ steps.prev_tag.outputs.tag }} + run: .github/scripts/release.sh create artifacts + + verify: + # Gate the mirror push on actually being able to resolve the staged + # package against the live release asset. Catches manifests that + # look syntactically fine but SPM cannot resolve (e.g. a path-based + # binaryTarget slipping in where a URL+checksum is expected). + name: Verify staged package resolves + needs: [release, parse-version] + runs-on: macos-latest + if: github.event_name == 'push' + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Download staged package + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + name: swift-package + path: artifacts + + - name: Resolve and build smoke consumer + env: + BUILD_VERSION: ${{ needs.parse-version.outputs.version }} + run: | + ./swift/scripts/verify.sh --tarball "artifacts/moq-ffi-${BUILD_VERSION}-swift.tar.gz" + + publish: + name: Publish to Swift Package mirror + needs: [verify, parse-version] + runs-on: ubuntu-latest + if: github.event_name == 'push' + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Generate moq-bot token + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3 + id: token + with: + app-id: ${{ secrets.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + owner: moq-dev + repositories: moq-swift + # Narrow the minted token to only what publish.sh needs, + # rather than inheriting the full App installation scope. + permission-contents: write + + - name: Download package + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + name: swift-package + path: swift-out + + - name: Publish to moq-dev/moq-swift mirror + env: + BUILD_VERSION: ${{ needs.parse-version.outputs.version }} + # Token is minted fresh per run, expires in 1 hour, never at rest. + SWIFT_MIRROR_TOKEN: ${{ steps.token.outputs.token }} + # Use the moq-bot identity for the commit author so the + # mirror's git log reflects who actually pushed. + GIT_AUTHOR_NAME: moq-bot + GIT_AUTHOR_EMAIL: moq-bot[bot]@users.noreply.github.com + run: ./swift/scripts/publish.sh + + publish-dry-run: + name: Publish dry-run + needs: [package, parse-version] + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Download package + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + name: swift-package + path: swift-out + + - name: Dry-run publish to mirror + env: + BUILD_VERSION: ${{ needs.parse-version.outputs.version }} + run: ./swift/scripts/publish.sh --dry-run diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index a6aef6223d..0000000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,52 +0,0 @@ -name: Release - -permissions: - pull-requests: write - contents: write - -# Only one release job can run at a time. -concurrency: - group: release - cancel-in-progress: true - -on: - push: - branches: - - main - -jobs: - release: - name: Plz - - runs-on: ubuntu-latest - if: ${{ github.repository_owner == 'moq-dev' }} - - steps: - # Generating a GitHub token, so that PRs and tags created by - # the release-plz-action can trigger actions workflows. - - name: Generate GitHub token - uses: actions/create-github-app-token@v2 - id: generate-token - with: - # GitHub App ID secret name - app-id: ${{ secrets.APP_ID }} - # GitHub App private key secret name - private-key: ${{ secrets.APP_PRIVATE_KEY }} - - # Checkout the repository - - name: Checkout repository - uses: actions/checkout@v6 - with: - fetch-depth: 0 - token: ${{ steps.generate-token.outputs.token }} - - # Instal Rust - - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable - - # Run release-plz to create PRs and releases - - name: Release-plz - uses: MarcoIeni/release-plz-action@v0.5 - env: - GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }} - CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} diff --git a/.github/workflows/rpm-repo.yml b/.github/workflows/rpm-repo.yml new file mode 100644 index 0000000000..f4d0dedd05 --- /dev/null +++ b/.github/workflows/rpm-repo.yml @@ -0,0 +1,60 @@ +name: rpm-repo + +# Mirrors .rpm artifacts attached to a release into the rpm.moq.dev repo. +# Invoked via workflow_dispatch from each per-binary release workflow's +# final job (gh workflow run rpm-repo.yml -f tag=...), or manually. +# +# Note: we do NOT trigger on release:published because releases created +# with the default GITHUB_TOKEN don't cascade to other workflows. The +# per-binary workflows call us explicitly instead. + +on: + workflow_dispatch: + inputs: + tag: + description: "Release tag to ingest (e.g. moq-relay-v1.2.3)" + required: true + +permissions: + contents: read + +concurrency: + group: rpm-repo + cancel-in-progress: false + +jobs: + publish: + name: Publish to rpm.moq.dev + runs-on: ubuntu-22.04 + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Set up packaging tools + uses: ./.github/actions/setup-packaging + + - name: Download .rpm assets from release + shell: bash + env: + GH_TOKEN: ${{ github.token }} + TAG: ${{ inputs.tag }} + run: | + mkdir -p artifacts + gh release download "$TAG" \ + --repo "${{ github.repository }}" \ + --dir artifacts \ + --pattern "*.rpm" + ls -la artifacts/ + + - name: Publish to R2 + shell: bash + env: + ARTIFACTS_DIR: artifacts + R2_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }} + R2_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }} + R2_ACCOUNT_ID: ${{ secrets.R2_ACCOUNT_ID }} + SIGNING_KEY: ${{ secrets.SIGNING_KEY }} + SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }} + run: ./infra/rpm/publish.sh diff --git a/.github/workflows/update-flake.yml b/.github/workflows/update-flake.yml index 285cb362d8..561963c82f 100644 --- a/.github/workflows/update-flake.yml +++ b/.github/workflows/update-flake.yml @@ -16,13 +16,15 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - name: Install Nix - uses: DeterminateSystems/nix-installer-action@main + uses: DeterminateSystems/nix-installer-action@00199f951aeb9404028a6e4b95ad42546f73296a # main + with: + determinate: false - name: Update flake.lock - uses: DeterminateSystems/update-flake-lock@main + uses: DeterminateSystems/update-flake-lock@5ba4a20ae344a5edd7b97ed3002219974f4d20d7 # main with: pr-title: "Update flake.lock" pr-labels: | diff --git a/.gitignore b/.gitignore index 6b7eb49e3c..5b4bdd9adb 100644 --- a/.gitignore +++ b/.gitignore @@ -30,7 +30,22 @@ node_modules *.m3u8 *.m4s -# We're using bun (and sometimes deno) +# Except these test fixtures, which are committed. +!rs/moq-mux/src/container/fmp4/test_data/*.mp4 + +# Cloudflare Wrangler +.wrangler/ + +# We're using bun package-lock.json yarn.lock pnpm-lock.yaml + +# Python +__pycache__/ +*.pyc +.venv/ + +# maturin develop drops uniffi bindings + cdylib here during editable +# installs of the py/moq-ffi package. +/py/moq-ffi/moq_ffi/_uniffi/ diff --git a/.remarkignore b/.remarkignore new file mode 100644 index 0000000000..c4a7d97cb1 --- /dev/null +++ b/.remarkignore @@ -0,0 +1,8 @@ +node_modules/ +target/ +dist/ +out/ +pkg/ +.direnv/ +.terraform/ +**/CHANGELOG.md diff --git a/.remarkrc.mjs b/.remarkrc.mjs new file mode 100644 index 0000000000..29be569e21 --- /dev/null +++ b/.remarkrc.mjs @@ -0,0 +1,19 @@ +export default { + plugins: [ + "remark-frontmatter", + "remark-preset-lint-consistent", + "remark-preset-lint-recommended", + ["remark-lint-list-item-indent", "one"], + ["remark-lint-maximum-line-length", false], + ["remark-lint-no-duplicate-headings", false], + ["remark-lint-no-undefined-references", false], + ], + settings: { + bullet: "-", + emphasis: "*", + strong: "*", + listItemIndent: "one", + rule: "-", + tightDefinitions: true, + }, +}; diff --git a/.taplo.toml b/.taplo.toml new file mode 100644 index 0000000000..2d69dedde8 --- /dev/null +++ b/.taplo.toml @@ -0,0 +1,9 @@ +# Skip vendored / build trees so `taplo format` doesn't recurse into them. +exclude = ["**/node_modules/**", "**/target/**", "**/dist/**", "**/.venv/**"] + +# Match the existing repo style (4-space indent on Cargo.toml, lines up +# to ~120 chars) so the initial format pass stays minimal. +[formatting] +indent_string = " " +column_width = 150 +align_comments = false diff --git a/.vscode/settings.json b/.vscode/settings.json index 48fb6b1432..9b4563f0bc 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,5 @@ { "css.lint.unknownAtRules": "ignore", - "biome.lsp.bin": "./node_modules/.bin/biome" + "biome.lsp.bin": "./node_modules/.bin/biome", + "cmake.sourceDirectory": "./rs/libmoq" } diff --git a/AGENTS.md b/AGENTS.md new file mode 120000 index 0000000000..681311eb9c --- /dev/null +++ b/AGENTS.md @@ -0,0 +1 @@ +CLAUDE.md \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md index b3c3358d84..a3124624e9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,6 +1,6 @@ # CLAUDE.md -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. +This file provides guidance for AI coding agents when working with code in this repository. ## Project Overview @@ -15,63 +15,207 @@ just fix # Auto-fix linting issues just build # Build all packages ``` +If `just` is unavailable, use `cargo` or `bun` directly. + ## Architecture The project contains multiple layers of protocols: 1. **quic** - Does all the networking. 2. **web-transport** - A small layer on top of QUIC/HTTP3 for browser support. Provided by the browser or the `web-transport` crates. -3. **moq-lite** - A generic pub/sub protocol on top of `web-transport` implemented by CDNs, splitting content into: - - broadcast: a collection of tracks produced by a publisher - - track: a live stream of groups within a broadcast. - - group: a live stream of frames within a track, each delivered independently over a QUIC stream. - - frame: a sized payload of bytes. -4. **hang** - Media-specific encoding/decoding on top of `moq-lite`. Contains: - - catalog: a JSON track containing a description of other tracks and their properties (for WebCodecs). - - container: each frame consists of a timestamp and codec bitstream -5. **application** - Users building on top of `moq-lite` or `hang` +3. **moq-net** - The networking layer on top of `web-transport`, implemented by CDNs. At session setup it negotiates one of two wire protocols: the simplified `moq-lite` protocol (the layer name) or the full IETF `moq-transport` protocol. Content splits into: + - broadcast: a collection of tracks produced by a publisher + - track: a live stream of groups within a broadcast. + - group: a live stream of frames within a track, each delivered independently over a QUIC stream. + - frame: a sized payload of bytes. +4. **hang** - Media-specific encoding/decoding on top of `moq-net`. Contains: + - catalog: a JSON track containing a description of other tracks and their properties (for WebCodecs). + - container: each frame consists of a timestamp and codec bitstream + - watch/publish: dedicated packages for subscribing/publishing with optional UI overlays +5. **moq-audio** - Native Opus encode/decode for raw PCM (more codecs to come). Used by `moq-ffi`/`libmoq` so native callers don't have to bring their own codec. +6. **application** - Users building on top of `moq-net` or `hang` Key architectural rule: The CDN/relay does not know anything about media. Anything in the `moq` layer should be generic, using rules on the wire on how to deliver content. - ## Project Structure ``` -/rs/ # Rust crates - moq/ # Core protocol (published as moq-lite) - moq-relay/ # Clusterable relay server - moq-token/ # JWT authentication - hang/ # Media encoding/streaming - hang-cli/ # CLI tool for media operations (binary is named `hang`) - -/js/ # TypeScript/JavaScript packages - moq/ # Core protocol for browsers (published as @moq/lite) - hang/ # Media layer with Web Components (published as @moq/hang) - hang-demo/ # Demo applications +/rs/ # Rust crates + moq-net/ # Core networking layer (published as moq-net; negotiates moq-lite or moq-transport) + moq-native/ # QUIC/WebTransport connection helpers for native apps; clock example lives in examples/clock.rs + moq-relay/ # Clusterable relay server (binary: moq-relay) + moq-token/ # JWT authentication library + moq-token-cli/ # JWT token CLI tool (binary: moq-token-cli) + moq-cli/ # CLI tool for media operations (binary: moq) + moq-mux/ # Media muxers/demuxers (fMP4, CMAF, HLS) + moq-audio/ # Native PCM ↔ Opus encode/decode on top of moq-mux + hang/ # Media encoding/streaming (catalog/container format) + libmoq/ # C bindings (staticlib) + moq-ffi/ # UniFFI bindings for Python/Swift/Kotlin (cdylib + staticlib) + moq-boy/ # MoQ Boy emulator publisher (binary: moq-boy) + moq-gst/ # GStreamer plugin (moqsink/moqsrc elements) + +/js/ # TypeScript/JavaScript packages + net/ # Core networking layer for browsers (published as @moq/net) + signals/ # Reactive signals library (published as @moq/signals) + token/ # JWT token generation (published as @moq/token) + clock/ # Clock example (published as @moq/clock) + hang/ # Core media layer: catalog, container, support (published as @moq/hang) + watch/ # Watch/subscribe to streams + UI (published as @moq/watch) + publish/ # Publish media to streams + UI (published as @moq/publish) + moq-boy/ # MoQ Boy web viewer (published as @moq/boy) + +/py/ # Python packages (uv workspace) + moq-ffi/ # Maturin project: rs/moq-ffi cdylib + uniffi bindings. + # Distribution `moq-ffi` (PyPI); import `moq_ffi`. One + # wheel covers every crate exposed via moq-ffi because + # uniffi-linked libraries can't be split across separate + # wheels. Version tracks rs/moq-ffi (release-py-ffi.yml + # fires on moq-ffi-v* tags). Most callers want `moq-rs`. + moq-rs/ # Pure-python ergonomic wrapper. Distribution `moq-rs` + # (PyPI, since `moq` is taken); import `moq`. Depends on + # moq-ffi via a compatible-release pin (~=0.2.x) so it + # floats to the latest moq-ffi patch. Versioned + # independently: bump py/moq-rs/pyproject.toml by hand; on + # merge to main release-py.yml publishes to PyPI if that + # version isn't already there (registry is the gate). + +/swift/ # Swift wrapper over rs/moq-ffi (SwiftPM) +/kt/ # Kotlin wrapper over rs/moq-ffi (Gradle, KMP) +/go/ # Go wrapper over rs/moq-ffi (uniffi-bindgen-go) + # swift/kt/go are in-tree source skeletons. + # CI mirrors them to moq-dev/moq-{swift,kotlin,go} + # on each moq-ffi-v* tag. + +/demo/ # Demos and test media + boy/ # MoQ Boy demo (ROM hosting, orchestration justfile) + relay/ # Relay server configs (relay.toml, root.toml, leaf*.toml) + pub/ # Media hosting (vid.moq.dev) + web/ # Web demo (watch/publish examples) + throttle/ # Network throttle script for testing + +/doc/ # Documentation site (VitePress, deployed via Cloudflare) ``` +## Dependencies + +- When adding new dependencies, always use the **newest stable version** available. + ## Development Tips 1. The project uses `just` as the task runner - check `justfile` for all available commands -2. For Rust development, the workspace is configured in the `rs/Cargo.toml` -3. For JS/TS development, bun workspaces are used with configuration in `js/package.json` +2. For Rust development, the workspace is configured in the root `Cargo.toml` +3. For JS/TS development, bun workspaces are used with configuration in the root `package.json` +4. Consult `doc/` for documentation and the [IETF datatracker](https://datatracker.ietf.org/doc/draft-lcurley-moq-lite/) for specification drafts when working on protocol-level code + +## Version Matching Convention + +When matching on `Version` enums, default to the **newest** draft behavior so future versions default forward. Explicitly list older versions: + +```rust +// CORRECT: future versions get draft-17+ behavior +match version { + Version::Draft14 | Version::Draft15 | Version::Draft16 => { /* old behavior */ } + _ => { /* newest/draft-17 behavior */ } +} +``` + +## Writing Style + +- **No em dashes (—)** in code, comments, doc comments, commit messages, or any prose. Use a period and start a new sentence, or use a comma/parenthesis if the clauses are tightly bound. + +## Rust Conventions + +- **Error handling**: Use `thiserror` with `#[from]` for library crates, `anyhow` for binaries. Always add `#[non_exhaustive]` to public `thiserror` enums. +- Use `anyhow::Context` (`.context("msg")`) instead of `.map_err(|_| anyhow::anyhow!("msg"))` for error conversion +- **Config flags + TOML merge**: For any `#[arg]` field on a TOML-loadable config, use `Option` (not bare `bool` / `String` / etc.). The TOML→CLI merge clobbers bare fields with their `Default` when the flag is absent, silently overwriting TOML values. See `rs/moq-relay/src/config.rs::tests` for the regression test; add one for any new flag. +- **Prefer `if let` / `let ... else` over an unwrapping `match`**: a `match` whose only job is to unwrap (`Ok(v) => v` / `Some(v) => v`) reads cleaner as `if let Some(v) = x { ... }` or `let Some(v) = x else { ... };`. Matching on an `Option`/`Result` just to bind the inner value is the tell. Keep `match` when both arms do real work or you need the `Err` / `None` payload. + +## Comment Conventions + +- Keep things brief and avoid comments if the code is self-explanatory. Reserve comments for the non-obvious WHY: a hidden constraint, a subtle invariant, a workaround for a specific bug, behavior that would surprise a reader. +- Write the way you'd say it out loud, not the way a doc generator would. One short line is almost always enough. Skip throat-clearing like "This function is responsible for...". +- Comments must reflect the **current** state of the code, not its history. Don't write "X no longer does Y" or "this used to cascade". Describe what the code does today, or delete the comment. Migration context belongs in commit messages and PR descriptions, where it ages with the change rather than rotting in the source. + +## AI Attribution + +LLM-authored prose visible to humans (PR descriptions, PR comments, review replies) should end with `(Written by Claude)` or similar. Do **not** tag code comments, doc comments, or `/doc` pages: source markers rot. Commit attribution lives in the `Co-Authored-By` trailer, not the commit body. + +## Refactor As You Go + +A function with 4+ args, or a call site passing the same 3+ values into multiple functions, is a struct waiting to happen. Make the change in the same PR rather than leaving a TODO. Same for repeated tuples returned across modules. ## Tooling - **TypeScript**: Always use `bun` for all package management and script execution (not npm, yarn, or pnpm) - **Common**: Use `just` for common development tasks - **Rust**: Use `cargo` for Rust-specific operations +- **Formatting/Linting**: Biome for JS/TS formatting and linting +- **UI**: Plain Web Components in `@moq/watch/ui` and `@moq/publish/ui`, built directly on `@moq/signals` +- **Builds**: Nix flake for reproducible builds (optional) +- **Local-first**: When work can live in a `just` recipe (invoked via `nix develop --command`) or as logic in a GitHub Actions workflow step, prefer the recipe. The same code then runs reproducibly on a developer machine and in CI, and is debuggable locally without pushing commits. Workflow YAML should mostly delegate to `just`; reach for plugins (`dorny/paths-filter`, custom actions, etc.) only when a recipe genuinely can't express the logic. +- **CI**: Prefer building release artifacts inside Nix (`nix build .#pkg`) over relying on runner-provided toolchains and `apt`/`brew` packages. Pinning the build environment in `flake.lock` makes artifacts deterministic and decouples them from drift in GitHub Actions runner images. Reach for the runner-native toolchain only when Nix doesn't fit (e.g. Windows runners). +- **JS async patterns**: Use `Effect.interval()`, `Effect.timer()`, and `Effect.event()` helpers from `@moq/signals` instead of raw `setInterval`, `setTimeout`, `addEventListener`. These handle cleanup automatically when the Effect is closed. ## Testing Approach - Run `just check` to execute all tests and linting. - Run `just fix` to automatically fix formating and easy things. - Rust tests are integrated within source files +- Async tests that sleep should call `tokio::time::pause()` at the start to simulate time instantly + +## Cross-Package Sync + +Changes in one area usually need matching updates elsewhere, including docs. If you skip a row, say why in the PR description. + +| Change in | Also update | +|---|---| +| `rs/moq-ffi` | `rs/libmoq`, `{py,swift,kt,go}/`, `doc/lib/{py,swift,kt,go,c}` | +| `rs/moq-net` wire/API | `js/net`, `doc/concept` | +| `rs/hang` catalog/container | `js/hang`, `doc/concept` | +| `rs/moq-token` | `js/token` | +| `rs/moq-relay` config/behavior | `doc/bin/relay/` | +| `rs/moq-cli` | `doc/bin/cli.md` | +| `rs/moq-gst` | `doc/bin/gstreamer.md` | +| `js/{watch,publish}` UI/API | `demo/web` if it consumes the API | + +## Branch Targeting + +Two long-lived branches: + +- **`main`**: stable. Bug fixes, small additive changes, docs, refactors that preserve public/wire behavior. +- **`dev`**: staging branch for disruptive work. Target it for: + - Wire-protocol changes (anything under `rs/moq-net`, including `moq-lite` / `moq-transport` framing or draft bumps). + - Breaking changes to public APIs in `rs/moq-ffi`, `rs/libmoq`, `rs/moq-net`, `rs/hang`, `js/net`, `js/hang`, or any of the language wrappers under `swift/`, `kt/`, `go/`, `py/`. + - Catalog/container format changes in `rs/hang` or `js/hang`. + - Major features that need time to settle before shipping. + +`dev` periodically merges into `main` (or vice versa) when the batch is ready to ship. When in doubt, target `main`; reviewers will redirect to `dev` if needed. CI (`pull_request:` workflows) runs on PRs against either branch, so no extra setup is needed when you switch the base. ## Workflow When making changes to the codebase: -1. Make your code changes -2. Run `just fix` to auto-format and fix linting issues -3. Run `just check` to verify everything passes -4. Commit and push changes + +1. Pick the base branch per [Branch Targeting](#branch-targeting) above +2. Make your code changes +3. Run `just fix` to auto-format and fix linting issues +4. Run `just check` to verify everything passes +5. Walk the Cross-Package Sync table; update paired packages and docs in the same PR +6. Add tests where they're easy to write +7. Commit and push changes + +## PR Reviews + +CodeRabbit reviews PRs automatically, but it has an hourly quota and runs out of org credits. If a PR shows a "Review limit reached" / "out of usage credits" message instead of an actual review, run the `/review` skill locally against the PR to get review feedback without waiting for the quota to refill. + +## PR Title and Description Maintenance + +When pushing additional commits to an existing PR, check whether the title and description still describe the change accurately. They often go stale during review iterations: a flag gets renamed, an API gets reshaped, an extra fix lands, etc. The PR description is what shows up in the squash-merge commit, so a stale title/body means a misleading entry in `git log` forever. + +Update them with `gh pr edit --title "..." --body "..."` whenever the scope shifts. Specifically watch for: + +- Flags, file names, or public APIs renamed in later commits but still referenced by their old name in the PR body. +- Bullet points in the "Summary" section that describe behavior the latest commits have changed or removed. +- The test-plan checklist getting out of date as new tests are added. + +When you edit a PR description you authored, keep the `(Written by Claude)` marker so reviewers still know the body wasn't human-authored. diff --git a/Cargo.lock b/Cargo.lock index 69ff062ba1..429bb8a5e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,13 +19,37 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aead" -version = "0.6.0-rc.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac8202ab55fcbf46ca829833f347a82a2a4ce0596f0304ac322c2d100030cd56" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ - "bytes", - "crypto-common 0.2.0-rc.4", - "inout", + "crypto-common 0.1.7", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures 0.2.17", +] + +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", ] [[package]] @@ -43,6 +67,12 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" +[[package]] +name = "android_log-sys" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85965b6739a430150bdd138e2374a98af0c3ee0d030b3bb7fc3bddff58d0102e" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -54,9 +84,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.21" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" dependencies = [ "anstyle", "anstyle-parse", @@ -69,15 +99,15 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] name = "anstyle-parse" -version = "0.2.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" dependencies = [ "utf8parse", ] @@ -104,18 +134,15 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.100" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" -dependencies = [ - "backtrace", -] +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" [[package]] name = "arc-swap" -version = "1.8.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d03449bb8ca2cc2ef70869af31463d1ae5ccc8fa3e334b307203fbf815207e" +checksum = "6a3a1fd6f75306b68087b831f025c712524bcb19aad54e557b1129cfa0a2b207" dependencies = [ "rustversion", ] @@ -132,11 +159,53 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +[[package]] +name = "askama" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4" +dependencies = [ + "askama_derive", + "itoa", + "percent-encoding", + "serde", + "serde_json", +] + +[[package]] +name = "askama_derive" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f" +dependencies = [ + "askama_parser", + "basic-toml", + "memchr", + "proc-macro2", + "quote", + "rustc-hash", + "serde", + "serde_derive", + "syn 2.0.117", +] + +[[package]] +name = "askama_parser" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358" +dependencies = [ + "memchr", + "serde", + "serde_derive", + "winnow 0.7.15", +] + [[package]] name = "asn1-rs" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56624a96882bb8c26d61312ae18cb45868e5a9992ea73c58e45c3101e56a1e60" +checksum = "b7f43a50ac4fdca5df8e885c21b835997f0a1cdee65494a6847694a98652d9d8" dependencies = [ "asn1-rs-derive", "asn1-rs-impl", @@ -144,7 +213,7 @@ dependencies = [ "nom", "num-traits", "rusticata-macros", - "thiserror 2.0.17", + "thiserror 2.0.18", "time", ] @@ -156,7 +225,7 @@ checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", "synstructure", ] @@ -168,45 +237,40 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] -name = "async-channel" -version = "2.5.0" +name = "assert-json-diff" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" +checksum = "47e4f2b81832e72834d7518d8487a0396a28cc408186a2e8854c0f98011faf12" dependencies = [ - "concurrent-queue", - "event-listener-strategy", - "futures-core", - "pin-project-lite", + "serde", + "serde_json", ] [[package]] -name = "async-compat" -version = "0.2.5" +name = "async-compression" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ba85bc55464dcbf728b56d97e119d673f4cf9062be330a9a26f3acf504a590" +checksum = "e79b3f8a79cccc2898f31920fc69f304859b3bd567490f75ebf51ae1c792a9ac" dependencies = [ - "futures-core", - "futures-io", - "once_cell", + "compression-codecs", + "compression-core", "pin-project-lite", "tokio", ] [[package]] -name = "async-compression" -version = "0.4.36" +name = "async-lock" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98ec5f6c2f8bc326c994cb9e241cc257ddaba9afa8555a43cffbb5dd86efaa37" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" dependencies = [ - "compression-codecs", - "compression-core", - "futures-core", + "event-listener", + "event-listener-strategy", "pin-project-lite", - "tokio", ] [[package]] @@ -217,7 +281,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -231,15 +295,6 @@ dependencies = [ "rustc_version", ] -[[package]] -name = "atomic-polyfill" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" -dependencies = [ - "critical-section", -] - [[package]] name = "atomic-waker" version = "1.1.2" @@ -260,15 +315,15 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "aws-lc-rs" -version = "1.15.2" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88aab2464f1f25453baa7a07c84c5b7684e274054ba06817f382357f77a288" +checksum = "5ec2f1fc3ec205783a5da9a7e6c1509cc69dedf09a1949e412c1e18469326d00" dependencies = [ "aws-lc-sys", "untrusted 0.7.1", @@ -277,9 +332,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.35.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45afffdee1e7c9126814751f88dddc747f41d91da16c9551a0f1e8a11e788a1" +checksum = "1a2f9779ce85b93ab6170dd940ad0169b5766ff848247aff13bb788b832fe3f4" dependencies = [ "cc", "cmake", @@ -289,9 +344,9 @@ dependencies = [ [[package]] name = "axum" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8" +checksum = "31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90" dependencies = [ "axum-core", "base64 0.22.1", @@ -313,10 +368,10 @@ dependencies = [ "serde_json", "serde_path_to_error", "serde_urlencoded", - "sha1 0.10.6", + "sha1", "sync_wrapper", "tokio", - "tokio-tungstenite 0.28.0", + "tokio-tungstenite 0.29.0", "tower", "tower-layer", "tower-service", @@ -351,7 +406,7 @@ dependencies = [ "arc-swap", "bytes", "either", - "fs-err", + "fs-err 3.3.0", "http", "http-body", "hyper", @@ -402,12 +457,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd307490d624467aa6f74b0eabb77633d1f758a7b25f12bceb0b22e08d9726f6" -[[package]] -name = "base32" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "022dfe9eb35f19ebbcb51e0b40a5ab759f46ad60cadf7297e0bd085afb50e076" - [[package]] name = "base64" version = "0.21.7" @@ -422,28 +471,73 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" -version = "1.8.2" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] +name = "basic-toml" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a" +dependencies = [ + "serde", +] + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bindgen" +version = "0.72.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "itertools 0.13.0", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex 1.3.0", + "syn 2.0.117", +] + +[[package]] +name = "bit-vec" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d809780667f4410e7c41b07f52439b94d2bdf8528eeedc287fa38d3b7f95d82" +checksum = "b71798fca2c1fe1086445a7258a4bc81e6e49dcd24c8d0dd9a1e57395b603f51" +dependencies = [ + "serde", +] [[package]] name = "bitflags" -version = "2.10.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" [[package]] name = "blake3" -version = "1.8.3" +version = "1.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2468ef7d57b3fb7e16b576e8377cdbde2320c60e1491e961d11da40fc4f02a2d" +checksum = "0aa83c34e62843d924f905e0f5c866eb1dd6545fc4d719e803d9ba6030371fce" dependencies = [ "arrayref", "arrayvec", "cc", "cfg-if", "constant_time_eq", - "cpufeatures", + "cpufeatures 0.3.0", ] [[package]] @@ -457,203 +551,398 @@ dependencies = [ [[package]] name = "block-buffer" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96eb4cdd6cf1b31d671e9efe75c5d1ec614776856cefbe109ca373554a6d514f" +checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" dependencies = [ "hybrid-array", - "zeroize", ] [[package]] -name = "buf-list" -version = "1.1.2" +name = "block2" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6b175f9cf8fffedd4c4b18bcfef092356e952b81f596e148f18e98280994593" +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" dependencies = [ - "bytes", + "objc2", ] [[package]] -name = "bumpalo" -version = "3.19.1" +name = "boring" +version = "4.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" +checksum = "3b0e3bc837369e9e662d3845c374ac3771b054d4bc2dee5457591198d16d684c" +dependencies = [ + "bitflags", + "boring-sys", + "foreign-types", + "libc", + "openssl-macros", +] [[package]] -name = "byteorder" -version = "1.5.0" +name = "boring-sys" +version = "4.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +checksum = "15aad385759d3da2737772aefb391332227bef7cb71fb85c106cadd9d1e63a98" +dependencies = [ + "bindgen", + "cmake", + "fs_extra", + "fslock", +] [[package]] -name = "bytes" -version = "1.11.0" +name = "boytacean" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" +checksum = "44a774c104e597a24d60ea21e7b949ad19e4aa7a39590dd1467f517066bbed42" dependencies = [ - "serde", + "boytacean-common", + "boytacean-encoding", + "boytacean-hashing", + "built", + "chrono", + "regex", ] [[package]] -name = "bytestring" -version = "1.5.0" +name = "boytacean-common" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d51a26a3d429ea3a419c67122eff610fbc96e59d75544f77d677f4e39c094940" + +[[package]] +name = "boytacean-encoding" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "113b4343b5f6617e7ad401ced8de3cc8b012e73a594347c307b90db3e9271289" +checksum = "e2bfc97163003de6037ab40296d0f5c2e50fe1b76c626e75cedd8f2017346b13" dependencies = [ - "bytes", + "boytacean-common", + "boytacean-hashing", ] [[package]] -name = "cbindgen" -version = "0.29.2" +name = "boytacean-hashing" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "befbfd072a8e81c02f8c507aefce431fe5e7d051f83d48a23ffc9b9fe5a11799" +checksum = "a4d1f207e18fc7559267427e86a9e45997d242ea6fa10ae41a617053eb5d9eb4" dependencies = [ - "clap", - "heck", - "indexmap 2.13.0", - "log", - "proc-macro2", - "quote", - "serde", - "serde_json", - "syn", - "tempfile", - "toml", + "boytacean-common", ] [[package]] -name = "cc" -version = "1.2.52" +name = "bs58" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd4932aefd12402b36c60956a4fe0035421f544799057659ff86f923657aada3" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" dependencies = [ - "find-msvc-tools", - "jobserver", - "libc", - "shlex", + "tinyvec", ] [[package]] -name = "cesu8" -version = "1.1.0" +name = "buffer-pool" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" +checksum = "a735dacb3d6e895d2537d263a01a09c3e48838e03818a8beed7a41249dffe09f" +dependencies = [ + "crossbeam", +] [[package]] -name = "cfg-if" -version = "1.0.4" +name = "built" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +checksum = "56ed6191a7e78c36abdb16ab65341eefd73d64d303fffccdbb00d51e4205967b" +dependencies = [ + "cargo-lock", +] [[package]] -name = "cfg_aliases" -version = "0.2.1" +name = "bumpalo" +version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" [[package]] -name = "chacha20" -version = "0.10.0-rc.2" +name = "byteorder" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bd162f2b8af3e0639d83f28a637e4e55657b7a74508dba5a9bf4da523d5c9e9" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", - "zeroize", -] +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] -name = "chrono" -version = "0.4.42" +name = "bytes" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" dependencies = [ - "iana-time-zone", - "js-sys", - "num-traits", "serde", - "wasm-bindgen", - "windows-link", ] [[package]] -name = "cipher" -version = "0.5.0-rc.1" +name = "bytestring" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e12a13eb01ded5d32ee9658d94f553a19e804204f2dc811df69ab4d9e0cb8c7" +checksum = "86566c496f2f47d9b8147a4c8b02ffdb69c919fe0c2b2e7195d22cbba0e635c9" dependencies = [ - "block-buffer 0.11.0", - "crypto-common 0.2.0-rc.4", - "inout", - "zeroize", + "bytes", ] [[package]] -name = "clap" -version = "4.5.54" +name = "camino" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394" +checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" dependencies = [ - "clap_builder", - "clap_derive", + "serde_core", ] [[package]] -name = "clap_builder" -version = "4.5.54" +name = "cargo-lock" +version = "10.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00" +checksum = "c06acb4f71407ba205a07cb453211e0e6a67b21904e47f6ba1f9589e38f2e454" dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", + "semver", + "serde", + "toml 0.8.23", + "url", ] [[package]] -name = "clap_derive" -version = "4.5.49" +name = "cargo-platform" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", + "serde", ] [[package]] -name = "clap_lex" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" - -[[package]] -name = "cmake" -version = "0.1.57" +name = "cargo_metadata" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" +checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" dependencies = [ - "cc", + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror 2.0.18", ] [[package]] -name = "cobs" -version = "0.3.0" +name = "cbindgen" +version = "0.29.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +checksum = "c95537b45400390270fae69ac098d057c8f5399001cde9d04f700c105ddfff2d" dependencies = [ - "thiserror 2.0.17", + "clap", + "heck", + "indexmap 2.14.0", + "log", + "proc-macro2", + "quote", + "serde", + "serde_json", + "syn 2.0.117", + "tempfile", + "toml 0.9.12+spec-1.1.0", ] [[package]] -name = "colorchoice" +name = "cc" +version = "1.2.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex 2.0.1", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cf-rustracing" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6565523d8145e63e0cf1b397a5f1bd4e90d5652a7dffb2de8cec460ff23ef6b1" +dependencies = [ + "backtrace", + "rand 0.10.1", + "tokio", + "trackable", +] + +[[package]] +name = "cf-rustracing-jaeger" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16c0e4d8cce27f6a6eaff58d2b66f063a18b8ed0d6ef0947ae7a263afa3b7c08" +dependencies = [ + "cf-rustracing", + "hostname", + "local-ip-address", + "percent-encoding", + "rand 0.10.1", + "thrift_codec", + "tokio", + "trackable", +] + +[[package]] +name = "cfg-expr" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb693542bcafa528e198be0ebd9d3632ca5b7c93dbe7237460e199910835997c" +dependencies = [ + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cfg-if" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chacha20" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "rand_core 0.10.1", +] + +[[package]] +name = "chrono" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common 0.1.7", + "inout", +] + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "clap" +version = "4.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "clap_lex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" + +[[package]] +name = "cmake" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" +dependencies = [ + "cc", +] + +[[package]] +name = "cmov" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" + +[[package]] +name = "cobs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +dependencies = [ + "thiserror 2.0.18", +] + +[[package]] +name = "colorchoice" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" [[package]] name = "combine" @@ -667,9 +956,9 @@ dependencies = [ [[package]] name = "compression-codecs" -version = "0.4.35" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0f7ac3e5b97fdce45e8922fb05cae2c37f7bbd63d30dd94821dacfd8f3f2bf2" +checksum = "ce2548391e9c1929c21bf6aa2680af86fe4c1b33e6cea9ac1cfeec0bd11218cf" dependencies = [ "compression-core", "flate2", @@ -678,9 +967,9 @@ dependencies = [ [[package]] name = "compression-core" -version = "0.4.31" +version = "0.4.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75984efb6ed102a0d42db99afb6c1948f0380d1d91808d5529916e6c08b49d8d" +checksum = "cc14f565cf027a105f7a44ccf9e5b424348421a1d8952a8fc9d499d313107789" [[package]] name = "concurrent-queue" @@ -731,6 +1020,18 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "const-hex" +version = "1.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33e2a781ebdf4467d1428dc4593067825fb646f6871475098d8577421af73558" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "proptest", + "serde_core", +] + [[package]] name = "const-oid" version = "0.9.6" @@ -803,6 +1104,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + [[package]] name = "crc32fast" version = "1.5.0" @@ -818,6 +1128,17 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" +[[package]] +name = "crossbeam" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" +dependencies = [ + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + [[package]] name = "crossbeam-channel" version = "0.5.15" @@ -836,6 +1157,15 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "crossbeam-queue" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -856,9 +1186,9 @@ dependencies = [ [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", "typenum", @@ -866,58 +1196,43 @@ dependencies = [ [[package]] name = "crypto-common" -version = "0.2.0-rc.4" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8235645834fbc6832939736ce2f2d08192652269e11010a6240f61b908a1c6" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" dependencies = [ "hybrid-array", - "rand_core 0.9.3", ] [[package]] -name = "crypto_box" -version = "0.10.0-pre.0" +name = "ctr" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bda4de3e070830cf3a27a394de135b6709aefcc54d1e16f2f029271254a6ed9" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" dependencies = [ - "aead", - "chacha20", - "crypto_secretbox", - "curve25519-dalek", - "salsa20", - "serdect", - "subtle", - "zeroize", + "cipher", ] [[package]] -name = "crypto_secretbox" -version = "0.2.0-pre.0" +name = "ctutils" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54532aae6546084a52cef855593daf9555945719eeeda9974150e0def854873e" +checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" dependencies = [ - "aead", - "chacha20", - "cipher", - "hybrid-array", - "poly1305", - "salsa20", - "subtle", - "zeroize", + "cmov", ] [[package]] name = "curve25519-dalek" -version = "5.0.0-pre.1" +version = "5.0.0-pre.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f9200d1d13637f15a6acb71e758f64624048d85b31a5fdbfd8eca1e2687d0b7" +checksum = "335f1947f241137a14106b6f5acc5918a5ede29c9d71d3f2cb1678d5075d9fc3" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "curve25519-dalek-derive", - "digest 0.11.0-rc.3", + "digest 0.11.3", "fiat-crypto", - "rand_core 0.9.3", + "rand_core 0.10.1", "rustc_version", "serde", "subtle", @@ -932,116 +1247,246 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", +] + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core 0.20.11", + "darling_macro 0.20.11", ] [[package]] name = "darling" -version = "0.21.3" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.23.0", + "darling_macro 0.23.0", ] [[package]] name = "darling_core" -version = "0.21.3" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", - "syn", + "syn 2.0.117", ] [[package]] -name = "darling_macro" -version = "0.21.3" +name = "darling_core" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" dependencies = [ - "darling_core", + "ident_case", + "proc-macro2", "quote", - "syn", + "strsim", + "syn 2.0.117", ] [[package]] -name = "data-encoding" -version = "2.9.0" +name = "darling_macro" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core 0.20.11", + "quote", + "syn 2.0.117", +] [[package]] -name = "der" -version = "0.7.10" +name = "darling_macro" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" dependencies = [ - "const-oid 0.9.6", - "pem-rfc7468 0.7.0", - "zeroize", + "darling_core 0.23.0", + "quote", + "syn 2.0.117", ] [[package]] -name = "der" -version = "0.8.0-rc.10" +name = "dashmap" +version = "6.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02c1d73e9668ea6b6a28172aa55f3ebec38507131ce179051c8033b5c6037653" +checksum = "e6361d5c062261c78a176addb82d4c821ae42bed6089de0e12603cd25de2059c" dependencies = [ - "const-oid 0.10.2", - "pem-rfc7468 1.0.0", - "zeroize", + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", ] [[package]] -name = "der-parser" -version = "10.0.0" +name = "data-encoding" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" -dependencies = [ - "asn1-rs", - "displaydoc", - "nom", - "num-bigint", - "num-traits", - "rusticata-macros", -] +checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8" [[package]] -name = "deranged" -version = "0.5.5" +name = "data-encoding-macro" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" +checksum = "3259c913752a86488b501ed8680446a5ed2d5aeac6e596cb23ba3800768ea32c" dependencies = [ - "powerfmt", - "serde_core", + "data-encoding", + "data-encoding-macro-internal", ] [[package]] -name = "derive_more" -version = "2.1.1" +name = "data-encoding-macro-internal" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +checksum = "ccc2776f0c61eca1ca32528f85548abd1a4be8fb53d1b21c013e4f18da1e7090" dependencies = [ - "derive_more-impl", + "data-encoding", + "syn 2.0.117", ] [[package]] -name = "derive_more-impl" -version = "2.1.1" +name = "datagram-socket" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +checksum = "8b2dc498ae9ce30da432498ea95297c7ed80d09a88ea4dce4ba6db2126eef60b" dependencies = [ - "convert_case", - "proc-macro2", - "quote", + "buffer-pool", + "futures-util", + "libc", + "smallvec", + "tokio", +] + +[[package]] +name = "deadpool" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0be2b1d1d6ec8d846f05e137292d0b89133caf95ef33695424c09568bdd39b1b" +dependencies = [ + "deadpool-runtime", + "lazy_static", + "num_cpus", + "tokio", +] + +[[package]] +name = "deadpool-runtime" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "092966b41edc516079bdf31ec78a2e0588d1d0c08f78b91d8307215928642b2b" + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid 0.9.6", + "pem-rfc7468 0.7.0", + "zeroize", +] + +[[package]] +name = "der" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fd89660b2dc699704064e59e9dba0147b903e85319429e131620d022be411b" +dependencies = [ + "const-oid 0.10.2", + "pem-rfc7468 1.0.0", + "zeroize", +] + +[[package]] +name = "der-parser" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "powerfmt", + "serde_core", +] + +[[package]] +name = "derive_builder" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" +dependencies = [ + "darling 0.20.11", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "derive_builder_macro" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" +dependencies = [ + "derive_builder_core", + "syn 2.0.117", +] + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", "rustc_version", - "syn", + "syn 2.0.117", "unicode-xid", ] @@ -1059,37 +1504,49 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.4", "const-oid 0.9.6", - "crypto-common 0.1.6", + "crypto-common 0.1.7", "subtle", ] [[package]] name = "digest" -version = "0.11.0-rc.3" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dac89f8a64533a9b0eaa73a68e424db0fb1fd6271c74cc0125336a05f090568d" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" dependencies = [ - "block-buffer 0.11.0", + "block-buffer 0.12.0", "const-oid 0.10.2", - "crypto-common 0.2.0-rc.4", + "crypto-common 0.2.2", +] + +[[package]] +name = "dispatch2" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" +dependencies = [ + "bitflags", + "block2", + "libc", + "objc2", ] [[package]] name = "displaydoc" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] name = "dlopen2" -version = "0.5.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b4f5f101177ff01b8ec4ecc81eead416a8aa42819a2869311b3420fa114ffa" +checksum = "5e2c5bd4158e66d1e215c49b837e11d62f3267b30c92f1d171c4d3105e3dc4d4" dependencies = [ "libc", "once_cell", @@ -1097,13 +1554,10 @@ dependencies = [ ] [[package]] -name = "document-features" -version = "0.2.12" +name = "dtoa" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" -dependencies = [ - "litrs", -] +checksum = "4c3cf4824e2d5f025c7b531afcb2325364084a16806f6d47fbc1f5fbd9960590" [[package]] name = "dunce" @@ -1117,6 +1571,35 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" +[[package]] +name = "ebml-iterable" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5173ac3752f08b526a6991509615e1a345b221ec3c58c7633433e8c9582312" +dependencies = [ + "ebml-iterable-specification", + "ebml-iterable-specification-derive", + "futures", +] + +[[package]] +name = "ebml-iterable-specification" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f56467af159a98735d44231f53eaa505e919e6003266f103b99649a93f106784" + +[[package]] +name = "ebml-iterable-specification-derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b066b81018300fdce40f71c4db355a102699324af96fad28f25ab1b5f87de066" +dependencies = [ + "ebml-iterable-specification", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "ecdsa" version = "0.16.9" @@ -1133,36 +1616,36 @@ dependencies = [ [[package]] name = "ed25519" -version = "3.0.0-rc.2" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "594435fe09e345ee388e4e8422072ff7dfeca8729389fbd997b3f5504c44cd47" +checksum = "29fcf32e6c73d1079f83ab4d782de2d81620346a5f38c6237a86a22f8368980a" dependencies = [ - "pkcs8 0.11.0-rc.8", - "serde", - "signature 3.0.0-rc.6", + "pkcs8 0.11.0", + "serdect", + "signature 3.0.0", ] [[package]] name = "ed25519-dalek" -version = "3.0.0-pre.1" +version = "3.0.0-pre.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad207ed88a133091f83224265eac21109930db09bedcad05d5252f2af2de20a1" +checksum = "20449acd54b660981ae5caa2bcb56d1fe7f25f2e37a38ec507400fab034d4bb6" dependencies = [ "curve25519-dalek", "ed25519", - "rand_core 0.9.3", + "rand_core 0.10.1", "serde", - "sha2 0.11.0-rc.2", - "signature 3.0.0-rc.6", + "sha2 0.11.0", + "signature 3.0.0", "subtle", "zeroize", ] [[package]] name = "either" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" [[package]] name = "elliptic-curve" @@ -1198,15 +1681,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" [[package]] -name = "enum-as-inner" -version = "0.6.1" +name = "enum-assoc" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" +checksum = "3ed8956bd5c1f0415200516e78ff07ec9e16415ade83c056c230d7b7ea0d55b7" dependencies = [ - "heck", "proc-macro2", "quote", - "syn", + "syn 2.0.117", +] + +[[package]] +name = "enum_dispatch" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa18ce2bc66555b3218614519ac839ddb759a7d6720732f979ef8d13be147ecd" +dependencies = [ + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] @@ -1215,6 +1709,26 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +[[package]] +name = "erased-serde" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c138974f9d5e7fe373eb04df7cae98833802ae4b11c24ac7039a21d5af4b26c" +dependencies = [ + "serde", +] + +[[package]] +name = "erased-serde" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2add8a07dd6a8d93ff627029c51de145e12686fbc36ecb298ac22e74cf02dec" +dependencies = [ + "serde", + "serde_core", + "typeid", +] + [[package]] name = "errno" version = "0.3.14" @@ -1248,21 +1762,21 @@ dependencies = [ [[package]] name = "fastbloom" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18c1ddb9231d8554c2d6bdf4cfaabf0c59251658c68b6c95cd52dd0c513a912a" +checksum = "4e7f34442dbe69c60fe8eaf58a8cafff81a1f278816d8ab4db255b3bef4ac3c4" dependencies = [ "getrandom 0.3.4", "libm", - "rand 0.9.2", + "rand 0.9.4", "siphasher", ] [[package]] name = "fastrand" -version = "2.3.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" [[package]] name = "ff" @@ -1274,6 +1788,31 @@ dependencies = [ "subtle", ] +[[package]] +name = "ffmpeg-next" +version = "8.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c4bd5ab1ac61f29c634df1175d350ded29cf74c3c6d4f7030431a5ae3c7d5d" +dependencies = [ + "bitflags", + "ffmpeg-sys-next", + "libc", +] + +[[package]] +name = "ffmpeg-sys-next" +version = "8.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a314bc0e022a33a99567ed4bd2576bd58ffd8fcff7891c29194cfecc26a62547" +dependencies = [ + "bindgen", + "cc", + "libc", + "num_cpus", + "pkg-config", + "vcpkg", +] + [[package]] name = "fiat-crypto" version = "0.3.0" @@ -1282,9 +1821,9 @@ checksum = "64cd1e32ddd350061ae6edb1b082d7c54915b5c672c389143b9a63403a109f24" [[package]] name = "find-msvc-tools" -version = "0.1.7" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f449e6c6c08c865631d4890cfacf252b3d396c9bcc83adb6623cdb02a8336c41" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] name = "fixedbitset" @@ -1294,20 +1833,38 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.1.5" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" dependencies = [ "crc32fast", "miniz_oxide", ] +[[package]] +name = "flume" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" +dependencies = [ + "futures-core", + "futures-sink", + "nanorand", + "spin 0.9.8", +] + [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "foldhash" version = "0.2.0" @@ -1315,90 +1872,197 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" [[package]] -name = "form_urlencoded" -version = "1.2.2" +name = "foreign-types" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" dependencies = [ - "percent-encoding", + "foreign-types-macros", + "foreign-types-shared", ] [[package]] -name = "fs-err" -version = "3.2.2" +name = "foreign-types-macros" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf68cef89750956493a66a10f512b9e58d9db21f2a573c079c0bdf1207a54a7" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ - "autocfg", - "tokio", + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] -name = "fs_extra" -version = "1.3.0" +name = "foreign-types-shared" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" [[package]] -name = "futures" -version = "0.3.31" +name = "form_urlencoded" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", + "percent-encoding", ] [[package]] -name = "futures-buffered" -version = "0.2.12" +name = "foundations" +version = "5.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8e0e1f38ec07ba4abbde21eed377082f17ccb988be9d988a5adbf4bafc118fd" +checksum = "f8842ece95ec0b71f0dbf9cb1da218ebdc6a40536bb97ea9c1974978058912b9" dependencies = [ - "cordyceps", - "diatomic-waker", - "futures-core", + "anyhow", + "cf-rustracing", + "cf-rustracing-jaeger", + "crossbeam-utils", + "erased-serde 0.4.10", + "foundations-macros", + "futures-util", + "governor", + "http", + "indexmap 2.14.0", + "libc", + "opentelemetry-proto", + "parking_lot", "pin-project-lite", - "spin 0.10.0", + "prometheus", + "prometheus-client", + "prometools", + "rand 0.10.1", + "serde", + "serde_json", + "serde_path_to_error", + "serde_with", + "serde_yaml", + "slab", + "slog", + "slog-async", + "slog-json", + "slog-term", + "thread_local", + "tokio", + "yaml-merge-keys", + "zeroize", ] [[package]] -name = "futures-channel" -version = "0.3.31" +name = "foundations-macros" +version = "5.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "ef32f15128fcc7706efb662b46b92bcad51c1e92cd691320864efde9e5e218c0" dependencies = [ - "futures-core", - "futures-sink", + "darling 0.23.0", + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-executor" -version = "0.3.31" +name = "fs-err" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41" dependencies = [ - "futures-core", - "futures-task", - "futures-util", + "autocfg", +] + +[[package]] +name = "fs-err" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73fde052dbfc920003cfd2c8e2c6e6d4cc7c1091538c3a24226cec0665ab08c0" +dependencies = [ + "autocfg", + "tokio", +] + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[package]] +name = "fsevent-sys" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" +dependencies = [ + "libc", +] + +[[package]] +name = "fslock" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04412b8935272e3a9bae6f48c7bfff74c2911f60525404edfdd28e49884c3bfb" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "futures" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-buffered" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4421cb78ee172b6b06080093479d3c50f058e7c81b7d577bbb8d118d551d4cd5" +dependencies = [ + "cordyceps", + "diatomic-waker", + "futures-core", + "pin-project-lite", + "spin 0.10.0", +] + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-executor" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", ] [[package]] name = "futures-io" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-lite" @@ -1415,32 +2079,38 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-timer" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "af43fadb8a98512d547e37b4e92e0ced13e205c061b87b4623eff01d918d6968" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-channel", "futures-core", @@ -1450,7 +2120,6 @@ dependencies = [ "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] @@ -1471,9 +2140,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.9" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -1482,9 +2151,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "js-sys", @@ -1502,17 +2171,118 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "r-efi", + "r-efi 5.3.0", "wasip2", "wasm-bindgen", ] +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi 6.0.0", + "rand_core 0.10.1", + "wasip2", + "wasip3", + "wasm-bindgen", +] + +[[package]] +name = "getset" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf0fc11e47561d47397154977bc219f4cf809b2974facc3ccb3b89e2436f912" +dependencies = [ + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", +] + [[package]] name = "gimli" version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" +[[package]] +name = "gio-sys" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521e93a7e56fc89e84aea9a52cfc9436816a4b363b030260b699950ff1336c83" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", + "windows-sys 0.59.0", +] + +[[package]] +name = "glib" +version = "0.20.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffc4b6e352d4716d84d7dde562dd9aee2a7d48beb872dd9ece7f2d1515b2d683" +dependencies = [ + "bitflags", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "futures-util", + "gio-sys", + "glib-macros", + "glib-sys", + "gobject-sys", + "libc", + "memchr", + "smallvec", +] + +[[package]] +name = "glib-macros" +version = "0.20.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8084af62f09475a3f529b1629c10c429d7600ee1398ae12dd3bf175d74e7145" +dependencies = [ + "heck", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "glib-sys" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ab79e1ed126803a8fb827e3de0e2ff95191912b8db65cee467edb56fc4cc215" +dependencies = [ + "libc", + "system-deps", +] + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + [[package]] name = "gloo-timers" version = "0.3.0" @@ -1525,6 +2295,51 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gobject-sys" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec9aca94bb73989e3cfdbf8f2e0f1f6da04db4d291c431f444838925c4c63eda" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "goblin" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b363a30c165f666402fe6a3024d3bec7ebc898f96a4a23bd1c99f8dbf3f4f47" +dependencies = [ + "log", + "plain", + "scroll", +] + +[[package]] +name = "governor" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9efcab3c1958580ff1f25a2a41be1668f7603d849bb63af523b208a3cc1223b8" +dependencies = [ + "cfg-if", + "dashmap", + "futures-sink", + "futures-timer", + "futures-util", + "getrandom 0.3.4", + "hashbrown 0.16.1", + "nonzero_ext", + "parking_lot", + "portable-atomic", + "quanta", + "rand 0.9.4", + "smallvec", + "spinning_top", + "web-time", +] + [[package]] name = "group" version = "0.13.0" @@ -1536,11 +2351,58 @@ dependencies = [ "subtle", ] +[[package]] +name = "gst-plugin-version-helper" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94668bc2592732b8c2b653668ae41211d45988fb61264888b9c2d545d4bd826d" +dependencies = [ + "chrono", + "toml_edit 0.25.12+spec-1.1.0", +] + +[[package]] +name = "gstreamer" +version = "0.23.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8757a87f3706560037a01a9f06a59fcc7bdb0864744dcf73546606e60c4316e1" +dependencies = [ + "cfg-if", + "futures-channel", + "futures-core", + "futures-util", + "glib", + "gstreamer-sys", + "itertools 0.14.0", + "libc", + "muldiv", + "num-integer", + "num-rational", + "once_cell", + "option-operations", + "paste", + "pin-project-lite", + "smallvec", + "thiserror 2.0.18", +] + +[[package]] +name = "gstreamer-sys" +version = "0.23.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "feea73b4d92dbf9c24a203c9cd0bcc740d584f6b5960d5faf359febf288919b2" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + [[package]] name = "h2" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" +checksum = "171fefbc92fe4a4de27e0698d6a5b392d6a0e333506bc49133760b3bcf948733" dependencies = [ "atomic-waker", "bytes", @@ -1548,7 +2410,7 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap 2.13.0", + "indexmap 2.14.0", "slab", "tokio", "tokio-util", @@ -1563,66 +2425,46 @@ checksum = "253b313319f7109de64e480ffb606f89475cd758bae82e096e00c5d95341d30e" [[package]] name = "hang" -version = "0.10.0" +version = "0.18.1" dependencies = [ "anyhow", - "buf-list", "bytes", "derive_more", - "futures", - "h264-parser", "hex", "lazy_static", - "m3u8-rs", - "moq-lite", + "moq-mux", "moq-native", - "mp4-atom", - "num_enum", + "moq-net", "regex", - "reqwest", - "scuffle-h265", "serde", "serde_json", "serde_with", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "tracing", "url", ] [[package]] -name = "hang-cli" -version = "0.7.3" -dependencies = [ - "anyhow", - "axum", - "axum-server", - "bytes", - "clap", - "hang", - "moq-native", - "rustls", - "sd-notify", - "tokio", - "tower-http", - "tracing", - "url", -] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] -name = "hash32" -version = "0.2.1" +name = "hashbrown" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" -dependencies = [ - "byteorder", -] +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "hashbrown" -version = "0.12.3" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash 0.1.5", +] [[package]] name = "hashbrown" @@ -1632,7 +2474,18 @@ checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" dependencies = [ "allocator-api2", "equivalent", - "foldhash", + "foldhash 0.2.0", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", ] [[package]] @@ -1648,26 +2501,18 @@ dependencies = [ "num-traits", ] -[[package]] -name = "heapless" -version = "0.7.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" -dependencies = [ - "atomic-polyfill", - "hash32", - "rustc_version", - "serde", - "spin 0.9.8", - "stable_deref_trait", -] - [[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + [[package]] name = "hex" version = "0.4.3" @@ -1675,28 +2520,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] -name = "hickory-proto" -version = "0.25.2" +name = "hickory-net" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8a6fe56c0038198998a6f217ca4e7ef3a5e51f46163bd6dd60b5c71ca6c6502" +checksum = "e2295ed2f9c31e471e1428a8f88a3f0e1f4b27c15049592138d1eebe9c35b183" dependencies = [ "async-trait", "bytes", "cfg-if", "data-encoding", - "enum-as-inner", "futures-channel", "futures-io", "futures-util", "h2", + "hickory-proto", "http", "idna", "ipnet", - "once_cell", - "rand 0.9.2", - "ring", + "jni 0.22.4", + "rand 0.10.1", "rustls", - "thiserror 2.0.17", + "thiserror 2.0.18", "tinyvec", "tokio", "tokio-rustls", @@ -1704,24 +2548,49 @@ dependencies = [ "url", ] +[[package]] +name = "hickory-proto" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bab31817bfb44672a252e97fe81cd0c18d1b2cf892108922f6818820df8c643" +dependencies = [ + "data-encoding", + "idna", + "ipnet", + "jni 0.22.4", + "once_cell", + "prefix-trie", + "rand 0.10.1", + "ring", + "thiserror 2.0.18", + "tinyvec", + "tracing", + "url", +] + [[package]] name = "hickory-resolver" -version = "0.25.2" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc62a9a99b0bfb44d2ab95a7208ac952d31060efc16241c87eaf36406fecf87a" +checksum = "f0d58d28879ceecde6607729660c2667a081ccdc082e082675042793960f178c" dependencies = [ "cfg-if", "futures-util", + "hickory-net", "hickory-proto", "ipconfig", + "ipnet", + "jni 0.22.4", "moka", + "ndk-context", "once_cell", "parking_lot", - "rand 0.9.2", + "rand 0.10.1", "resolv-conf", "rustls", "smallvec", - "thiserror 2.0.17", + "system-configuration", + "thiserror 2.0.18", "tokio", "tokio-rustls", "tracing", @@ -1745,11 +2614,22 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "hostname" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617aaa3557aef3810a6369d0a99fac8a080891b68bd9f9812a1eeda0c0730cbd" +dependencies = [ + "cfg-if", + "libc", + "windows-link", +] + [[package]] name = "http" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +checksum = "8be7462df143984c4598a256ef469b251d7d7f9e271135073e78fc535414f3d0" dependencies = [ "bytes", "itoa", @@ -1778,12 +2658,67 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "http-cache" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1437561a949a2168929d7559aecd2f0ecb18b9e676080396388cdc399ddb723a" +dependencies = [ + "async-trait", + "bincode", + "http", + "http-cache-semantics", + "httpdate", + "moka", + "serde", + "url", +] + +[[package]] +name = "http-cache-reqwest" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccca775a066b2a65da33611921e078ebdcfc27065c8bee96794703541101886" +dependencies = [ + "anyhow", + "async-trait", + "http", + "http-cache", + "http-cache-semantics", + "reqwest 0.12.28", + "reqwest-middleware", + "serde", + "url", +] + +[[package]] +name = "http-cache-semantics" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4311240f94cb6fe622337dc580b09ddd6ae4a891eb121dba20cf4f77ca4e7129" +dependencies = [ + "http", + "http-serde", + "serde", + "time", +] + [[package]] name = "http-range-header" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9171a2ea8a68358193d15dd5d70c1c10a2afc3e7e4c5bc92bc9f025cebd7359c" +[[package]] +name = "http-serde" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f056c8559e3757392c8d091e796416e4649d8e49e88b8d76df6c002f05027fd" +dependencies = [ + "http", + "serde", +] + [[package]] name = "httparse" version = "1.10.1" @@ -1814,19 +2749,18 @@ dependencies = [ [[package]] name = "hybrid-array" -version = "0.4.5" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f471e0a81b2f90ffc0cb2f951ae04da57de8baa46fa99112b062a5173a5088d0" +checksum = "9155a582abd142abc056962c29e3ce5ff2ad5469f4246b537ed42c5deba857da" dependencies = [ "typenum", - "zeroize", ] [[package]] name = "hyper" -version = "1.8.1" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498" dependencies = [ "atomic-waker", "bytes", @@ -1839,7 +2773,6 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "pin-utils", "smallvec", "tokio", "want", @@ -1847,19 +2780,18 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.7" +version = "0.27.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" dependencies = [ "http", "hyper", "hyper-util", "rustls", - "rustls-pki-types", "tokio", "tokio-rustls", "tower-service", - "webpki-roots 1.0.5", + "webpki-roots", ] [[package]] @@ -1877,14 +2809,13 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ "base64 0.22.1", "bytes", "futures-channel", - "futures-core", "futures-util", "http", "http-body", @@ -1893,7 +2824,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.1", + "socket2", "tokio", "tower-service", "tracing", @@ -1901,9 +2832,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.64" +version = "0.1.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1925,12 +2856,13 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" dependencies = [ "displaydoc", "potential_utf", + "utf8_iter", "yoke", "zerofrom", "zerovec", @@ -1938,9 +2870,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" dependencies = [ "displaydoc", "litemap", @@ -1951,9 +2883,9 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" dependencies = [ "icu_collections", "icu_normalizer_data", @@ -1965,15 +2897,15 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" [[package]] name = "icu_properties" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" dependencies = [ "icu_collections", "icu_locale_core", @@ -1985,15 +2917,15 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" [[package]] name = "icu_provider" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" dependencies = [ "displaydoc", "icu_locale_core", @@ -2004,12 +2936,24 @@ dependencies = [ "zerovec", ] +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + [[package]] name = "ident_case" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "identity-hash" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfdd7caa900436d8f13b2346fe10257e0c05c1f1f9e351f4f5d57c03bd5f45da" + [[package]] name = "idna" version = "1.1.0" @@ -2023,9 +2967,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" dependencies = [ "icu_normalizer", "icu_properties", @@ -2033,11 +2977,10 @@ dependencies = [ [[package]] name = "igd-next" -version = "0.16.2" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "516893339c97f6011282d5825ac94fc1c7aad5cad26bdc2d0cee068c0bf97f97" +checksum = "bac9a3c8278f43b4cd8463380f4a25653ac843e5b177e1d3eaf849cc9ba10d4d" dependencies = [ - "async-trait", "attohttpc", "bytes", "futures", @@ -2046,7 +2989,7 @@ dependencies = [ "hyper", "hyper-util", "log", - "rand 0.9.2", + "rand 0.10.1", "tokio", "url", "xmltree", @@ -2065,105 +3008,124 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.13.0" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", - "hashbrown 0.16.1", + "hashbrown 0.17.1", "serde", "serde_core", ] +[[package]] +name = "inotify" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd5b3eaf1a28b758ac0faa5a4254e8ab2705605496f1b1f3fbbc3988ad73d199" +dependencies = [ + "bitflags", + "inotify-sys", + "libc", +] + +[[package]] +name = "inotify-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", +] + [[package]] name = "inout" -version = "0.2.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" dependencies = [ - "hybrid-array", + "generic-array", ] [[package]] -name = "instant" -version = "0.1.13" +name = "intrusive-collections" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +checksum = "189d0897e4cbe8c75efedf3502c18c887b05046e59d28404d4d8e46cbc4d1e86" dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", + "memoffset", ] [[package]] name = "ipconfig" -version = "0.3.2" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" +checksum = "4d40460c0ce33d6ce4b0630ad68ff63d6661961c48b6dba35e5a4d81cfb48222" dependencies = [ - "socket2 0.5.10", + "socket2", "widestring", - "windows-sys 0.48.0", - "winreg", + "windows-registry", + "windows-result", + "windows-sys 0.61.2", ] [[package]] name = "ipnet" -version = "2.11.0" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" +dependencies = [ + "serde", +] [[package]] -name = "iri-string" -version = "0.7.10" +name = "ipnetwork" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" +checksum = "bf466541e9d546596ee94f9f69590f89473455f88372423e0008fc1a7daf100e" dependencies = [ - "memchr", "serde", ] [[package]] name = "iroh" -version = "0.95.1" +version = "1.0.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2374ba3cdaac152dc6ada92d971f7328e6408286faab3b7350842b2ebbed4789" +checksum = "b98e206e3d3f2642f5c08c413755fc0ac19b54ae1a656af88be03454ce3ed2e6" dependencies = [ - "aead", "backon", + "blake3", "bytes", "cfg_aliases", - "crypto_box", + "ctutils", "data-encoding", "derive_more", "ed25519-dalek", "futures-util", - "getrandom 0.3.4", + "getrandom 0.4.2", "hickory-resolver", "http", - "igd-next", - "instant", + "ipnet", "iroh-base", + "iroh-dns", "iroh-metrics", - "iroh-quinn", - "iroh-quinn-proto", - "iroh-quinn-udp", "iroh-relay", "n0-error", "n0-future", "n0-watcher", - "netdev", "netwatch", + "noq 1.0.0-rc.0", + "noq-proto 1.0.0-rc.0", + "noq-udp 1.0.0-rc.0", + "papaya", "pin-project", - "pkarr", - "pkcs8 0.11.0-rc.8", + "portable-atomic", "portmapper", - "rand 0.9.2", - "reqwest", + "rand 0.10.1", + "reqwest 0.13.4", + "rustc-hash", "rustls", "rustls-pki-types", - "rustls-platform-verifier 0.5.3", "rustls-webpki", "serde", "smallvec", @@ -2175,145 +3137,116 @@ dependencies = [ "tracing", "url", "wasm-bindgen-futures", - "webpki-roots 1.0.5", - "z32", + "webpki-roots", ] [[package]] name = "iroh-base" -version = "0.95.1" +version = "1.0.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25a8c5fb1cc65589f0d7ab44269a76f615a8c4458356952c9b0ef1c93ea45ff8" +checksum = "af93d67701c00c504982154569192ad384738c0450ba1196930314b955100552" dependencies = [ "curve25519-dalek", "data-encoding", + "data-encoding-macro", "derive_more", + "digest 0.11.3", "ed25519-dalek", + "getrandom 0.4.2", "n0-error", - "rand_core 0.9.3", + "rand 0.10.1", "serde", + "sha2 0.11.0", "url", "zeroize", "zeroize_derive", ] [[package]] -name = "iroh-metrics" -version = "0.37.0" +name = "iroh-dns" +version = "1.0.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79e3381da7c93c12d353230c74bba26131d1c8bf3a4d8af0fec041546454582e" +checksum = "de4112c91eb64094d77df9d3112606dcf7ff216421afccd2dc762fda5a7b2879" dependencies = [ - "iroh-metrics-derive", - "itoa", - "n0-error", - "postcard", - "ryu", - "serde", - "tracing", -] - -[[package]] -name = "iroh-metrics-derive" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4e12bd0763fd16062f5cc5e8db15dd52d26e75a8af4c7fb57ccee3589b344b8" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "iroh-quinn" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde160ebee7aabede6ae887460cd303c8b809054224815addf1469d54a6fcf7" -dependencies = [ - "bytes", + "arc-swap", "cfg_aliases", - "iroh-quinn-proto", - "iroh-quinn-udp", - "pin-project-lite", - "rustc-hash", + "derive_more", + "hickory-resolver", + "iroh-base", + "n0-error", + "n0-future", + "ndk-context", + "rand 0.10.1", + "reqwest 0.13.4", "rustls", - "socket2 0.5.10", - "thiserror 2.0.17", + "simple-dns", + "strum", "tokio", "tracing", - "web-time", + "url", ] [[package]] -name = "iroh-quinn-proto" -version = "0.13.0" +name = "iroh-metrics" +version = "1.0.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "929d5d8fa77d5c304d3ee7cae9aede31f13908bd049f9de8c7c0094ad6f7c535" +checksum = "d102597d0ee523f17fdb672c532395e634dbe945429284c811430d63bacc0d8a" dependencies = [ - "bytes", - "getrandom 0.2.16", - "rand 0.8.5", - "ring", - "rustc-hash", - "rustls", - "rustls-pki-types", - "rustls-platform-verifier 0.5.3", - "slab", - "thiserror 2.0.17", - "tinyvec", + "iroh-metrics-derive", + "itoa", + "n0-error", + "portable-atomic", + "ryu", + "serde", "tracing", - "web-time", ] [[package]] -name = "iroh-quinn-udp" -version = "0.5.7" +name = "iroh-metrics-derive" +version = "1.0.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c53afaa1049f7c83ea1331f5ebb9e6ebc5fdd69c468b7a22dd598b02c9bcc973" +checksum = "91c8e0c97f1dc787107f388433c349397c565572fe6406d600ff7bb7b7fe3b30" dependencies = [ - "cfg_aliases", - "libc", - "once_cell", - "socket2 0.5.10", - "tracing", - "windows-sys 0.59.0", + "heck", + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] name = "iroh-relay" -version = "0.95.1" +version = "1.0.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43fbdf2aeffa7d6ede1a31f6570866c2199b1cee96a0b563994623795d1bac2c" +checksum = "54f490405e42dd2ecf16be18a3587d2665401e94a498094f12322eaa6d5ebb2b" dependencies = [ "blake3", "bytes", "cfg_aliases", "data-encoding", "derive_more", - "getrandom 0.3.4", + "getrandom 0.4.2", "hickory-resolver", "http", "http-body-util", "hyper", "hyper-util", "iroh-base", + "iroh-dns", "iroh-metrics", - "iroh-quinn", - "iroh-quinn-proto", "lru", "n0-error", "n0-future", + "noq 1.0.0-rc.0", + "noq-proto 1.0.0-rc.0", "num_enum", "pin-project", - "pkarr", "postcard", - "rand 0.9.2", - "reqwest", + "rand 0.10.1", + "reqwest 0.13.4", "rustls", "rustls-pki-types", "serde", "serde_bytes", - "sha1 0.11.0-rc.2", "strum", "tokio", "tokio-rustls", @@ -2321,9 +3254,20 @@ dependencies = [ "tokio-websockets", "tracing", "url", - "webpki-roots 1.0.5", + "vergen-gitcl", + "webpki-roots", "ws_stream_wasm", - "z32", +] + +[[package]] +name = "is-terminal" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.61.2", ] [[package]] @@ -2332,6 +3276,15 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.14.0" @@ -2343,9 +3296,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "jni" @@ -2356,18 +3309,70 @@ dependencies = [ "cesu8", "cfg-if", "combine", - "jni-sys", + "jni-sys 0.3.1", "log", "thiserror 1.0.69", "walkdir", "windows-sys 0.45.0", ] +[[package]] +name = "jni" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" +dependencies = [ + "cfg-if", + "combine", + "jni-macros", + "jni-sys 0.4.1", + "log", + "simd_cesu8", + "thiserror 2.0.18", + "walkdir", + "windows-link", +] + +[[package]] +name = "jni-macros" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "simd_cesu8", + "syn 2.0.117", +] + [[package]] name = "jni-sys" -version = "0.3.0" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" +dependencies = [ + "jni-sys 0.4.1", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn 2.0.117", +] [[package]] name = "jobserver" @@ -2381,29 +3386,59 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.83" +version = "0.3.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" +checksum = "142bc4740e452c1e57ade0cbc129f139c9093e354346f0872ef985f4f5cf5f11" dependencies = [ + "cfg-if", + "futures-util", "once_cell", "wasm-bindgen", ] [[package]] name = "jsonwebtoken" -version = "10.2.0" +version = "10.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c76e1c7d7df3e34443b3621b459b066a7b79644f059fc8b2db7070c825fd417e" +checksum = "eba32bfb4ffdeaca3e34431072faf01745c9b26d25504aa7a6cf5684334fc4fc" dependencies = [ "aws-lc-rs", "base64 0.22.1", - "getrandom 0.2.16", + "getrandom 0.2.17", "js-sys", "pem", "serde", "serde_json", "signature 2.2.0", "simple_asn1", + "zeroize", +] + +[[package]] +name = "kio" +version = "0.3.0" +dependencies = [ + "smallvec", +] + +[[package]] +name = "kqueue" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "273c0752728918e0ac4976f2b275b6fefb9ecd400585dec929419f3844cd87b5" +dependencies = [ + "kqueue-sys", + "libc", +] + +[[package]] +name = "kqueue-sys" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07293a4e297ac234359b510362495713f75ea345d5307140414f20c69ffeb087" +dependencies = [ + "bitflags", + "libc", ] [[package]] @@ -2415,51 +3450,86 @@ dependencies = [ "spin 0.9.8", ] +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + [[package]] name = "libc" -version = "0.2.180" +version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] [[package]] name = "libm" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libmoq" -version = "0.2.4" +version = "0.3.1" dependencies = [ "anyhow", + "bytes", "cbindgen", "hang", - "moq-lite", + "moq-audio", + "moq-mux", "moq-native", - "slab", - "thiserror 2.0.17", + "moq-net", + "thiserror 2.0.18", "tokio", "tracing", "url", ] +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + [[package]] name = "linux-raw-sys" -version = "0.11.0" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "litemap" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" [[package]] -name = "litrs" -version = "1.0.0" +name = "local-ip-address" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" +checksum = "aa08fb2b1ec3ea84575e94b489d06d4ce0cbf052d12acd515838f50e3c3d63e3" +dependencies = [ + "libc", + "neli", + "windows-sys 0.61.2", +] [[package]] name = "lock_api" @@ -2472,9 +3542,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.29" +version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "616ec5685824bcc94416c6d4a7a446eea774a31efd7062c8480ba6fd06d7a6e5" [[package]] name = "loom" @@ -2491,11 +3561,11 @@ dependencies = [ [[package]] name = "lru" -version = "0.16.3" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1dc47f592c06f33f8e3aea9591776ec7c9f9e4124778ff8a3c3b87159f7e593" +checksum = "8a860605968fce16869fd239cf4237a82f3ac470723415db603b0e8b6c8d4fb9" dependencies = [ - "hashbrown 0.16.1", + "hashbrown 0.17.1", ] [[package]] @@ -2506,14 +3576,20 @@ checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" [[package]] name = "m3u8-rs" -version = "5.0.5" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c1d7ba86f7ea62f17f4310c55e93244619ddc7dadfc7e565de1967e4e41e6e7" +checksum = "f03cd3335fb5f2447755d45cda9c70f76013626a9db44374973791b0926a86c3" dependencies = [ "chrono", "nom", ] +[[package]] +name = "mac-addr" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3d25b0e0b648a86960ac23b7ad4abb9717601dec6f66c165f5b037f3f03065f" + [[package]] name = "matchers" version = "0.2.0" @@ -2531,9 +3607,18 @@ checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" [[package]] name = "memchr" -version = "2.7.6" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8" + +[[package]] +name = "memoffset" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] [[package]] name = "mime" @@ -2569,25 +3654,29 @@ dependencies = [ [[package]] name = "mio" -version = "1.1.1" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" dependencies = [ "libc", + "log", "wasi", "windows-sys 0.61.2", ] [[package]] name = "moka" -version = "0.12.12" +version = "0.12.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3dec6bd31b08944e08b58fd99373893a6c17054d6f3ea5006cc894f4f4eee2a" +checksum = "957228ad12042ee839f93c8f257b62b4c0ab5eaae1d4fa60de53b27c9d7c5046" dependencies = [ + "async-lock", "crossbeam-channel", "crossbeam-epoch", "crossbeam-utils", "equivalent", + "event-listener", + "futures-util", "parking_lot", "portable-atomic", "smallvec", @@ -2596,74 +3685,203 @@ dependencies = [ ] [[package]] -name = "moq-clock" -version = "0.10.2" +name = "moq-audio" +version = "0.0.1" +dependencies = [ + "bytes", + "hang", + "moq-mux", + "moq-net", + "rubato", + "thiserror 2.0.18", + "tokio", + "unsafe-libopus", +] + +[[package]] +name = "moq-boy" +version = "0.2.15" dependencies = [ "anyhow", - "chrono", + "boytacean", + "bytes", "clap", - "moq-lite", + "ffmpeg-next", + "hang", + "moq-mux", "moq-native", + "moq-net", + "serde", + "serde_json", "tokio", "tracing", "url", ] [[package]] -name = "moq-lite" -version = "0.11.0" +name = "moq-cli" +version = "0.7.28" +dependencies = [ + "anyhow", + "axum", + "axum-server", + "bytes", + "clap", + "hang", + "humantime", + "moq-mux", + "moq-native", + "rustls", + "sd-notify", + "tokio", + "tower-http", + "tracing", + "url", +] + +[[package]] +name = "moq-ffi" +version = "0.2.17" +dependencies = [ + "bytes", + "hang", + "moq-audio", + "moq-mux", + "moq-native", + "moq-net", + "pollster", + "thiserror 2.0.18", + "tokio", + "tracing", + "uniffi", + "url", +] + +[[package]] +name = "moq-gst" +version = "0.2.2" +dependencies = [ + "anyhow", + "bytes", + "gst-plugin-version-helper", + "gstreamer", + "hang", + "moq-mux", + "moq-native", + "moq-net", + "tokio", + "tracing", + "tracing-subscriber", + "url", +] + +[[package]] +name = "moq-loc" +version = "0.1.0" +dependencies = [ + "bytes", + "thiserror 2.0.18", +] + +[[package]] +name = "moq-msf" +version = "0.2.0" +dependencies = [ + "serde", + "serde_json", + "serde_with", +] + +[[package]] +name = "moq-mux" +version = "0.5.2" dependencies = [ - "async-channel", + "anyhow", + "base64 0.22.1", "bytes", "futures", - "hex", + "h264-parser", + "hang", + "kio", + "m3u8-rs", + "moq-loc", + "moq-msf", + "moq-net", + "mp4-atom", "num_enum", - "rand 0.9.2", - "serde", - "thiserror 2.0.17", + "reqwest 0.12.28", + "scuffle-av1", + "scuffle-h265", + "thiserror 2.0.18", "tokio", "tracing", - "web-async", - "web-transport-trait", + "url", + "webm-iterable", ] [[package]] name = "moq-native" -version = "0.11.0" +version = "0.16.1" dependencies = [ "anyhow", "bytes", + "chrono", "clap", "console-subscriber", "futures", "hex", "humantime", "humantime-serde", - "moq-lite", + "moq-net", "parking_lot", + "qmux", "quinn", - "rand 0.9.2", - "rcgen", - "reqwest", + "rand 0.9.4", + "rcgen 0.14.8", + "reqwest 0.12.28", "rustls", "rustls-native-certs", - "rustls-pemfile", "rustls-webpki", "serde", "serde_with", + "tikv-jemalloc-ctl", + "tikv-jemallocator", "time", "tokio", + "toml 0.9.12+spec-1.1.0", "tracing", + "tracing-android", "tracing-subscriber", + "tracing-test", "url", "web-transport-iroh", + "web-transport-noq", + "web-transport-proto", + "web-transport-quiche", "web-transport-quinn", - "web-transport-ws", +] + +[[package]] +name = "moq-net" +version = "0.1.8" +dependencies = [ + "bytes", + "futures", + "kio", + "num_enum", + "rand 0.9.4", + "serde", + "serde_json", + "thiserror 2.0.18", + "tokio", + "tracing", + "web-async", + "web-transport-trait", ] [[package]] name = "moq-relay" -version = "0.10.2" +version = "0.12.5" dependencies = [ "anyhow", "axum", @@ -2672,26 +3890,37 @@ dependencies = [ "clap", "futures", "http-body", - "moq-lite", + "http-cache-reqwest", + "jsonwebtoken", "moq-native", + "moq-net", "moq-token", + "notify", + "qmux", + "rcgen 0.13.2", + "reqwest 0.12.28", + "reqwest-middleware", "rustls", "sd-notify", "serde", + "serde_json", "serde_with", "tempfile", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", - "toml", + "tokio-rustls", + "toml 0.9.12+spec-1.1.0", "tower-http", + "tower-service", "tracing", "url", - "web-transport-ws", + "web-transport-trait", + "wiremock", ] [[package]] name = "moq-token" -version = "0.5.6" +version = "0.6.0" dependencies = [ "anyhow", "aws-lc-rs", @@ -2700,42 +3929,55 @@ dependencies = [ "jsonwebtoken", "p256", "p384", + "reqwest 0.12.28", "rsa", "serde", "serde_json", "serde_with", + "thiserror 2.0.18", + "tokio", ] [[package]] name = "moq-token-cli" -version = "0.5.7" +version = "0.5.28" dependencies = [ "anyhow", "clap", "moq-token", ] +[[package]] +name = "moq-video" +version = "0.0.2" + [[package]] name = "mp4-atom" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3af4894763f3d6e1eabd3d878853d88ad90add9bcff9165116fb84cbfb0207" +checksum = "6c6b338be0a8d66954dfb183f8469913c9c435d48885e801debde0953de74563" dependencies = [ "bytes", "derive_more", "num", - "paste", + "pastey", "serde", "thiserror 1.0.69", "tokio", "tracing", ] +[[package]] +name = "muldiv" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956787520e75e9bd233246045d19f42fb73242759cc57fba9611d940ae96d4b0" + [[package]] name = "n0-error" -version = "0.1.2" +version = "1.0.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d5969a2f40e9d9ed121a789c415f4114ac2b28e5731c080bdefee217d3b3fb" +checksum = "223e946a84aa91644507a6b7865cfebbb9a231ace499041c747ab0fd30408212" dependencies = [ "n0-error-macros", "spez", @@ -2743,13 +3985,13 @@ dependencies = [ [[package]] name = "n0-error-macros" -version = "0.1.2" +version = "1.0.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a6908df844696d9af91c7c3950d50e52d67df327d02a95367f95bbf177d6556" +checksum = "565305a21e6b3bf26640ad98f05a0fda12d3ab4315394566b52a7bddb8b34828" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -2775,30 +4017,81 @@ dependencies = [ [[package]] name = "n0-watcher" -version = "0.5.0" +version = "1.0.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38acf13c1ddafc60eb7316d52213467f8ccb70b6f02b65e7d97f7799b1f50be4" +checksum = "928d8039a66cce5efcfd35e88b32d3defc8eba630b3ac451522997f563956a52" dependencies = [ "derive_more", "n0-error", "n0-future", ] +[[package]] +name = "nanorand" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "neli" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22f9786d56d972959e1408b6a93be6af13b9c1392036c5c1fafa08a1b0c6ee87" +dependencies = [ + "bitflags", + "byteorder", + "derive_builder", + "getset", + "libc", + "log", + "neli-proc-macros", + "parking_lot", +] + +[[package]] +name = "neli-proc-macros" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05d8d08c6e98f20a62417478ebf7be8e1425ec9acecc6f63e22da633f6b71609" +dependencies = [ + "either", + "proc-macro2", + "quote", + "serde", + "syn 2.0.117", +] + [[package]] name = "netdev" -version = "0.38.2" +version = "0.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67ab878b4c90faf36dab10ea51d48c69ae9019bcca47c048a7c9b273d5d7a823" +checksum = "57bacaf873ee4eab5646f99b381b271ec75e716902a67cf962c0f328c5eb5bfb" dependencies = [ + "block2", + "dispatch2", "dlopen2", "ipnet", "libc", + "mac-addr", "netlink-packet-core", - "netlink-packet-route", + "netlink-packet-route 0.29.0", "netlink-sys", + "objc2-core-foundation", + "objc2-core-wlan", + "objc2-foundation", + "objc2-system-configuration", "once_cell", - "system-configuration", - "windows-sys 0.59.0", + "plist", + "windows-sys 0.61.2", ] [[package]] @@ -2812,9 +4105,21 @@ dependencies = [ [[package]] name = "netlink-packet-route" -version = "0.25.1" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9854ea6ad14e3f4698a7f03b65bce0833dd2d81d594a0e4a984170537146b6" +dependencies = [ + "bitflags", + "libc", + "log", + "netlink-packet-core", +] + +[[package]] +name = "netlink-packet-route" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ec2f5b6839be2a19d7fa5aab5bc444380f6311c2b693551cb80f45caaa7b5ef" +checksum = "be8919612f6028ab4eacbbfe1234a9a43e3722c6e0915e7ff519066991905092" dependencies = [ "bitflags", "libc", @@ -2833,17 +4138,17 @@ dependencies = [ "log", "netlink-packet-core", "netlink-sys", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] name = "netlink-sys" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16c903aa70590cb93691bf97a767c8d1d6122d2cc9070433deb3bbf36ce8bd23" +checksum = "cd6c30ed10fa69cc491d491b85cc971f6bdeb8e7367b7cde2ee6cc878d583fae" dependencies = [ "bytes", - "futures", + "futures-util", "libc", "log", "tokio", @@ -2851,15 +4156,14 @@ dependencies = [ [[package]] name = "netwatch" -version = "0.12.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26f2acd376ef48b6c326abf3ba23c449e0cb8aa5c2511d189dd8a8a3bfac889b" +checksum = "b5bfbba77b994ce69f1d40fc66fd8abbd23df62ce4aea61fbb34d638106a2549" dependencies = [ "atomic-waker", "bytes", "cfg_aliases", "derive_more", - "iroh-quinn-udp", "js-sys", "libc", "n0-error", @@ -2867,12 +4171,15 @@ dependencies = [ "n0-watcher", "netdev", "netlink-packet-core", - "netlink-packet-route", + "netlink-packet-route 0.30.0", "netlink-proto", "netlink-sys", + "noq-udp 1.0.0-rc.0", + "objc2-core-foundation", + "objc2-system-configuration", "pin-project-lite", "serde", - "socket2 0.6.1", + "socket2", "time", "tokio", "tokio-util", @@ -2883,6 +4190,19 @@ dependencies = [ "wmi", ] +[[package]] +name = "nix" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" +dependencies = [ + "bitflags", + "cfg-if", + "cfg_aliases", + "libc", + "memoffset", +] + [[package]] name = "nom" version = "7.1.3" @@ -2894,18 +4214,160 @@ dependencies = [ ] [[package]] -name = "ntimestamp" -version = "1.0.0" +name = "nonzero_ext" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50f94c405726d3e0095e89e72f75ce7f6587b94a8bd8dc8054b73f65c0fd68c" +checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21" + +[[package]] +name = "noq" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df966fb44ac763bc86da97fa6c811c54ae82ef656575949f93c6dae0c9f09bf" dependencies = [ - "base32", - "document-features", - "getrandom 0.2.16", - "httpdate", - "js-sys", - "once_cell", - "serde", + "bytes", + "cfg_aliases", + "noq-proto 0.16.0", + "noq-udp 0.9.0", + "pin-project-lite", + "rustc-hash", + "rustls", + "socket2", + "thiserror 2.0.18", + "tokio", + "tokio-stream", + "tracing", + "web-time", +] + +[[package]] +name = "noq" +version = "1.0.0-rc.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22739e0831e40f5ab7d6ac5317ed80bfe5fb3f44be57d23fa2eea8bff83fb303" +dependencies = [ + "bytes", + "cfg_aliases", + "derive_more", + "noq-proto 1.0.0-rc.0", + "noq-udp 1.0.0-rc.0", + "pin-project-lite", + "rustc-hash", + "rustls", + "socket2", + "thiserror 2.0.18", + "tokio", + "tokio-stream", + "tracing", + "web-time", +] + +[[package]] +name = "noq-proto" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c61b72abd670eebc05b5cf720e077b04a3ef3354bc7bc19f1c3524cb424db7b" +dependencies = [ + "aes-gcm", + "bytes", + "derive_more", + "enum-assoc", + "fastbloom", + "getrandom 0.3.4", + "identity-hash", + "lru-slab", + "rand 0.9.4", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "rustls-platform-verifier 0.6.2", + "slab", + "sorted-index-buffer", + "thiserror 2.0.18", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "noq-proto" +version = "1.0.0-rc.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cee32450cf726b223ac4154003c93cb52fbde159ab1240990e88945bf3ae35e" +dependencies = [ + "aes-gcm", + "aws-lc-rs", + "bytes", + "derive_more", + "enum-assoc", + "getrandom 0.4.2", + "identity-hash", + "lru-slab", + "rand 0.10.1", + "rand_pcg", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "sorted-index-buffer", + "thiserror 2.0.18", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "noq-udp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb9be4fedd6b98f3ba82ccd3506f4d0219fb723c3f97c67e12fe1494aa020e44" +dependencies = [ + "cfg_aliases", + "libc", + "socket2", + "tracing", + "windows-sys 0.61.2", +] + +[[package]] +name = "noq-udp" +version = "1.0.0-rc.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78633d1fe1bde91d12bcabb230ac9edb890857414c6d44f3212e0d309525b5ff" +dependencies = [ + "cfg_aliases", + "libc", + "socket2", + "tracing", + "windows-sys 0.61.2", +] + +[[package]] +name = "notify" +version = "8.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3" +dependencies = [ + "bitflags", + "fsevent-sys", + "inotify", + "kqueue", + "libc", + "log", + "mio", + "notify-types", + "walkdir", + "windows-sys 0.60.2", +] + +[[package]] +name = "notify-types" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42b8cfee0e339a0337359f3c88165702ac6e600dc01c0cc9579a92d62b08477a" +dependencies = [ + "bitflags", ] [[package]] @@ -2952,7 +4414,7 @@ dependencies = [ "num-integer", "num-iter", "num-traits", - "rand 0.8.5", + "rand 0.8.6", "smallvec", "zeroize", ] @@ -2968,9 +4430,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.1.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" [[package]] name = "num-integer" @@ -3013,11 +4475,21 @@ dependencies = [ "libm", ] +[[package]] +name = "num_cpus" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +dependencies = [ + "hermit-abi", + "libc", +] + [[package]] name = "num_enum" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" dependencies = [ "num_enum_derive", "rustversion", @@ -3025,23 +4497,122 @@ dependencies = [ [[package]] name = "num_enum_derive" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 2.0.117", +] + +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + +[[package]] +name = "nutype-enum" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1e13adea6de269faa0724df58f43f6fe2a81af7094f1dcb8b5b968eb2103cb3" +dependencies = [ + "scuffle-workspace-hack", +] + +[[package]] +name = "objc2" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" +dependencies = [ + "objc2-encode", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags", + "block2", + "dispatch2", + "libc", + "objc2", +] + +[[package]] +name = "objc2-core-wlan" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71e34919aba0d701380d911702455038a8a3587467fe0141d6a71501e7ffe48" +dependencies = [ + "bitflags", + "objc2", + "objc2-core-foundation", + "objc2-foundation", + "objc2-security", + "objc2-security-foundation", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" +dependencies = [ + "bitflags", + "block2", + "libc", + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-security" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe137109bd1e8b5a99390f77a7d8b2961dafc1a1c5db8f2e60329ad6d895a" +dependencies = [ + "bitflags", + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-security-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef76382e9cedd18123099f17638715cc3d81dba3637d4c0d39ab69df2ef345a5" +dependencies = [ + "objc2", + "objc2-foundation", ] [[package]] -name = "nutype-enum" -version = "0.1.5" +name = "objc2-system-configuration" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1e13adea6de269faa0724df58f43f6fe2a81af7094f1dcb8b5b968eb2103cb3" +checksum = "7216bd11cbda54ccabcab84d523dc93b858ec75ecfb3a7d89513fa22464da396" dependencies = [ - "scuffle-workspace-hack", + "bitflags", + "dispatch2", + "libc", + "objc2", + "objc2-core-foundation", + "objc2-security", ] [[package]] @@ -3053,6 +4624,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "octets" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8311fa8ab7a57759b4ff1f851a3048d9ef0effaa0130726426b742d26d8a88e7" + [[package]] name = "oid-registry" version = "0.8.1" @@ -3064,9 +4641,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.3" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" dependencies = [ "critical-section", "portable-atomic", @@ -3078,11 +4655,83 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "openssl-probe" -version = "0.2.0" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + +[[package]] +name = "opentelemetry" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b84bcd6ae87133e903af7ef497404dda70c60d0ea14895fc8a5e6722754fc2a0" +dependencies = [ + "futures-core", + "futures-sink", + "js-sys", + "pin-project-lite", + "thiserror 2.0.18", + "tracing", +] + +[[package]] +name = "opentelemetry-proto" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7175df06de5eaee9909d4805a3d07e28bb752c34cab57fa9cff549da596b30f" +dependencies = [ + "base64 0.22.1", + "const-hex", + "opentelemetry", + "opentelemetry_sdk", + "prost", + "serde", + "serde_json", + "tonic", + "tonic-prost", +] + +[[package]] +name = "opentelemetry_sdk" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f50d9b3dabb09ecd771ad0aa242ca6894994c130308ca3d7684634df8037391" +checksum = "e14ae4f5991976fd48df6d843de219ca6d31b01daaab2dad5af2badeded372bd" +dependencies = [ + "futures-channel", + "futures-executor", + "futures-util", + "opentelemetry", + "percent-encoding", + "rand 0.9.4", + "thiserror 2.0.18", +] + +[[package]] +name = "option-operations" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c26d27bb1aeab65138e4bf7666045169d1717febcc9ff870166be8348b223d0" +dependencies = [ + "paste", +] [[package]] name = "p256" @@ -3108,6 +4757,16 @@ dependencies = [ "sha2 0.10.9", ] +[[package]] +name = "papaya" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "997ee03cd38c01469a7046643714f0ad28880bcb9e6679ff0666e24817ca19b7" +dependencies = [ + "equivalent", + "seize", +] + [[package]] name = "parking" version = "2.2.1" @@ -3145,6 +4804,12 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pastey" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ee67f1008b1ba2321834326597b8e186293b049a023cdef258527550b9935b4" + [[package]] name = "pem" version = "3.0.6" @@ -3186,7 +4851,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.13.0", + "indexmap 2.14.0", ] [[package]] @@ -3201,66 +4866,29 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.10" +version = "1.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.10" +version = "1.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkarr" -version = "5.0.2" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d346b545765a0ef58b6a7e160e17ddaa7427f439b7b9a287df6c88c9e04bf2" -dependencies = [ - "async-compat", - "base32", - "bytes", - "cfg_aliases", - "document-features", - "dyn-clone", - "ed25519-dalek", - "futures-buffered", - "futures-lite", - "getrandom 0.3.4", - "log", - "lru", - "ntimestamp", - "reqwest", - "self_cell", - "serde", - "sha1_smol", - "simple-dns", - "thiserror 2.0.17", - "tokio", - "tracing", - "url", - "wasm-bindgen-futures", -] +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pkcs1" @@ -3285,52 +4913,87 @@ dependencies = [ [[package]] name = "pkcs8" -version = "0.11.0-rc.8" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "451913da69c775a56034ea8d9003d27ee8948e12443eae7c038ba100a4f21cb7" +dependencies = [ + "der 0.8.0", + "spki 0.8.0", +] + +[[package]] +name = "pkg-config" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" + +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + +[[package]] +name = "plist" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77089aec8290d0b7bb01b671b091095cf1937670725af4fd73d47249f03b12c0" +checksum = "092791278e026273c1b65bbdcfbba3a300f2994c896bd01ab01da613c29c46f1" dependencies = [ - "der 0.8.0-rc.10", - "spki 0.8.0-rc.4", + "base64 0.22.1", + "indexmap 2.14.0", + "quick-xml", + "serde", + "time", ] [[package]] -name = "poly1305" -version = "0.9.0-rc.2" +name = "pollster" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3" + +[[package]] +name = "polyval" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb78a635f75d76d856374961deecf61031c0b6f928c83dc9c0924ab6c019c298" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" dependencies = [ - "cpufeatures", + "cfg-if", + "cpufeatures 0.2.17", + "opaque-debug", "universal-hash", ] [[package]] name = "portable-atomic" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" +dependencies = [ + "serde", +] [[package]] name = "portmapper" -version = "0.12.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b575f975dcf03e258b0c7ab3f81497d7124f508884c37da66a7314aa2a8d467" +checksum = "aec2a8809e3f7dba624776bb223da9fed49c413c60b3bef21aadcb67a5e35944" dependencies = [ "base64 0.22.1", "bytes", "derive_more", - "futures-lite", - "futures-util", "hyper-util", "igd-next", "iroh-metrics", "libc", "n0-error", + "n0-future", "netwatch", "num_enum", - "rand 0.9.2", + "rand 0.10.1", "serde", "smallvec", - "socket2 0.6.1", + "socket2", "time", "tokio", "tokio-util", @@ -3340,111 +5003,327 @@ dependencies = [ ] [[package]] -name = "postcard" -version = "1.1.3" +name = "postcard" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" +dependencies = [ + "cobs", + "embedded-io 0.4.0", + "embedded-io 0.6.1", + "postcard-derive", + "serde", +] + +[[package]] +name = "postcard-derive" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0232bd009a197ceec9cc881ba46f727fcd8060a2d8d6a9dde7a69030a6fe2bb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "potential_utf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prefix-trie" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cf6e3177f0684016a5c209b00882e15f8bdd3f3bb48f0491df10cd102d0c6e7" +dependencies = [ + "either", + "ipnet", + "num-traits", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.117", +] + +[[package]] +name = "primal-check" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc0d895b311e3af9902528fbb8f928688abbd95872819320517cc24ca6b2bd08" +dependencies = [ + "num-integer", +] + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + +[[package]] +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit 0.25.12+spec-1.1.0", +] + +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "procfs" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc5b72d8145275d844d4b5f6d4e1eef00c8cd889edb6035c21675d1bb1f45c9f" +dependencies = [ + "bitflags", + "hex", + "procfs-core", + "rustix 0.38.44", +] + +[[package]] +name = "procfs-core" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "239df02d8349b06fc07398a3a1697b06418223b1c7725085e801e7c0fc6a12ec" +dependencies = [ + "bitflags", + "hex", +] + +[[package]] +name = "prometheus" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ca5326d8d0b950a9acd87e6a3f94745394f62e4dae1b1ee22b2bc0c394af43a" +dependencies = [ + "cfg-if", + "fnv", + "lazy_static", + "libc", + "memchr", + "parking_lot", + "procfs", + "thiserror 2.0.18", +] + +[[package]] +name = "prometheus-client" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" +checksum = "83cd1b99916654a69008fd66b4f9397fbe08e6e51dfe23d4417acf5d3b8cb87c" dependencies = [ - "cobs", - "embedded-io 0.4.0", - "embedded-io 0.6.1", - "heapless", - "postcard-derive", - "serde", + "dtoa", + "itoa", + "parking_lot", + "prometheus-client-derive-text-encode", ] [[package]] -name = "postcard-derive" -version = "0.2.2" +name = "prometheus-client-derive-text-encode" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0232bd009a197ceec9cc881ba46f727fcd8060a2d8d6a9dde7a69030a6fe2bb" +checksum = "66a455fbcb954c1a7decf3c586e860fd7889cddf4b8e164be736dbac95a953cd" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] -name = "potential_utf" -version = "0.1.4" +name = "prometools" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +checksum = "06c0f1b9189e7361a3e32ded803ab2ecb9a829d86cc32ce3fba8cff1b0cd4b69" dependencies = [ - "zerovec", + "itoa", + "parking_lot", + "prometheus-client", + "ryu", + "serde", ] [[package]] -name = "powerfmt" -version = "0.2.0" +name = "proptest" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" +checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744" +dependencies = [ + "bitflags", + "num-traits", + "rand 0.9.4", + "rand_chacha 0.9.0", + "rand_xorshift", + "regex-syntax", + "unarray", +] [[package]] -name = "ppv-lite86" -version = "0.2.21" +name = "prost" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568" dependencies = [ - "zerocopy", + "bytes", + "prost-derive", ] [[package]] -name = "primeorder" -version = "0.13.6" +name = "prost-derive" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" dependencies = [ - "elliptic-curve", + "anyhow", + "itertools 0.14.0", + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] -name = "proc-macro-crate" -version = "3.4.0" +name = "prost-types" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +checksum = "8991c4cbdb8bc5b11f0b074ffe286c30e523de90fee5ba8132f1399f23cb3dd7" dependencies = [ - "toml_edit", + "prost", ] [[package]] -name = "proc-macro2" -version = "1.0.105" +name = "qlog" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" +checksum = "0f15b83c59e6b945f2261c95a1dd9faf239187f32ff0a96af1d1d28c4557f919" dependencies = [ - "unicode-ident", + "serde", + "serde_json", + "serde_with", + "smallvec", ] [[package]] -name = "prost" -version = "0.14.1" +name = "qmux" +version = "0.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7231bd9b3d3d33c86b58adbac74b5ec0ad9f496b19d22801d773636feaa95f3d" +checksum = "1a625edac9a3021654a955444ca602b7b66b6764c7372196df08af53779ffbe7" dependencies = [ "bytes", - "prost-derive", + "futures", + "rustls", + "thiserror 2.0.18", + "tokio", + "tokio-rustls", + "tokio-tungstenite 0.28.0", + "tracing", + "web-transport-proto", + "web-transport-trait", ] [[package]] -name = "prost-derive" -version = "0.14.1" +name = "quanta" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9120690fafc389a67ba3803df527d0ec9cbbc9cc45e4cc20b332996dfb672425" +checksum = "f3ab5a9d756f0d97bdc89019bd2e4ea098cf9cde50ee7564dde6b81ccc8f06c7" dependencies = [ - "anyhow", - "itertools", - "proc-macro2", - "quote", - "syn", + "crossbeam-utils", + "libc", + "once_cell", + "raw-cpuid", + "wasi", + "web-sys", + "winapi", ] [[package]] -name = "prost-types" -version = "0.14.1" +name = "quiche" +version = "0.24.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9b4db3d6da204ed77bb26ba83b6122a73aeb2e87e25fbf7ad2e84c4ccbf8f72" +checksum = "ba053386c3a3b16441cb8a34574f91a9178fd3d813c0639514fcd8e4f274a44b" dependencies = [ - "prost", + "boring", + "cmake", + "either", + "enum_dispatch", + "foreign-types-shared", + "intrusive-collections", + "libc", + "libm", + "log", + "octets", + "qlog", + "slab", + "smallvec", + "windows-sys 0.59.0", +] + +[[package]] +name = "quick-xml" +version = "0.39.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdcc8dd4e2f670d309a5f0e83fe36dfdc05af317008fea29144da1a2ac858e5e" +dependencies = [ + "memchr", ] [[package]] @@ -3460,8 +5339,8 @@ dependencies = [ "quinn-udp", "rustc-hash", "rustls", - "socket2 0.6.1", - "thiserror 2.0.17", + "socket2", + "thiserror 2.0.18", "tokio", "tracing", "web-time", @@ -3469,23 +5348,23 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.13" +version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" +checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" dependencies = [ "aws-lc-rs", "bytes", "fastbloom", "getrandom 0.3.4", "lru-slab", - "rand 0.9.2", + "rand 0.9.4", "ring", "rustc-hash", "rustls", "rustls-pki-types", "rustls-platform-verifier 0.6.2", "slab", - "thiserror 2.0.17", + "thiserror 2.0.18", "tinyvec", "tracing", "web-time", @@ -3500,16 +5379,16 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.6.1", + "socket2", "tracing", "windows-sys 0.60.2", ] [[package]] name = "quote" -version = "1.0.43" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] @@ -3520,25 +5399,41 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + [[package]] name = "rand" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" dependencies = [ - "libc", "rand_chacha 0.3.1", "rand_core 0.6.4", ] [[package]] name = "rand" -version = "0.9.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" dependencies = [ "rand_chacha 0.9.0", - "rand_core 0.9.3", + "rand_core 0.9.5", +] + +[[package]] +name = "rand" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" +dependencies = [ + "chacha20", + "getrandom 0.4.2", + "rand_core 0.10.1", ] [[package]] @@ -3558,7 +5453,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -3567,30 +5462,85 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", ] [[package]] name = "rand_core" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ "getrandom 0.3.4", ] +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + +[[package]] +name = "rand_pcg" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a" +dependencies = [ + "rand_core 0.10.1", +] + +[[package]] +name = "rand_xorshift" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" +dependencies = [ + "rand_core 0.9.5", +] + +[[package]] +name = "raw-cpuid" +version = "11.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" +dependencies = [ + "bitflags", +] + [[package]] name = "rcgen" -version = "0.14.6" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75e669e5202259b5314d1ea5397316ad400819437857b90861765f24c4cf80a2" +dependencies = [ + "pem", + "ring", + "rustls-pki-types", + "time", + "yasna 0.5.2", +] + +[[package]] +name = "rcgen" +version = "0.14.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ec0a99f2de91c3cddc84b37e7db80e4d96b743e05607f647eb236fc0455907f" +checksum = "57f6d249aad744e274e682777a50283a225a32705394ee6d5fcc01efa25e4055" dependencies = [ "aws-lc-rs", "ring", "rustls-pki-types", "time", "x509-parser", - "yasna", + "yasna 0.6.0", +] + +[[package]] +name = "realfft" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f821338fddb99d089116342c46e9f1fbf3828dba077674613e734e01d6ea8677" +dependencies = [ + "rustfft", ] [[package]] @@ -3619,14 +5569,14 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] name = "regex" -version = "1.12.2" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", @@ -3636,9 +5586,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -3647,9 +5597,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "reqwest" @@ -3660,7 +5610,6 @@ dependencies = [ "base64 0.22.1", "bytes", "futures-core", - "futures-util", "http", "http-body", "http-body-util", @@ -3680,6 +5629,42 @@ dependencies = [ "sync_wrapper", "tokio", "tokio-rustls", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", +] + +[[package]] +name = "reqwest" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "rustls", + "rustls-pki-types", + "rustls-platform-verifier 0.7.0", + "sync_wrapper", + "tokio", + "tokio-rustls", "tokio-util", "tower", "tower-http", @@ -3689,7 +5674,21 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", - "webpki-roots 1.0.5", +] + +[[package]] +name = "reqwest-middleware" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57f17d28a6e6acfe1733fe24bcd30774d13bffa4b8a22535b4c8c98423088d4e" +dependencies = [ + "anyhow", + "async-trait", + "http", + "reqwest 0.12.28", + "serde", + "thiserror 1.0.69", + "tower-service", ] [[package]] @@ -3716,7 +5715,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.16", + "getrandom 0.2.17", "libc", "untrusted 0.9.0", "windows-sys 0.52.0", @@ -3742,17 +5741,29 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rubato" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5258099699851cfd0082aeb645feb9c084d9a5e1f1b8d5372086b989fc5e56a1" +dependencies = [ + "num-complex", + "num-integer", + "num-traits", + "realfft", +] + [[package]] name = "rustc-demangle" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" +checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" [[package]] name = "rustc-hash" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" [[package]] name = "rustc_version" @@ -3763,6 +5774,20 @@ dependencies = [ "semver", ] +[[package]] +name = "rustfft" +version = "6.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21db5f9893e91f41798c88680037dba611ca6674703c1a18601b01a72c8adb89" +dependencies = [ + "num-complex", + "num-integer", + "num-traits", + "primal-check", + "strength_reduce", + "transpose", +] + [[package]] name = "rusticata-macros" version = "4.1.0" @@ -3774,22 +5799,35 @@ dependencies = [ [[package]] name = "rustix" -version = "1.1.3" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustix" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ "bitflags", "errno", "libc", - "linux-raw-sys", + "linux-raw-sys 0.12.1", "windows-sys 0.61.2", ] [[package]] name = "rustls" -version = "0.23.36" +version = "0.23.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" +checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b" dependencies = [ "aws-lc-rs", "log", @@ -3813,20 +5851,11 @@ dependencies = [ "security-framework", ] -[[package]] -name = "rustls-pemfile" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" -dependencies = [ - "rustls-pki-types", -] - [[package]] name = "rustls-pki-types" -version = "1.13.2" +version = "1.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282" +checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" dependencies = [ "web-time", "zeroize", @@ -3834,13 +5863,13 @@ dependencies = [ [[package]] name = "rustls-platform-verifier" -version = "0.5.3" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19787cda76408ec5404443dc8b31795c87cd8fec49762dc75fa727740d34acc1" +checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" dependencies = [ "core-foundation 0.10.1", "core-foundation-sys", - "jni", + "jni 0.21.1", "log", "once_cell", "rustls", @@ -3849,19 +5878,19 @@ dependencies = [ "rustls-webpki", "security-framework", "security-framework-sys", - "webpki-root-certs 0.26.11", - "windows-sys 0.59.0", + "webpki-root-certs", + "windows-sys 0.61.2", ] [[package]] name = "rustls-platform-verifier" -version = "0.6.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" +checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0" dependencies = [ "core-foundation 0.10.1", "core-foundation-sys", - "jni", + "jni 0.22.4", "log", "once_cell", "rustls", @@ -3870,7 +5899,7 @@ dependencies = [ "rustls-webpki", "security-framework", "security-framework-sys", - "webpki-root-certs 1.0.5", + "webpki-root-certs", "windows-sys 0.61.2", ] @@ -3882,9 +5911,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-webpki" -version = "0.103.8" +version = "0.103.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" +checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" dependencies = [ "aws-lc-rs", "ring", @@ -3893,26 +5922,16 @@ dependencies = [ ] [[package]] -name = "rustversion" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" - -[[package]] -name = "ryu" +name = "rustversion" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] -name = "salsa20" -version = "0.11.0-rc.1" +name = "ryu" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3ff3b81c8a6e381bc1673768141383f9328048a60edddcfc752a8291a138443" -dependencies = [ - "cfg-if", - "cipher", -] +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] name = "same-file" @@ -3925,9 +5944,9 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.28" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" dependencies = [ "windows-sys 0.61.2", ] @@ -3946,9 +5965,9 @@ dependencies = [ [[package]] name = "schemars" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54e910108742c57a770f492731f99be216a52fadd361b06c8fb59d74ccc267d2" +checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" dependencies = [ "dyn-clone", "ref-cast", @@ -3968,6 +5987,38 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "scroll" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6" +dependencies = [ + "scroll_derive", +] + +[[package]] +name = "scroll_derive" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1783eabc414609e28a5ba76aee5ddd52199f7107a0b24c2e9746a1ecc34a683d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "scuffle-av1" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "028eddc8b17fe9dba817b238c56d3acf03748bdbed4c35783cfb93857ef15955" +dependencies = [ + "byteorder", + "bytes", + "scuffle-bytes-util", + "scuffle-workspace-hack", +] + [[package]] name = "scuffle-bytes-util" version = "0.1.5" @@ -4013,9 +6064,9 @@ checksum = "8028ded836a0d9fabdfa4d713389b76a2098b5153f50a135c8faed7e3a3d5ae2" [[package]] name = "sd-notify" -version = "0.4.5" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b943eadf71d8b69e661330cb0e2656e31040acf21ee7708e2c238a0ec6af2bf4" +checksum = "3e4ef7359e694bfaf1dd27a30f9d760b54c00dfae9f19bd0c05a39bc9128fe76" dependencies = [ "libc", ] @@ -4036,9 +6087,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "3.5.1" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ "bitflags", "core-foundation 0.10.1", @@ -4049,25 +6100,33 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.15.0" +version = "2.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" dependencies = [ "core-foundation-sys", "libc", ] [[package]] -name = "self_cell" -version = "1.2.2" +name = "seize" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b12e76d157a900eb52e81bc6e9f3069344290341720e9178cde2407113ac8d89" +checksum = "5b55fb86dfd3a2f5f76ea78310a88f96c4ea21a3031f8d212443d56123fd0521" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] [[package]] name = "semver" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" +dependencies = [ + "serde", + "serde_core", +] [[package]] name = "send_wrapper" @@ -4112,15 +6171,16 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] name = "serde_json" -version = "1.0.149" +version = "1.0.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" dependencies = [ + "indexmap 2.14.0", "itoa", "memchr", "serde", @@ -4141,9 +6201,18 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "1.0.4" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_spanned" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" dependencies = [ "serde_core", ] @@ -4162,17 +6231,18 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.16.1" +version = "3.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fa237f2807440d238e0364a218270b98f767a00d3dada77b1c53ae88940e2e7" +checksum = "e72c1c2cb7b223fafb600a619537a871c2818583d619401b785e7c0b746ccde2" dependencies = [ "base64 0.22.1", + "bs58", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.13.0", + "indexmap 2.14.0", "schemars 0.9.0", - "schemars 1.2.0", + "schemars 1.2.1", "serde_core", "serde_json", "serde_with_macros", @@ -4181,46 +6251,58 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.16.1" +version = "3.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52a8e3ca0ca629121f70ab50f95249e5a6f925cc0f6ffe8256c45b728875706c" +checksum = "b90c488738ecb4fb0262f41f43bc40efc5868d9fb744319ddf5f5317f417bfac" dependencies = [ - "darling", + "darling 0.23.0", "proc-macro2", "quote", - "syn", + "syn 2.0.117", +] + +[[package]] +name = "serde_yaml" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b" +dependencies = [ + "indexmap 1.9.3", + "ryu", + "serde", + "yaml-rust", ] [[package]] name = "serdect" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9af4a3e75ebd5599b30d4de5768e00b5095d518a79fefc3ecbaf77e665d1ec06" +checksum = "66cf8fedced2fcf12406bcb34223dffb92eaf34908ede12fed414c82b7f00b3e" dependencies = [ "base16ct 1.0.0", "serde", ] [[package]] -name = "sha1" -version = "0.10.6" +name = "sfv" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +checksum = "0d471eaefb14f4b30032525bdb124b36e55ba9cb1292080e06f1a236cd10fe87" dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.7", + "base64 0.22.1", + "indexmap 2.14.0", + "ref-cast", ] [[package]] name = "sha1" -version = "0.11.0-rc.2" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e046edf639aa2e7afb285589e5405de2ef7e61d4b0ac1e30256e3eab911af9" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", - "cpufeatures", - "digest 0.11.0-rc.3", + "cpufeatures 0.2.17", + "digest 0.10.7", ] [[package]] @@ -4236,19 +6318,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest 0.10.7", ] [[package]] name = "sha2" -version = "0.11.0-rc.2" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1e3878ab0f98e35b2df35fe53201d088299b41a6bb63e3e34dada2ac4abd924" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" dependencies = [ "cfg-if", - "cpufeatures", - "digest 0.11.0-rc.3", + "cpufeatures 0.3.0", + "digest 0.11.3", ] [[package]] @@ -4266,6 +6348,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + [[package]] name = "signal-hook-registry" version = "1.4.8" @@ -4288,15 +6376,25 @@ dependencies = [ [[package]] name = "signature" -version = "3.0.0-rc.6" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a96996ccff7dfa16f052bd995b4cecc72af22c35138738dc029f0ead6608d" +checksum = "28d567dcbaf0049cb8ac2608a76cd95ff9e4412e1899d389ee400918ca7537f5" [[package]] name = "simd-adler32" -version = "0.3.8" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" + +[[package]] +name = "simd_cesu8" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" +checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33" +dependencies = [ + "rustc_version", + "simdutf8", +] [[package]] name = "simdutf8" @@ -4306,63 +6404,140 @@ checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[package]] name = "simple-dns" -version = "0.9.3" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee851d0e5e7af3721faea1843e8015e820a234f81fda3dea9247e15bac9a86a" +checksum = "7a75cbde1bf934313596a004973e462f9a82caa814dcf1a5f507bdf51597eeb4" dependencies = [ "bitflags", ] [[package]] name = "simple_asn1" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "297f631f50729c8c99b84667867963997ec0b50f32b2a7dbcab828ef0541e8bb" +checksum = "0d585997b0ac10be3c5ee635f1bab02d512760d14b7c468801ac8a01d9ae5f1d" dependencies = [ "num-bigint", "num-traits", - "thiserror 2.0.17", + "thiserror 2.0.18", "time", ] [[package]] name = "siphasher" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" +checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" [[package]] name = "slab" -version = "0.4.11" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "slog" +version = "2.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b3b8565691b22d2bdfc066426ed48f837fc0c5f2c8cad8d9718f7f99d6995c1" +dependencies = [ + "anyhow", + "erased-serde 0.3.31", + "rustversion", + "serde_core", +] + +[[package]] +name = "slog-async" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72c8038f898a2c79507940990f05386455b3a317d8f18d4caea7cbc3d5096b84" +dependencies = [ + "crossbeam-channel", + "slog", + "take_mut", + "thread_local", +] + +[[package]] +name = "slog-json" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e1e53f61af1e3c8b852eef0a9dee29008f55d6dd63794f3f12cef786cf0f219" +dependencies = [ + "serde", + "serde_json", + "slog", + "time", +] + +[[package]] +name = "slog-scope" +version = "4.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42b76cf645c92e7850d5a1c9205ebf2864bd32c0ab3e978e6daad51fedf7ef54" +dependencies = [ + "arc-swap", + "lazy_static", + "slog", +] + +[[package]] +name = "slog-stdlog" +version = "4.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" +checksum = "6706b2ace5bbae7291d3f8d2473e2bfab073ccd7d03670946197aec98471fa3e" +dependencies = [ + "log", + "slog", + "slog-scope", +] + +[[package]] +name = "slog-term" +version = "2.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cb1fc680b38eed6fad4c02b3871c09d2c81db8c96aa4e9c0a34904c830f09b5" +dependencies = [ + "chrono", + "is-terminal", + "slog", + "term", + "thread_local", + "time", +] [[package]] name = "smallvec" version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +dependencies = [ + "serde", +] [[package]] -name = "socket2" -version = "0.5.10" +name = "smawk" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] +checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" [[package]] name = "socket2" -version = "0.6.1" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] +[[package]] +name = "sorted-index-buffer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea06cc588e43c632923a55450401b8f25e628131571d4e1baea1bdfdb2b5ed06" + [[package]] name = "spez" version = "0.1.2" @@ -4371,7 +6546,7 @@ checksum = "c87e960f4dca2788eeb86bbdde8dd246be8948790b7618d656e68f9b720a86e8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -4389,6 +6564,15 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591" +[[package]] +name = "spinning_top" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300" +dependencies = [ + "lock_api", +] + [[package]] name = "spki" version = "0.7.3" @@ -4401,12 +6585,12 @@ dependencies = [ [[package]] name = "spki" -version = "0.8.0-rc.4" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8baeff88f34ed0691978ec34440140e1572b68c7dd4a495fd14a3dc1944daa80" +checksum = "1d9efca8738c78ee9484207732f728b1ef517bbb1833d6fc0879ca898a522f6f" dependencies = [ "base64ct", - "der 0.8.0-rc.10", + "der 0.8.0", ] [[package]] @@ -4415,6 +6599,18 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strength_reduce" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe895eb47f22e2ddd4dabc02bce419d2e643c8e3b585c78158b349195bc24d82" + [[package]] name = "strsim" version = "0.11.1" @@ -4423,23 +6619,23 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "strum" -version = "0.27.2" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" +checksum = "9628de9b8791db39ceda2b119bbe13134770b56c138ec1d3af810d045c04f9bd" dependencies = [ "strum_macros", ] [[package]] name = "strum_macros" -version = "0.27.2" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" +checksum = "ab85eea0270ee17587ed4156089e10b9e6880ee688791d45a905f5b1ca36f664" dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -4450,9 +6646,20 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.114" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -4476,14 +6683,14 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] name = "system-configuration" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" dependencies = [ "bitflags", "core-foundation 0.9.4", @@ -4500,25 +6707,79 @@ dependencies = [ "libc", ] +[[package]] +name = "system-deps" +version = "7.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396a35feb67335377e0251fcbc1092fc85c484bd4e3a7a54319399da127796e7" +dependencies = [ + "cfg-expr", + "heck", + "pkg-config", + "toml 1.1.2+spec-1.1.0", + "version-compare", +] + [[package]] name = "tagptr" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" +[[package]] +name = "take_mut" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" + +[[package]] +name = "target-lexicon" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" + +[[package]] +name = "task-killswitch" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2ba744ef0fcfe2d3fa7475ec61af0a9c76c1b0a75d58f0d20a9e10745ae44f" +dependencies = [ + "dashmap", + "parking_lot", + "tokio", +] + [[package]] name = "tempfile" -version = "3.24.0" +version = "3.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.3.4", + "getrandom 0.4.2", "once_cell", - "rustix", + "rustix 1.1.4", + "windows-sys 0.61.2", +] + +[[package]] +name = "term" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8c27177b12a6399ffc08b98f76f7c9a1f4fe9fc967c784c5a071fa8d93cf7e1" +dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "textwrap" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" +dependencies = [ + "smawk", +] + [[package]] name = "thiserror" version = "1.0.69" @@ -4530,11 +6791,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ - "thiserror-impl 2.0.17", + "thiserror-impl 2.0.18", ] [[package]] @@ -4545,18 +6806,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] name = "thiserror-impl" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -4568,33 +6829,76 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "thrift_codec" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83d957f535b242b91aa9f47bde08080f9a6fef276477e55b0079979d002759d5" +dependencies = [ + "byteorder", + "trackable", +] + +[[package]] +name = "tikv-jemalloc-ctl" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "661f1f6a57b3a36dc9174a2c10f19513b4866816e13425d3e418b11cc37bc24c" +dependencies = [ + "libc", + "paste", + "tikv-jemalloc-sys", +] + +[[package]] +name = "tikv-jemalloc-sys" +version = "0.6.1+5.3.0-1-ge13ca993e8ccb9ba9847cc330696e02839f328f7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd8aa5b2ab86a2cefa406d889139c162cbb230092f7d1d7cbc1716405d852a3b" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "tikv-jemallocator" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0359b4327f954e0567e69fb191cf1436617748813819c94b8cd4a431422d053a" +dependencies = [ + "libc", + "tikv-jemalloc-sys", +] + [[package]] name = "time" -version = "0.3.44" +version = "0.3.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" dependencies = [ "deranged", "itoa", "js-sys", + "libc", "num-conv", + "num_threads", "powerfmt", - "serde", + "serde_core", "time-core", "time-macros", ] [[package]] name = "time-core" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" [[package]] name = "time-macros" -version = "0.2.24" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" dependencies = [ "num-conv", "time-core", @@ -4602,9 +6906,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" dependencies = [ "displaydoc", "zerovec", @@ -4612,9 +6916,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" dependencies = [ "tinyvec_macros", ] @@ -4627,9 +6931,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.49.0" +version = "1.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" +checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" dependencies = [ "bytes", "libc", @@ -4637,7 +6941,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.1", + "socket2", "tokio-macros", "tracing", "windows-sys 0.61.2", @@ -4645,13 +6949,48 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", +] + +[[package]] +name = "tokio-quiche" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3152843e8aafb0dae1f31cb0e1223ffff010de71efca2ec2a6b5405a57001a5" +dependencies = [ + "anyhow", + "boring", + "buffer-pool", + "crossbeam", + "datagram-socket", + "foundations", + "futures", + "futures-util", + "ipnetwork", + "libc", + "log", + "nix", + "octets", + "pin-project", + "quiche", + "serde", + "serde_with", + "slog-scope", + "slog-stdlog", + "smallvec", + "task-killswitch", + "thiserror 2.0.18", + "tokio", + "tokio-stream", + "tokio-util", + "triomphe", + "url", ] [[package]] @@ -4678,30 +7017,30 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.24.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" +checksum = "d25a406cddcc431a75d3d9afc6a7c0f7428d4891dd973e4d54c56b46127bf857" dependencies = [ "futures-util", "log", "rustls", + "rustls-native-certs", "rustls-pki-types", "tokio", "tokio-rustls", - "tungstenite 0.24.0", - "webpki-roots 0.26.11", + "tungstenite 0.28.0", ] [[package]] name = "tokio-tungstenite" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d25a406cddcc431a75d3d9afc6a7c0f7428d4891dd973e4d54c56b46127bf857" +checksum = "8f72a05e828585856dacd553fba484c242c46e391fb0e58917c942ee9202915c" dependencies = [ "futures-util", "log", "tokio", - "tungstenite 0.28.0", + "tungstenite 0.29.0", ] [[package]] @@ -4712,28 +7051,31 @@ checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" dependencies = [ "bytes", "futures-core", + "futures-io", "futures-sink", "futures-util", "pin-project-lite", + "slab", "tokio", ] [[package]] name = "tokio-websockets" -version = "0.12.3" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1b6348ebfaaecd771cecb69e832961d277f59845d4220a584701f72728152b7" +checksum = "dad543404f98bfc969aeb71994105c592acfc6c43323fddcd016bb208d1c65cb" dependencies = [ + "aws-lc-rs", "base64 0.22.1", "bytes", "futures-core", "futures-sink", - "getrandom 0.3.4", + "getrandom 0.4.2", "http", "httparse", - "rand 0.9.2", - "ring", + "rand 0.10.1", "rustls-pki-types", + "sha1_smol", "simdutf8", "tokio", "tokio-rustls", @@ -4742,17 +7084,53 @@ dependencies = [ [[package]] name = "toml" -version = "0.9.11+spec-1.1.0" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", + "toml_edit 0.22.27", +] + +[[package]] +name = "toml" +version = "0.9.12+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" +dependencies = [ + "indexmap 2.14.0", + "serde_core", + "serde_spanned 1.1.1", + "toml_datetime 0.7.5+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 0.7.15", +] + +[[package]] +name = "toml" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3afc9a848309fe1aaffaed6e1546a7a14de1f935dc9d89d32afd9a44bab7c46" +checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" dependencies = [ - "indexmap 2.13.0", + "indexmap 2.14.0", "serde_core", - "serde_spanned", - "toml_datetime", + "serde_spanned 1.1.1", + "toml_datetime 1.1.1+spec-1.1.0", "toml_parser", "toml_writer", - "winnow", + "winnow 1.0.3", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", ] [[package]] @@ -4764,38 +7142,67 @@ dependencies = [ "serde_core", ] +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + [[package]] name = "toml_edit" -version = "0.23.10+spec-1.0.0" +version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap 2.13.0", - "toml_datetime", + "indexmap 2.14.0", + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", + "toml_write", + "winnow 0.7.15", +] + +[[package]] +name = "toml_edit" +version = "0.25.12+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7" +dependencies = [ + "indexmap 2.14.0", + "toml_datetime 1.1.1+spec-1.1.0", "toml_parser", - "winnow", + "winnow 1.0.3", ] [[package]] name = "toml_parser" -version = "1.0.6+spec-1.1.0" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" dependencies = [ - "winnow", + "winnow 1.0.3", ] +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + [[package]] name = "toml_writer" -version = "1.0.6+spec-1.1.0" +version = "1.1.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" +checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" [[package]] name = "tonic" -version = "0.14.2" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb7613188ce9f7df5bfe185db26c5814347d110db17920415cf2fbcad85e7203" +checksum = "ac2a5518c70fa84342385732db33fb3f44bc4cc748936eb5833d2df34d6445ef" dependencies = [ "async-trait", "axum", @@ -4810,7 +7217,7 @@ dependencies = [ "hyper-util", "percent-encoding", "pin-project", - "socket2 0.6.1", + "socket2", "sync_wrapper", "tokio", "tokio-stream", @@ -4822,9 +7229,9 @@ dependencies = [ [[package]] name = "tonic-prost" -version = "0.14.2" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66bd50ad6ce1252d87ef024b3d64fe4c3cf54a86fb9ef4c631fdd0ded7aeaa67" +checksum = "50849f68853be452acf590cde0b146665b8d507b3b8af17261df47e02c209ea0" dependencies = [ "bytes", "prost", @@ -4833,13 +7240,13 @@ dependencies = [ [[package]] name = "tower" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ "futures-core", "futures-util", - "indexmap 2.13.0", + "indexmap 2.14.0", "pin-project-lite", "slab", "sync_wrapper", @@ -4852,9 +7259,9 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.8" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" dependencies = [ "async-compression", "bitflags", @@ -4866,7 +7273,6 @@ dependencies = [ "http-body-util", "http-range-header", "httpdate", - "iri-string", "mime", "mime_guess", "percent-encoding", @@ -4876,7 +7282,7 @@ dependencies = [ "tower", "tower-layer", "tower-service", - "tracing", + "url", ] [[package]] @@ -4903,6 +7309,17 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-android" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12612be8f868a09c0ceae7113ff26afe79d81a24473a393cb9120ece162e86c0" +dependencies = [ + "android_log-sys", + "tracing", + "tracing-subscriber", +] + [[package]] name = "tracing-attributes" version = "0.1.31" @@ -4911,7 +7328,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -4937,9 +7354,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.22" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" dependencies = [ "matchers", "nu-ansi-term", @@ -4953,6 +7370,66 @@ dependencies = [ "tracing-log", ] +[[package]] +name = "tracing-test" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19a4c448db514d4f24c5ddb9f73f2ee71bfb24c526cf0c570ba142d1119e0051" +dependencies = [ + "tracing-core", + "tracing-subscriber", + "tracing-test-macro", +] + +[[package]] +name = "tracing-test-macro" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad06847b7afb65c7866a36664b75c40b895e318cea4f71299f013fb22965329d" +dependencies = [ + "quote", + "syn 2.0.117", +] + +[[package]] +name = "trackable" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15bd114abb99ef8cee977e517c8f37aee63f184f2d08e3e6ceca092373369ae" +dependencies = [ + "trackable_derive", +] + +[[package]] +name = "trackable_derive" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebeb235c5847e2f82cfe0f07eb971d1e5f6804b18dac2ae16349cc604380f82f" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "transpose" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad61aed86bc3faea4300c7aee358b4c6d0c8d6ccc36524c96e4c92ccf26e77e" +dependencies = [ + "num-integer", + "strength_reduce", +] + +[[package]] +name = "triomphe" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd69c5aa8f924c7519d6372789a74eac5b94fb0f8fcf0d4a97eb0bfc3e785f39" +dependencies = [ + "serde", + "stable_deref_trait", +] + [[package]] name = "try-lock" version = "0.2.5" @@ -4961,46 +7438,56 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "tungstenite" -version = "0.24.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" +checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" dependencies = [ - "byteorder", "bytes", "data-encoding", "http", "httparse", "log", - "rand 0.8.5", + "rand 0.9.4", "rustls", "rustls-pki-types", - "sha1 0.10.6", - "thiserror 1.0.69", + "sha1", + "thiserror 2.0.18", "utf-8", ] [[package]] name = "tungstenite" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" +checksum = "6c01152af293afb9c7c2a57e4b559c5620b421f6d133261c60dd2d0cdb38e6b8" dependencies = [ "bytes", "data-encoding", "http", "httparse", "log", - "rand 0.9.2", - "sha1 0.10.6", - "thiserror 2.0.17", - "utf-8", + "rand 0.9.4", + "sha1", + "thiserror 2.0.18", ] +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + [[package]] name = "typenum" -version = "1.19.0" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "unarray" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicase" @@ -5010,15 +7497,15 @@ checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-segmentation" -version = "1.12.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" +checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" [[package]] name = "unicode-xid" @@ -5026,16 +7513,160 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "uniffi" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc5f2297ee5b893405bed1a6929faec4713a061df158ecf5198089f23910d470" +dependencies = [ + "anyhow", + "camino", + "cargo_metadata", + "clap", + "uniffi_bindgen", + "uniffi_build", + "uniffi_core", + "uniffi_macros", + "uniffi_pipeline", +] + +[[package]] +name = "uniffi_bindgen" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bc0c60a9607e7ab77a2ad47ec5530178015014839db25af7512447d2238016c" +dependencies = [ + "anyhow", + "askama", + "camino", + "cargo_metadata", + "fs-err 2.11.0", + "glob", + "goblin", + "heck", + "indexmap 2.14.0", + "once_cell", + "serde", + "tempfile", + "textwrap", + "toml 0.9.12+spec-1.1.0", + "uniffi_internal_macros", + "uniffi_meta", + "uniffi_pipeline", + "uniffi_udl", +] + +[[package]] +name = "uniffi_build" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c39413c43b955e4aa8a4e2b34bbd1b6b5ff6bd85532b52f9eb92fbe88c14458" +dependencies = [ + "anyhow", + "camino", + "uniffi_bindgen", +] + +[[package]] +name = "uniffi_core" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77baf5d539fe2e1ad6805e942dbc5dbdeb2b83eb5f2b3a6535d422ca4b02a12f" +dependencies = [ + "anyhow", + "bytes", + "once_cell", + "static_assertions", +] + +[[package]] +name = "uniffi_internal_macros" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4b42137524f4be6400fcaca9d02c1d4ecb6ad917e4013c0b93235526d8396e5" +dependencies = [ + "anyhow", + "indexmap 2.14.0", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "uniffi_macros" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9273ec45330d8fe9a3701b7b983cea7a4e218503359831967cb95d26b873561" +dependencies = [ + "camino", + "fs-err 2.11.0", + "once_cell", + "proc-macro2", + "quote", + "serde", + "syn 2.0.117", + "toml 0.9.12+spec-1.1.0", + "uniffi_meta", +] + +[[package]] +name = "uniffi_meta" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "431d2f443e7828a6c29d188de98b6771a6491ee98bba2d4372643bf93f988a18" +dependencies = [ + "anyhow", + "siphasher", + "uniffi_internal_macros", + "uniffi_pipeline", +] + +[[package]] +name = "uniffi_pipeline" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "761ef74f6175e15603d0424cc5f98854c5baccfe7bf4ccb08e5816f9ab8af689" +dependencies = [ + "anyhow", + "heck", + "indexmap 2.14.0", + "tempfile", + "uniffi_internal_macros", +] + +[[package]] +name = "uniffi_udl" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68773ec0e1c067b6505a73bbf6a5782f31a7f9209333a0df97b87565c46bf370" +dependencies = [ + "anyhow", + "textwrap", + "uniffi_meta", + "weedle2", +] + [[package]] name = "universal-hash" -version = "0.6.0-rc.2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a55be643b40a21558f44806b53ee9319595bc7ca6896372e4e08e5d7d83c9cd6" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ - "crypto-common 0.2.0-rc.4", + "crypto-common 0.1.7", "subtle", ] +[[package]] +name = "unsafe-libopus" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c757408e7256c910343c7b215c8c8b878948630eecc774baabcca0972376eb73" +dependencies = [ + "arrayref", + "num-complex", + "num-traits", +] + [[package]] name = "untrusted" version = "0.7.1" @@ -5081,20 +7712,69 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.19.0" +version = "1.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" +checksum = "d258b83ceec21034727ecee8c382cfa6c3e133699b0742c64571814fb420c9f7" dependencies = [ - "getrandom 0.3.4", + "getrandom 0.4.2", "js-sys", "wasm-bindgen", ] [[package]] -name = "valuable" -version = "0.1.1" +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "vergen" +version = "9.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b849a1f6d8639e8de261e81ee0fc881e3e3620db1af9f2e0da015d4382ceaf75" +dependencies = [ + "anyhow", + "derive_builder", + "rustversion", + "vergen-lib", +] + +[[package]] +name = "vergen-gitcl" +version = "9.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ff3b5300a085d6bcd8fc96a507f706a28ae3814693236c9b409db71a1d15b9" +dependencies = [ + "anyhow", + "derive_builder", + "rustversion", + "time", + "vergen", + "vergen-lib", +] + +[[package]] +name = "vergen-lib" +version = "9.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b34a29ba7e9c59e62f229ae1932fb1b8fb8a6fdcc99215a641913f5f5a59a569" +dependencies = [ + "anyhow", + "derive_builder", + "rustversion", +] + +[[package]] +name = "version-compare" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" +checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e" [[package]] name = "version_check" @@ -5129,18 +7809,27 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.1+wasi-0.2.4" +version = "1.0.3+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" dependencies = [ - "wit-bindgen", + "wit-bindgen 0.57.1", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen 0.51.0", ] [[package]] name = "wasm-bindgen" -version = "0.2.106" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" +checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409" dependencies = [ "cfg-if", "once_cell", @@ -5151,22 +7840,19 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.56" +version = "0.4.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c" +checksum = "9473dbd2991ae90b6291c3c32c30c6187ac49aa32f9905d1cce280ec1e110b0f" dependencies = [ - "cfg-if", "js-sys", - "once_cell", "wasm-bindgen", - "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.106" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" +checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5174,31 +7860,53 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.106" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" +checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn", + "syn 2.0.117", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.106" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" +checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437" dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap 2.14.0", + "wasm-encoder", + "wasmparser", +] + [[package]] name = "wasm-streams" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb" dependencies = [ "futures-util", "js-sys", @@ -5207,11 +7915,23 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap 2.14.0", + "semver", +] + [[package]] name = "web-async" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6b2260b739b0e95cf9b78f22a64704af7ed9760ea12baa3745b4b97899dc89a" +checksum = "f5414b65d9a5094649bb99987bb74db71febfdfa3677b7954a0a05c99d0424e8" dependencies = [ "tokio", "tracing", @@ -5220,9 +7940,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.83" +version = "0.3.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" +checksum = "6d621441cfc37b84979402712047321980c178f299193a3589d05b99e8763436" dependencies = [ "js-sys", "wasm-bindgen", @@ -5240,17 +7960,35 @@ dependencies = [ [[package]] name = "web-transport-iroh" -version = "0.1.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02538319baa3665fbdd788bb2e08c498ad7c17462b9444d71f9da6a5b11247a9" +checksum = "8f4ebffba98c30a0ac3560c4d7c595e61a5ad040049d65ff5c91304e5ee5f5ee" dependencies = [ "bytes", "http", "iroh", - "iroh-quinn", "n0-error", "n0-future", - "thiserror 2.0.17", + "tokio", + "tracing", + "url", + "web-transport-proto", + "web-transport-trait", +] + +[[package]] +name = "web-transport-noq" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d42caba209a9583813c1d802197fc568e9a78f45e42ff40fba54e4d16d2e3af2" +dependencies = [ + "bytes", + "futures", + "http", + "noq 0.17.0", + "rustls", + "rustls-native-certs", + "thiserror 2.0.18", "tokio", "tracing", "url", @@ -5260,31 +7998,33 @@ dependencies = [ [[package]] name = "web-transport-proto" -version = "0.3.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "660175a6d1643adb93b71c4f853d4f20f0fce47f53ae579afe9f7711fe84870d" +checksum = "0225d295c8ac00a2e9a498aefeaf3f3c6186da12a251c938189b15b82ea22808" dependencies = [ "bytes", "http", - "thiserror 2.0.17", + "sfv", + "thiserror 2.0.18", "tokio", "url", ] [[package]] -name = "web-transport-quinn" -version = "0.10.2" +name = "web-transport-quiche" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f44b4e68a3e7adb790793e24ec8b5923a610a8c2df1d6cd58849f9e4759d04" +checksum = "b165e13c505ce9541d0a1f762020fed6e63d3ee88e6f685e4f60007cfa555282" dependencies = [ + "boring", "bytes", + "flume", "futures", "http", - "quinn", - "rustls", - "rustls-native-certs", - "thiserror 2.0.17", + "rustls-pki-types", + "thiserror 2.0.18", "tokio", + "tokio-quiche", "tracing", "url", "web-transport-proto", @@ -5292,63 +8032,68 @@ dependencies = [ ] [[package]] -name = "web-transport-trait" -version = "0.3.1" +name = "web-transport-quinn" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ae5c857e6b426610648b39c6b48f9e66ae97b27b166d7c2f1ec369596548271" +checksum = "cac11b6caf163be7f980442a26fcba15e8074a5f22e85fbb71f0f77d11cecf60" dependencies = [ "bytes", + "futures", + "http", + "quinn", + "rustls", + "rustls-native-certs", + "thiserror 2.0.18", + "tokio", + "tracing", + "url", + "web-transport-proto", + "web-transport-trait", ] [[package]] -name = "web-transport-ws" -version = "0.2.2" +name = "web-transport-trait" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aee7ae0f2a6f3596dc2842e20f2ad0cf046211414979d67e445760348b60becf" +checksum = "fc5f83d19cf6c8ba147f4e1e5935a8a115c91f6abbf714d740a83b967d558e6e" dependencies = [ "bytes", - "futures", - "thiserror 2.0.17", - "tokio", - "tokio-tungstenite 0.24.0", - "web-transport-proto", - "web-transport-trait", ] [[package]] -name = "webpki-root-certs" -version = "0.26.11" +name = "webm-iterable" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75c7f0ef91146ebfb530314f5f1d24528d7f0767efbfd31dce919275413e393e" +checksum = "cd9fbf173b4b38f2f8bbb0082a0d4cb21f263a70811f5fccb1663c421c66d9f9" dependencies = [ - "webpki-root-certs 1.0.5", + "ebml-iterable", ] [[package]] name = "webpki-root-certs" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36a29fc0408b113f68cf32637857ab740edfafdf460c326cd2afaa2d84cc05dc" +checksum = "f31141ce3fc3e300ae89b78c0dd67f9708061d1d2eda54b8209346fd6be9a92c" dependencies = [ "rustls-pki-types", ] [[package]] name = "webpki-roots" -version = "0.26.11" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +checksum = "52f5ee44c96cf55f1b349600768e3ece3a8f26010c05265ab73f945bb1a2eb9d" dependencies = [ - "webpki-roots 1.0.5", + "rustls-pki-types", ] [[package]] -name = "webpki-roots" -version = "1.0.5" +name = "weedle2" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12bed680863276c63889429bfd6cab3b99943659923822de1c8a39c49e4d722c" +checksum = "998d2c24ec099a87daf9467808859f9d82b61f1d9c9701251aea037f514eae0e" dependencies = [ - "rustls-pki-types", + "nom", ] [[package]] @@ -5441,7 +8186,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -5452,7 +8197,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -5471,6 +8216,17 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" +dependencies = [ + "windows-link", + "windows-result", + "windows-strings", +] + [[package]] name = "windows-result" version = "0.4.1" @@ -5498,15 +8254,6 @@ dependencies = [ "windows-targets 0.42.2", ] -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - [[package]] name = "windows-sys" version = "0.52.0" @@ -5558,21 +8305,6 @@ dependencies = [ "windows_x86_64_msvc 0.42.2", ] -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - [[package]] name = "windows-targets" version = "0.52.6" @@ -5621,12 +8353,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" @@ -5645,12 +8371,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" @@ -5669,12 +8389,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -5705,12 +8419,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.6" @@ -5729,12 +8437,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" @@ -5753,12 +8455,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" @@ -5777,12 +8473,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -5797,49 +8487,159 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" -version = "0.7.14" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" dependencies = [ "memchr", ] [[package]] -name = "winreg" -version = "0.50.0" +name = "wiremock" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +checksum = "08db1edfb05d9b3c1542e521aea074442088292f00b5f28e435c714a98f85031" dependencies = [ - "cfg-if", - "windows-sys 0.48.0", + "assert-json-diff", + "base64 0.22.1", + "deadpool", + "futures", + "http", + "http-body-util", + "hyper", + "hyper-util", + "log", + "once_cell", + "regex", + "serde", + "serde_json", + "tokio", + "url", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", ] [[package]] name = "wit-bindgen" -version = "0.46.0" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap 2.14.0", + "prettyplease", + "syn 2.0.117", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.117", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap 2.14.0", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap 2.14.0", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] [[package]] name = "wmi" -version = "0.17.3" +version = "0.18.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120d8c2b6a7c96c27bf4a7947fd7f02d73ca7f5958b8bd72a696e46cb5521ee6" +checksum = "7c81b85c57a57500e56669586496bf2abd5cf082b9d32995251185d105208b64" dependencies = [ "chrono", "futures", "log", "serde", - "thiserror 2.0.17", + "thiserror 2.0.18", "windows", "windows-core", ] [[package]] name = "writeable" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" [[package]] name = "ws_stream_wasm" @@ -5854,7 +8654,7 @@ dependencies = [ "pharos", "rustc_version", "send_wrapper", - "thiserror 2.0.17", + "thiserror 2.0.18", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -5862,9 +8662,9 @@ dependencies = [ [[package]] name = "x509-parser" -version = "0.18.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3e137310115a65136898d2079f003ce33331a6c4b0d51f1531d1be082b6425" +checksum = "d43b0f71ce057da06bc0851b23ee24f3f86190b07203dd8f567d0b706a185202" dependencies = [ "asn1-rs", "aws-lc-rs", @@ -5875,7 +8675,7 @@ dependencies = [ "oid-registry", "ring", "rusticata-macros", - "thiserror 2.0.17", + "thiserror 2.0.18", "time", ] @@ -5894,6 +8694,27 @@ dependencies = [ "xml-rs", ] +[[package]] +name = "yaml-merge-keys" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af47d205071caaef70ebce5e04e1d88eba944833f8a6626dacdda700f86c285a" +dependencies = [ + "lazy_static", + "serde_yaml", + "thiserror 1.0.69", + "yaml-rust", +] + +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + [[package]] name = "yasna" version = "0.5.2" @@ -5903,11 +8724,21 @@ dependencies = [ "time", ] +[[package]] +name = "yasna" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5f6765e852b9b4dc8e2a76843e4d64d1cea8e79bcde0b6901aea8e7c7f08282" +dependencies = [ + "bit-vec", + "time", +] + [[package]] name = "yoke" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -5916,60 +8747,54 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", "synstructure", ] -[[package]] -name = "z32" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2164e798d9e3d84ee2c91139ace54638059a3b23e361f5c11781c2c6459bde0f" - [[package]] name = "zerocopy" -version = "0.8.33" +version = "0.8.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "668f5168d10b9ee831de31933dc111a459c97ec93225beb307aed970d1372dfd" +checksum = "3b065d4f0e55f82fae73202e189638116a87c55ab6b8e6c2721e13dd9d854ad1" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.33" +version = "0.8.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c7962b26b0a8685668b671ee4b54d007a67d4eaf05fda79ac0ecf41e32270f1" +checksum = "0b631b19d36a892ab55420c92dbc83ccd79274f25be714855d3074aa71cab639" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] name = "zerofrom" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", "synstructure", ] @@ -5990,14 +8815,14 @@ checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] name = "zerotrie" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" dependencies = [ "displaydoc", "yoke", @@ -6006,9 +8831,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" dependencies = [ "yoke", "zerofrom", @@ -6017,17 +8842,17 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] name = "zmij" -version = "1.0.12" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fc5a66a20078bf1251bde995aa2fdcc4b800c70b5d92dd2c62abc5c60f679f8" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/Cargo.toml b/Cargo.toml index 4aa705b1fb..fdf84f17e1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,33 +1,80 @@ [workspace] members = [ "rs/hang", - "rs/hang-cli", + "rs/kio", "rs/libmoq", - "rs/moq-clock", - "rs/moq-lite", + "rs/moq-audio", + "rs/moq-boy", + "rs/moq-cli", + "rs/moq-ffi", + "rs/moq-gst", + "rs/moq-loc", + "rs/moq-msf", + "rs/moq-mux", "rs/moq-native", + "rs/moq-net", "rs/moq-relay", "rs/moq-token", "rs/moq-token-cli", + "rs/moq-video", +] +default-members = [ + "rs/kio", + "rs/hang", + # "rs/libmoq", # requires C toolchain + "rs/moq-boy", + "rs/moq-audio", + "rs/moq-cli", + # "rs/moq-ffi", # requires Python/maturin + # "rs/moq-gst", # requires GStreamer + "rs/moq-loc", + "rs/moq-msf", + "rs/moq-net", + "rs/moq-mux", + "rs/moq-native", + "rs/moq-relay", + "rs/moq-token", + "rs/moq-token-cli", + "rs/moq-video", ] resolver = "2" +[workspace.package] +rust-version = "1.85" + [workspace.dependencies] -hang = { version = "0.10", path = "rs/hang" } -moq-lite = { version = "0.11", path = "rs/moq-lite" } -moq-native = { version = "0.11", path = "rs/moq-native" } -moq-token = { version = "0.5", path = "rs/moq-token" } +hang = { version = "0.18", path = "rs/hang" } +kio = { version = "0.3", path = "rs/kio" } +moq-audio = { version = "0.0.1", path = "rs/moq-audio" } +moq-loc = { version = "0.1", path = "rs/moq-loc" } +moq-msf = { version = "0.2", path = "rs/moq-msf" } +moq-mux = { version = "0.5", path = "rs/moq-mux" } +moq-native = { version = "0.16", path = "rs/moq-native", default-features = false } +moq-net = { version = "0.1", path = "rs/moq-net" } +moq-token = { version = "0.6", path = "rs/moq-token" } +qmux = { version = "0.0.7", default-features = false } serde = { version = "1", features = ["derive"] } tokio = "1.48" -web-async = { version = "0.1.1", features = ["tracing"] } -web-transport-iroh = "0.1.1" -web-transport-quinn = "0.10" -web-transport-trait = "0.3" -web-transport-ws = "0.2.2" +web-async = { version = "0.1.3", features = ["tracing"] } +web-transport-iroh = "0.5" +web-transport-noq = "0.0.3" +web-transport-proto = "0.6" +web-transport-quiche = "0.2" +web-transport-quinn = "0.11" +web-transport-trait = "0.3.4" [profile.dev] panic = "abort" [profile.release] panic = "abort" + +[profile.profiling] +inherits = "release" +debug = "line-tables-only" +# frame pointers: pass RUSTFLAGS="-C force-frame-pointers=yes" when building + +[profile.release-with-debug] +inherits = "release" +debug = true diff --git a/README.md b/README.md index c64a2daf76..252bffddc3 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ ![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue) [![Discord](https://img.shields.io/discord/1124083992740761730)](https://discord.gg/FCYF3p99mr) -[![Crates.io](https://img.shields.io/crates/v/moq-lite)](https://crates.io/crates/moq-lite) -[![npm](https://img.shields.io/npm/v/@moq/lite)](https://www.npmjs.com/package/@moq/lite) +[![Crates.io](https://img.shields.io/crates/v/moq-net)](https://crates.io/crates/moq-net) +[![npm](https://img.shields.io/npm/v/@moq/net)](https://www.npmjs.com/package/@moq/net) # Media over QUIC @@ -14,61 +14,73 @@ Built using modern web technologies, MoQ delivers WebRTC-like latency without th The core networking is delegated to a QUIC library but the rest is in application-space, giving you full control over your media pipeline. **Key Features:** -- 🚀 **Real-time latency** using QUIC for priotization and partial reliability. + +- 🚀 **Real-time latency** using QUIC for prioritization and partial reliability. - 📈 **Massive scale** designed for fan-out and supports cross-region clustering. - 🌐 **Modern Web** using [WebTransport](https://developer.mozilla.org/en-US/docs/Web/API/WebTransport_API), [WebCodecs](https://developer.mozilla.org/en-US/docs/Web/API/WebCodecs_API), and [WebAudio](https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API). - 🎯 **Multi-language** with both Rust (native) and TypeScript (web) libraries. - 🔧 **Generic** for any live data, not just media. Includes text chat as both an example and a core feature. -> **Note:** This project is a [fork](https://moq.dev/blog/transfork) of the [IETF MoQ specification](https://datatracker.ietf.org/group/moq/documents/). The focus is narrower, focusing on simplicity and deployability. +> **Note:** This project implements [moq-lite](https://doc.moq.dev/concept/layer/moq-lite), a forwards-compatible subset of the IETF [moq-transport](https://datatracker.ietf.org/doc/draft-ietf-moq-transport/) draft. moq-lite works with any moq-transport CDN (ex. [Cloudflare](https://moq.dev/blog/first-cdn/)). The focus is narrower, prioritizing simplicity and deployability. + +## Installing on Linux +Debian/Ubuntu users can install pre-built packages from `apt.moq.dev`, +Fedora/RHEL/Rocky/AlmaLinux/openSUSE users from `rpm.moq.dev`. The +relay ships with a hardened systemd unit and a default config; the +GStreamer plugin lands in the right multiarch plugin directory and is +visible to `gst-inspect-1.0` after one install. See +[Linux Installation](https://doc.moq.dev/setup/linux) for the apt/dnf +one-liners and the list of available packages. ## Demo + This repository is split into multiple binaries and libraries across different languages. -It can get overwhelming, so there's an included [demo](js/hang-demo) with some examples. +It can get overwhelming, so there's an included [demo](demo/web) with some examples. **Note:** this demo uses an insecure HTTP fetch intended for *local development only*. In production, you'll need a proper domain and a matching TLS certificate via [LetsEncrypt](https://letsencrypt.org/docs/) or similar. - ### Quick Setup + **Requirements:** + - [Nix](https://nixos.org/download.html) - [Nix Flakes enabled](https://nixos.wiki/wiki/Flakes) ```sh # Runs a relay, demo media, and the web server -nix develop -c just dev +nix develop -c just ``` -Then visit [https://localhost:8080](https://localhost:8080) to see the demo. +Then visit to see the demo. Note that this uses an insecure HTTP fetch for local development only; in production you'll need a proper domain + TLS certificate. -*TIP:* If you've installed [nix-direnv](https://github.com/nix-community/nix-direnv), then only `just dev` is required. - +*TIP:* If you've installed [nix-direnv](https://github.com/nix-community/nix-direnv), then only `just` is required. ### Full Setup + If you don't like Nix, then you can install dependencies manually: **Requirements:** + - [Just](https://github.com/casey/just) - [Rust](https://www.rust-lang.org/tools/install) - [Bun](https://bun.sh/) - [FFmpeg](https://ffmpeg.org/download.html) -- [Deno](https://deno.com/runtime) (optional) - ...probably some other stuff **Run it:** + ```sh # Install some more dependencies just install # Runs a relay, demo media, and the web server -just dev +just ``` -Then visit [https://localhost:8080](https://localhost:8080) to see the demo. - +Then visit to see the demo. ## Architecture @@ -77,7 +89,7 @@ MoQ is designed as a layered protocol stack. **Rule 1**: The CDN MUST NOT know anything about your application, media codecs, or even the available tracks. Everything could be fully E2EE and the CDN wouldn't care. **No business logic allowed**. -Instead, [`moq-relay`](rs/moq-relay) operates on rules encoded in the [`moq-lite`](https://docs.rs/moq-lite) header. +Instead, [`moq-relay`](rs/moq-relay) operates on rules encoded in the [`moq-net`](https://docs.rs/moq-net) header. These rules are based on video encoding but are generic enough to be used for any live data. The goal is to keep the server as dumb as possible while supporting a wide range of use-cases. @@ -87,7 +99,6 @@ If you want to do something more custom, then you can always extend it or replac Think of `hang` as like HLS/DASH, while `moq-lite` is like HTTP. - ``` ┌─────────────────┐ │ Application │ 🏢 Your business logic @@ -104,46 +115,52 @@ Think of `hang` as like HLS/DASH, while `moq-lite` is like HTTP. └─────────────────┘ ``` - ## Libraries -This repository provides both [Rust](/rs) and [TypeScript](/js) libraries with similar APIs but language-specific optimizations. + +This repository provides both [Rust](rs) and [TypeScript](js) libraries with similar APIs but language-specific optimizations. ### Rust + | Crate | Description | Docs | |-----------------------------|---------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------| -| [moq-lite](rs/moq-lite) | The core pub/sub transport protocol. Has built-in concurrency and deduplication. | [![docs.rs](https://docs.rs/moq-lite/badge.svg)](https://docs.rs/moq-lite) | +| [moq-net](rs/moq-net) | The networking layer: real-time pub/sub with built-in caching, fan-out, and prioritization. Negotiates either the `moq-lite` or `moq-transport` wire protocol. | [![docs.rs](https://docs.rs/moq-net/badge.svg)](https://docs.rs/moq-net) | | [moq-relay](rs/moq-relay) | A clusterable relay server. This relay performs fan-out connecting multiple clients and servers together. | | | [moq-token](rs/moq-token) | An authentication scheme supported by `moq-relay`. Can be used as a library or as [a CLI](rs/moq-token-cli) to authenticate sessions. | | | [moq-native](rs/moq-native) | Opinionated helpers to configure a Quinn QUIC endpoint. It's harder than it should be. | [![docs.rs](https://docs.rs/moq-native/badge.svg)](https://docs.rs/moq-native) | -| [libmoq](rs/libmoq) | C bindings for `moq-lite`. | [![docs.rs](https://docs.rs/libmoq/badge.svg)](https://docs.rs/libmoq) | -| [hang](rs/hang) | Media-specific encoding/streaming layered on top of `moq-lite`. Can be used as a library or [a CLI](rs/hang-cli). | [![docs.rs](https://docs.rs/hang/badge.svg)](https://docs.rs/hang) | -| [hang-gst](https://github.com/moq-dev/gstreamer) | A GStreamer plugin for publishing or consuming hang broadcasts. A separate repo to avoid requiring gstreamer as a build dependency. | | - +| [libmoq](rs/libmoq) | C bindings for `moq-net`. | [![docs.rs](https://docs.rs/libmoq/badge.svg)](https://docs.rs/libmoq) | +| [hang](rs/hang) | Media-specific encoding/streaming layered on top of `moq-net`. Can be used as a library. | [![docs.rs](https://docs.rs/hang/badge.svg)](https://docs.rs/hang) | +| [moq-cli](rs/moq-cli) | A CLI for publishing media to MoQ relays. | | +| [moq-mux](rs/moq-mux) | Media muxers and demuxers (fMP4/CMAF, HLS) for importing content into MoQ broadcasts. | [![docs.rs](https://docs.rs/moq-mux/badge.svg)](https://docs.rs/moq-mux) | +| [moq-gst](rs/moq-gst) | A GStreamer plugin for publishing or consuming MoQ broadcasts. Not built by default; requires GStreamer dev libraries. | | ### TypeScript | Package | Description | NPM | |------------------------------------------|--------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------| -| **[@moq/lite](js/lite)** | The core pub/sub transport protocol. Intended for browsers, but can be run server-side using [Deno](https://deno.com/). | [![npm](https://img.shields.io/npm/v/@moq/lite)](https://www.npmjs.com/package/@moq/lite) | -| **[@moq/token](js/token)** | Authentication library & CLI for JS/TS environments (see [Authentication](doc/concepts/authentication.md)) | [![npm](https://img.shields.io/npm/v/@moq/token)](https://www.npmjs.com/package/@moq/token) | -| **[@moq/hang](js/hang)** | Media-specific encoding/streaming layered on top of `moq-lite`. Provides both a Javascript API and Web Components. | [![npm](https://img.shields.io/npm/v/@moq/hang)](https://www.npmjs.com/package/@moq/hang) | -| **[@moq/hang-demo](js/hang-demo)** | Examples using `@moq/hang`. | | -| **[@moq/hang-ui](js/hang-ui)**. | UI Components that interact with the Hang Web Components using SolidJS. | [![npm](https://img.shields.io/npm/v/@moq/hang-ui)](https://www.npmjs.com/package/@moq/hang-ui) | - +| **[@moq/net](js/net)** | The networking layer: real-time pub/sub with built-in caching, fan-out, and prioritization. Negotiates either the `moq-lite` or `moq-transport` wire protocol. Intended for browsers, runs server-side with a WebTransport polyfill. | [![npm](https://img.shields.io/npm/v/@moq/net)](https://www.npmjs.com/package/@moq/net) | +| **[@moq/token](js/token)** | Authentication library & CLI for JS/TS environments (see [Authentication](doc/app/relay/auth.md)) | [![npm](https://img.shields.io/npm/v/@moq/token)](https://www.npmjs.com/package/@moq/token) | +| **[@moq/hang](js/hang)** | Core media library: catalog, container, and support. Shared by `@moq/watch` and `@moq/publish`. | [![npm](https://img.shields.io/npm/v/@moq/hang)](https://www.npmjs.com/package/@moq/hang) | +| **[@moq/demo](demo/web)** | Examples using `@moq/hang`. | | +| **[@moq/watch](js/watch)** | Subscribe to and render MoQ broadcasts (Web Component + JS API). | [![npm](https://img.shields.io/npm/v/@moq/watch)](https://www.npmjs.com/package/@moq/watch) | +| **[@moq/publish](js/publish)** | Publish media to MoQ broadcasts (Web Component + JS API). | [![npm](https://img.shields.io/npm/v/@moq/publish)](https://www.npmjs.com/package/@moq/publish) | +| **[@moq/ui-core](js/ui-core)** | Shared UI components (Button, Icon, Stats, CSS theme) used by `@moq/watch/ui` and `@moq/publish/ui`. | [![npm](https://img.shields.io/npm/v/@moq/ui-core)](https://www.npmjs.com/package/@moq/ui-core) | ## Documentation -Additional documentation and implementation details: -- **[Authentication](doc/concepts/authentication.md)** - JWT tokens, authorization, and security +Additional documentation and implementation details: +- **[Authentication](doc/app/relay/auth.md)** - JWT tokens, authorization, and security ## Protocol + Read the specifications: + - [moq-lite](https://moq-dev.github.io/drafts/draft-lcurley-moq-lite.html) - [hang](https://moq-dev.github.io/drafts/draft-lcurley-moq-hang.html) - [use-cases](https://moq-dev.github.io/drafts/draft-lcurley-moq-use-cases.html) ## Development + ```sh # See all available commands just @@ -163,7 +180,7 @@ just pub tos # Terminal 2: Publish a demo video using ffmpeg just web # Terminal 3: Start web server ``` -There are more commands: check out the [justfile](justfile), [rs/justfile](rs/justfile), and [js/justfile](js/justfile). +There are more commands: check out the [justfile](justfile). ## Iroh support @@ -171,10 +188,10 @@ The `moq-native` and `moq-relay` crates optionally support connecting via [iroh] When the iroh feature is enabled, you can connect to iroh endpoints with these URLs: -* `iroh://`: Connect via moq-lite over raw QUIC. -* `moql+iroh://`: Connect via moq-lite over raw QUIC (same as above) -* `moqt+iroh://`: Connect via IETF MoQ over raw QUIC -* `h3+iroh:///optional/path?with=query`: Connect via WebTransport over HTTP/3. +- `iroh://`: Connect via moq-lite over raw QUIC. +- `moql+iroh://`: Connect via moq-lite over raw QUIC (same as above) +- `moqt+iroh://`: Connect via IETF MoQ over raw QUIC +- `h3+iroh:///optional/path?with=query`: Connect via WebTransport over HTTP/3. `ENDPOINT_ID` must be the hex-encoded iroh endpoint id. It is currently not possible to set direct addresses or iroh relay URLs. The iroh integration in moq-native uses iroh's default discovery mechanisms to discover other endpoints by their endpoint id. @@ -192,10 +209,10 @@ just relay --iroh-enabled # We set an `anon/` prefix to match the broadcast name the web ui expects # Because moq-lite does not have headers if using raw QUIC, only the hostname # in the URL can be used. -just pub bbb iroh://ENDPOINT_ID/anon --iroh-enabled +just pub-iroh bbb iroh://ENDPOINT_ID anon/ # Alternatively you can use WebTransport over HTTP/3 over iroh, # which allows to set a path prefix in the URL: -just pub bbb h3+iroh://ENDPOINT_ID/anon --iroh-enabled +just pub-iroh bbb h3+iroh://ENDPOINT_ID/anon # Terminal 3: Start web server just web @@ -203,10 +220,11 @@ just web Then open [localhost:5173](http://localhost:5173) and watch BBB, pushed from terminal 1 via iroh to the relay running in terminal 2, from where the browser fetches it over regular WebTransport. -`just serve` serves a video via iroh alongside regular QUIC (it enables the `iroh` feature). This repo currently does not provide a native viewer, so you can't subscribe to it directly. However, you can use the [watch example from iroh-live](https://github.com/n0-computer/iroh-live/blob/main/iroh-live/examples/watch.rs) to view a video published via `hang-native`. +`just serve` serves a video via iroh alongside regular QUIC (it enables the `iroh` feature). This repo currently does not provide a native viewer, so you can't subscribe to it directly. However, you can use the [watch example from iroh-live](https://github.com/n0-computer/iroh-live/blob/main/iroh-live/examples/watch.rs) to view a video published via `moq-native`. ## License Licensed under either: -- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or https://www.apache.org/licenses/LICENSE-2.0) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or https://opensource.org/licenses/MIT) diff --git a/biome.jsonc b/biome.jsonc index 52050a8d28..ebca15ef6d 100644 --- a/biome.jsonc +++ b/biome.jsonc @@ -1,6 +1,6 @@ // This has to be in the root otherwise the VSCode plugin will not work out of the box. { - "$schema": "https://biomejs.dev/schemas/2.3.11/schema.json", + "$schema": "./node_modules/@biomejs/biome/configuration_schema.json", "vcs": { "enabled": true, "clientKind": "git", diff --git a/bun.lock b/bun.lock index 99fb7edc52..465739ff4a 100644 --- a/bun.lock +++ b/bun.lock @@ -1,12 +1,56 @@ { "lockfileVersion": 1, - "configVersion": 1, + "configVersion": 0, "workspaces": { "": { "name": "moq", "devDependencies": { - "@biomejs/biome": "^2.3.11", + "@biomejs/biome": "^2.4.10", "concurrently": "^9.2.1", + "publint": "^0.3.18", + "remark-cli": "^12.0.1", + "remark-frontmatter": "^5.0.0", + "remark-lint-list-item-indent": "^4.0.1", + "remark-lint-maximum-line-length": "^4.1.1", + "remark-lint-no-duplicate-headings": "^4.0.1", + "remark-lint-no-undefined-references": "^5.0.2", + "remark-preset-lint-consistent": "^6.0.1", + "remark-preset-lint-recommended": "^7.0.1", + "remark-stringify": "^11.0.0", + }, + }, + "demo/boy": { + "name": "@moq/demo-boy", + "version": "0.2.0", + "dependencies": { + "@moq/boy": "workspace:^", + }, + "devDependencies": { + "esbuild": "^0.27.0", + "typescript": "^6.0.0", + "vite": "^7.3.1", + "vite-plugin-solid": "^2.11.10", + }, + }, + "demo/web": { + "name": "@moq/demo", + "version": "0.1.1", + "dependencies": { + "@moq/hang": "workspace:^", + "@moq/publish": "workspace:^", + "@moq/watch": "workspace:^", + }, + "devDependencies": { + "@tailwindcss/typography": "^0.5.16", + "@tailwindcss/vite": "^4.1.13", + "esbuild": "^0.27.0", + "highlight.js": "^11.11.1", + "solid-element": "^1.9.1", + "solid-js": "^1.9.10", + "tailwindcss": "^4.1.13", + "typescript": "^6.0.0", + "vite": "^7.3.1", + "vite-plugin-solid": "^2.11.10", }, }, "doc": { @@ -24,105 +68,124 @@ "moq-clock": "./src/main.ts", }, "dependencies": { - "@moq/lite": "workspace:*", + "@fails-components/webtransport": "^1.5.2", + "@fails-components/webtransport-transport-http3-quiche": "^1.5.2", + "@moq/net": "workspace:*", }, "devDependencies": { - "@types/deno": "^2.3.0", - "typescript": "^5.9.2", + "@types/node": "^24.3.1", + "typescript": "^6.0.0", }, }, "js/hang": { "name": "@moq/hang", - "version": "0.1.1", + "version": "0.2.7", "dependencies": { "@kixelated/libavjs-webcodecs-polyfill": "^0.5.5", "@libav.js/variant-opus-af": "^6.8.8", - "@moq/lite": "workspace:^", + "@moq/loc": "workspace:^", + "@moq/net": "workspace:^", "@moq/signals": "workspace:^", - "async-mutex": "^0.5.0", - "comlink": "^4.4.2", + "@svta/cml-iso-bmff": "^1.0.0-alpha.9", "zod": "^4.1.5", }, "devDependencies": { "@types/audioworklet": "^0.0.77", + "@types/bun": "^1.3.11", "@typescript/lib-dom": "npm:@types/web@^0.0.241", "fast-glob": "^3.3.3", "rimraf": "^6.0.1", - "typescript": "^5.9.2", - "vitest": "^3.2.4", + "typescript": "^6.0.0", }, }, - "js/hang-demo": { - "name": "@moq/hang-demo", + "js/loc": { + "name": "@moq/loc", "version": "0.1.0", "dependencies": { - "@moq/hang": "workspace:^", - "@moq/hang-ui": "workspace:^", + "@moq/net": "workspace:^", }, "devDependencies": { - "@tailwindcss/typography": "^0.5.16", - "@tailwindcss/vite": "^4.1.13", - "highlight.js": "^11.11.1", - "tailwindcss": "^4.1.13", - "typescript": "^5.9.2", - "vite": "^6.3.6", - "vite-plugin-solid": "^2.11.10", + "@types/bun": "^1.3.11", + "rimraf": "^6.0.1", + "typescript": "^6.0.0", }, }, - "js/hang-ui": { - "name": "@moq/hang-ui", - "version": "0.1.1", + "js/moq-boy": { + "name": "@moq/boy", + "version": "0.2.10", + "dependencies": { + "@moq/net": "workspace:^", + "@moq/signals": "workspace:^", + "@moq/watch": "workspace:^", + "zod": "^4.3.6", + }, "devDependencies": { - "@solidjs/testing-library": "^0.8.10", - "@testing-library/jest-dom": "^6.9.1", - "happy-dom": "^20.0.11", + "@types/bun": "^1.3.11", + "esbuild": "^0.27.0", "rimraf": "^6.0.1", - "solid-element": "^1.9.1", "solid-js": "^1.9.10", - "typescript": "^5.9.2", - "unplugin-solid": "^1.0.0", + "typescript": "^6.0.0", "vite": "^7.3.1", "vite-plugin-solid": "^2.11.10", - "vitest": "^3.2.4", - }, - "peerDependencies": { - "@moq/hang": "workspace:^0.1.0", - "@moq/signals": "workspace:^0.1.0", }, }, - "js/lite": { - "name": "@moq/lite", + "js/msf": { + "name": "@moq/msf", "version": "0.1.1", "dependencies": { + "@moq/net": "workspace:^", + "zod": "^4.1.5", + }, + "devDependencies": { + "rimraf": "^6.0.1", + "typescript": "^6.0.0", + }, + }, + "js/net": { + "name": "@moq/net", + "version": "0.1.2", + "dependencies": { + "@moq/qmux": "^0.0.6", "@moq/signals": "workspace:*", - "@moq/web-transport-ws": "^0.1.2", "async-mutex": "^0.5.0", }, "devDependencies": { - "@types/deno": "^2.3.0", + "@types/bun": "^1.3.11", "@types/node": "^24.3.1", "@typescript/lib-dom": "npm:@types/web@^0.0.241", - "madge": "^8.0.0", "rimraf": "^6.0.1", - "typescript": "^5.9.2", - "vite": "^6.3.6", + "typescript": "^6.0.0", "vite-plugin-html": "^3.2.2", }, "peerDependencies": { - "zod": "^4.1.0", + "zod": "^4.0.0", }, }, - "js/signals": { - "name": "@moq/signals", - "version": "0.1.0", + "js/publish": { + "name": "@moq/publish", + "version": "0.2.9", "dependencies": { - "dequal": "^2.0.3", + "@moq/hang": "workspace:^", + "@moq/net": "workspace:^", + "@moq/signals": "workspace:^", }, + "devDependencies": { + "@types/audioworklet": "^0.0.77", + "@typescript/lib-dom": "npm:@types/web@^0.0.241", + "esbuild": "^0.27.0", + "rimraf": "^6.0.1", + "typescript": "^6.0.0", + "vite": "^7.3.1", + }, + }, + "js/signals": { + "name": "@moq/signals", + "version": "0.1.7", "devDependencies": { "@types/react": "^19.1.8", "rimraf": "^6.0.1", "solid-js": "^1.9.7", - "typescript": "^5.9.2", + "typescript": "^6.0.0", }, "peerDependencies": { "@types/react": "^19.1.8", @@ -130,13 +193,14 @@ "solid-js": "^1.9.7", }, "optionalPeers": [ + "@types/react", "react", "solid-js", ], }, "js/token": { "name": "@moq/token", - "version": "0.1.1", + "version": "0.2.3", "bin": { "moq-token": "./src/cli.ts", }, @@ -147,15 +211,37 @@ "zod": "^4.1.5", }, "devDependencies": { + "@types/bun": "^1.3.11", "@types/node": "^24.3.1", - "typescript": "^5.9.2", + "rimraf": "^6.0.1", + "typescript": "^6.0.0", + }, + }, + "js/watch": { + "name": "@moq/watch", + "version": "0.2.13", + "dependencies": { + "@moq/hang": "workspace:^", + "@moq/msf": "workspace:^", + "@moq/net": "workspace:^", + "@moq/signals": "workspace:^", + }, + "devDependencies": { + "@types/audioworklet": "^0.0.77", + "@types/bun": "^1.3.11", + "@typescript/lib-dom": "npm:@types/web@^0.0.241", + "esbuild": "^0.27.0", + "rimraf": "^6.0.1", + "typescript": "^6.0.0", + "vite": "^7.3.1", }, }, }, + "trustedDependencies": [ + "@fails-components/webtransport-transport-http3-quiche", + ], "packages": { - "@adobe/css-tools": ["@adobe/css-tools@4.4.4", "", {}, "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg=="], - - "@algolia/abtesting": ["@algolia/abtesting@1.12.2", "", { "dependencies": { "@algolia/client-common": "5.46.2", "@algolia/requester-browser-xhr": "5.46.2", "@algolia/requester-fetch": "5.46.2", "@algolia/requester-node-http": "5.46.2" } }, "sha512-oWknd6wpfNrmRcH0vzed3UPX0i17o4kYLM5OMITyMVM2xLgaRbIafoxL0e8mcrNNb0iORCJA0evnNDKRYth5WQ=="], + "@algolia/abtesting": ["@algolia/abtesting@1.14.1", "", { "dependencies": { "@algolia/client-common": "5.48.1", "@algolia/requester-browser-xhr": "5.48.1", "@algolia/requester-fetch": "5.48.1", "@algolia/requester-node-http": "5.48.1" } }, "sha512-Dkj0BgPiLAaim9sbQ97UKDFHJE/880wgStAM18U++NaJ/2Cws34J5731ovJifr6E3Pv4T2CqvMXf8qLCC417Ew=="], "@algolia/autocomplete-core": ["@algolia/autocomplete-core@1.17.7", "", { "dependencies": { "@algolia/autocomplete-plugin-algolia-insights": "1.17.7", "@algolia/autocomplete-shared": "1.17.7" } }, "sha512-BjiPOW6ks90UKl7TwMv7oNQMnzU+t/wk9mgIDi6b1tXpUek7MW0lbNOUHpvam9pe3lVCf4xPFT+lK7s+e+fs7Q=="], @@ -165,49 +251,49 @@ "@algolia/autocomplete-shared": ["@algolia/autocomplete-shared@1.17.7", "", { "peerDependencies": { "@algolia/client-search": ">= 4.9.1 < 6", "algoliasearch": ">= 4.9.1 < 6" } }, "sha512-o/1Vurr42U/qskRSuhBH+VKxMvkkUVTLU6WZQr+L5lGZZLYWyhdzWjW0iGXY7EkwRTjBqvN2EsR81yCTGV/kmg=="], - "@algolia/client-abtesting": ["@algolia/client-abtesting@5.46.2", "", { "dependencies": { "@algolia/client-common": "5.46.2", "@algolia/requester-browser-xhr": "5.46.2", "@algolia/requester-fetch": "5.46.2", "@algolia/requester-node-http": "5.46.2" } }, "sha512-oRSUHbylGIuxrlzdPA8FPJuwrLLRavOhAmFGgdAvMcX47XsyM+IOGa9tc7/K5SPvBqn4nhppOCEz7BrzOPWc4A=="], + "@algolia/client-abtesting": ["@algolia/client-abtesting@5.48.1", "", { "dependencies": { "@algolia/client-common": "5.48.1", "@algolia/requester-browser-xhr": "5.48.1", "@algolia/requester-fetch": "5.48.1", "@algolia/requester-node-http": "5.48.1" } }, "sha512-LV5qCJdj+/m9I+Aj91o+glYszrzd7CX6NgKaYdTOj4+tUYfbS62pwYgUfZprYNayhkQpVFcrW8x8ZlIHpS23Vw=="], - "@algolia/client-analytics": ["@algolia/client-analytics@5.46.2", "", { "dependencies": { "@algolia/client-common": "5.46.2", "@algolia/requester-browser-xhr": "5.46.2", "@algolia/requester-fetch": "5.46.2", "@algolia/requester-node-http": "5.46.2" } }, "sha512-EPBN2Oruw0maWOF4OgGPfioTvd+gmiNwx0HmD9IgmlS+l75DatcBkKOPNJN+0z3wBQWUO5oq602ATxIfmTQ8bA=="], + "@algolia/client-analytics": ["@algolia/client-analytics@5.48.1", "", { "dependencies": { "@algolia/client-common": "5.48.1", "@algolia/requester-browser-xhr": "5.48.1", "@algolia/requester-fetch": "5.48.1", "@algolia/requester-node-http": "5.48.1" } }, "sha512-/AVoMqHhPm14CcHq7mwB+bUJbfCv+jrxlNvRjXAuO+TQa+V37N8k1b0ijaRBPdmSjULMd8KtJbQyUyabXOu6Kg=="], - "@algolia/client-common": ["@algolia/client-common@5.46.2", "", {}, "sha512-Hj8gswSJNKZ0oyd0wWissqyasm+wTz1oIsv5ZmLarzOZAp3vFEda8bpDQ8PUhO+DfkbiLyVnAxsPe4cGzWtqkg=="], + "@algolia/client-common": ["@algolia/client-common@5.48.1", "", {}, "sha512-VXO+qu2Ep6ota28ktvBm3sG53wUHS2n7bgLWmce5jTskdlCD0/JrV4tnBm1l7qpla1CeoQb8D7ShFhad+UoSOw=="], - "@algolia/client-insights": ["@algolia/client-insights@5.46.2", "", { "dependencies": { "@algolia/client-common": "5.46.2", "@algolia/requester-browser-xhr": "5.46.2", "@algolia/requester-fetch": "5.46.2", "@algolia/requester-node-http": "5.46.2" } }, "sha512-6dBZko2jt8FmQcHCbmNLB0kCV079Mx/DJcySTL3wirgDBUH7xhY1pOuUTLMiGkqM5D8moVZTvTdRKZUJRkrwBA=="], + "@algolia/client-insights": ["@algolia/client-insights@5.48.1", "", { "dependencies": { "@algolia/client-common": "5.48.1", "@algolia/requester-browser-xhr": "5.48.1", "@algolia/requester-fetch": "5.48.1", "@algolia/requester-node-http": "5.48.1" } }, "sha512-zl+Qyb0nLg+Y5YvKp1Ij+u9OaPaKg2/EPzTwKNiVyOHnQJlFxmXyUZL1EInczAZsEY8hVpPCLtNfhMhfxluXKQ=="], - "@algolia/client-personalization": ["@algolia/client-personalization@5.46.2", "", { "dependencies": { "@algolia/client-common": "5.46.2", "@algolia/requester-browser-xhr": "5.46.2", "@algolia/requester-fetch": "5.46.2", "@algolia/requester-node-http": "5.46.2" } }, "sha512-1waE2Uqh/PHNeDXGn/PM/WrmYOBiUGSVxAWqiJIj73jqPqvfzZgzdakHscIVaDl6Cp+j5dwjsZ5LCgaUr6DtmA=="], + "@algolia/client-personalization": ["@algolia/client-personalization@5.48.1", "", { "dependencies": { "@algolia/client-common": "5.48.1", "@algolia/requester-browser-xhr": "5.48.1", "@algolia/requester-fetch": "5.48.1", "@algolia/requester-node-http": "5.48.1" } }, "sha512-r89Qf9Oo9mKWQXumRu/1LtvVJAmEDpn8mHZMc485pRfQUMAwSSrsnaw1tQ3sszqzEgAr1c7rw6fjBI+zrAXTOw=="], - "@algolia/client-query-suggestions": ["@algolia/client-query-suggestions@5.46.2", "", { "dependencies": { "@algolia/client-common": "5.46.2", "@algolia/requester-browser-xhr": "5.46.2", "@algolia/requester-fetch": "5.46.2", "@algolia/requester-node-http": "5.46.2" } }, "sha512-EgOzTZkyDcNL6DV0V/24+oBJ+hKo0wNgyrOX/mePBM9bc9huHxIY2352sXmoZ648JXXY2x//V1kropF/Spx83w=="], + "@algolia/client-query-suggestions": ["@algolia/client-query-suggestions@5.48.1", "", { "dependencies": { "@algolia/client-common": "5.48.1", "@algolia/requester-browser-xhr": "5.48.1", "@algolia/requester-fetch": "5.48.1", "@algolia/requester-node-http": "5.48.1" } }, "sha512-TPKNPKfghKG/bMSc7mQYD9HxHRUkBZA4q1PEmHgICaSeHQscGqL4wBrKkhfPlDV1uYBKW02pbFMUhsOt7p4ZpA=="], - "@algolia/client-search": ["@algolia/client-search@5.46.2", "", { "dependencies": { "@algolia/client-common": "5.46.2", "@algolia/requester-browser-xhr": "5.46.2", "@algolia/requester-fetch": "5.46.2", "@algolia/requester-node-http": "5.46.2" } }, "sha512-ZsOJqu4HOG5BlvIFnMU0YKjQ9ZI6r3C31dg2jk5kMWPSdhJpYL9xa5hEe7aieE+707dXeMI4ej3diy6mXdZpgA=="], + "@algolia/client-search": ["@algolia/client-search@5.48.1", "", { "dependencies": { "@algolia/client-common": "5.48.1", "@algolia/requester-browser-xhr": "5.48.1", "@algolia/requester-fetch": "5.48.1", "@algolia/requester-node-http": "5.48.1" } }, "sha512-4Fu7dnzQyQmMFknYwTiN/HxPbH4DyxvQ1m+IxpPp5oslOgz8m6PG5qhiGbqJzH4HiT1I58ecDiCAC716UyVA8Q=="], - "@algolia/ingestion": ["@algolia/ingestion@1.46.2", "", { "dependencies": { "@algolia/client-common": "5.46.2", "@algolia/requester-browser-xhr": "5.46.2", "@algolia/requester-fetch": "5.46.2", "@algolia/requester-node-http": "5.46.2" } }, "sha512-1Uw2OslTWiOFDtt83y0bGiErJYy5MizadV0nHnOoHFWMoDqWW0kQoMFI65pXqRSkVvit5zjXSLik2xMiyQJDWQ=="], + "@algolia/ingestion": ["@algolia/ingestion@1.48.1", "", { "dependencies": { "@algolia/client-common": "5.48.1", "@algolia/requester-browser-xhr": "5.48.1", "@algolia/requester-fetch": "5.48.1", "@algolia/requester-node-http": "5.48.1" } }, "sha512-/RFq3TqtXDUUawwic/A9xylA2P3LDMO8dNhphHAUOU51b1ZLHrmZ6YYJm3df1APz7xLY1aht6okCQf+/vmrV9w=="], - "@algolia/monitoring": ["@algolia/monitoring@1.46.2", "", { "dependencies": { "@algolia/client-common": "5.46.2", "@algolia/requester-browser-xhr": "5.46.2", "@algolia/requester-fetch": "5.46.2", "@algolia/requester-node-http": "5.46.2" } }, "sha512-xk9f+DPtNcddWN6E7n1hyNNsATBCHIqAvVGG2EAGHJc4AFYL18uM/kMTiOKXE/LKDPyy1JhIerrh9oYb7RBrgw=="], + "@algolia/monitoring": ["@algolia/monitoring@1.48.1", "", { "dependencies": { "@algolia/client-common": "5.48.1", "@algolia/requester-browser-xhr": "5.48.1", "@algolia/requester-fetch": "5.48.1", "@algolia/requester-node-http": "5.48.1" } }, "sha512-Of0jTeAZRyRhC7XzDSjJef0aBkgRcvRAaw0ooYRlOw57APii7lZdq+layuNdeL72BRq1snaJhoMMwkmLIpJScw=="], - "@algolia/recommend": ["@algolia/recommend@5.46.2", "", { "dependencies": { "@algolia/client-common": "5.46.2", "@algolia/requester-browser-xhr": "5.46.2", "@algolia/requester-fetch": "5.46.2", "@algolia/requester-node-http": "5.46.2" } }, "sha512-NApbTPj9LxGzNw4dYnZmj2BoXiAc8NmbbH6qBNzQgXklGklt/xldTvu+FACN6ltFsTzoNU6j2mWNlHQTKGC5+Q=="], + "@algolia/recommend": ["@algolia/recommend@5.48.1", "", { "dependencies": { "@algolia/client-common": "5.48.1", "@algolia/requester-browser-xhr": "5.48.1", "@algolia/requester-fetch": "5.48.1", "@algolia/requester-node-http": "5.48.1" } }, "sha512-bE7JcpFXzxF5zHwj/vkl2eiCBvyR1zQ7aoUdO+GDXxGp0DGw7nI0p8Xj6u8VmRQ+RDuPcICFQcCwRIJT5tDJFw=="], - "@algolia/requester-browser-xhr": ["@algolia/requester-browser-xhr@5.46.2", "", { "dependencies": { "@algolia/client-common": "5.46.2" } }, "sha512-ekotpCwpSp033DIIrsTpYlGUCF6momkgupRV/FA3m62SreTSZUKjgK6VTNyG7TtYfq9YFm/pnh65bATP/ZWJEg=="], + "@algolia/requester-browser-xhr": ["@algolia/requester-browser-xhr@5.48.1", "", { "dependencies": { "@algolia/client-common": "5.48.1" } }, "sha512-MK3wZ2koLDnvH/AmqIF1EKbJlhRS5j74OZGkLpxI4rYvNi9Jn/C7vb5DytBnQ4KUWts7QsmbdwHkxY5txQHXVw=="], - "@algolia/requester-fetch": ["@algolia/requester-fetch@5.46.2", "", { "dependencies": { "@algolia/client-common": "5.46.2" } }, "sha512-gKE+ZFi/6y7saTr34wS0SqYFDcjHW4Wminv8PDZEi0/mE99+hSrbKgJWxo2ztb5eqGirQTgIh1AMVacGGWM1iw=="], + "@algolia/requester-fetch": ["@algolia/requester-fetch@5.48.1", "", { "dependencies": { "@algolia/client-common": "5.48.1" } }, "sha512-2oDT43Y5HWRSIQMPQI4tA/W+TN/N2tjggZCUsqQV440kxzzoPGsvv9QP1GhQ4CoDa+yn6ygUsGp6Dr+a9sPPSg=="], - "@algolia/requester-node-http": ["@algolia/requester-node-http@5.46.2", "", { "dependencies": { "@algolia/client-common": "5.46.2" } }, "sha512-ciPihkletp7ttweJ8Zt+GukSVLp2ANJHU+9ttiSxsJZThXc4Y2yJ8HGVWesW5jN1zrsZsezN71KrMx/iZsOYpg=="], + "@algolia/requester-node-http": ["@algolia/requester-node-http@5.48.1", "", { "dependencies": { "@algolia/client-common": "5.48.1" } }, "sha512-xcaCqbhupVWhuBP1nwbk1XNvwrGljozutEiLx06mvqDf3o8cHyEgQSHS4fKJM+UAggaWVnnFW+Nne5aQ8SUJXg=="], - "@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="], + "@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], - "@babel/compat-data": ["@babel/compat-data@7.28.5", "", {}, "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA=="], + "@babel/compat-data": ["@babel/compat-data@7.29.0", "", {}, "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg=="], - "@babel/core": ["@babel/core@7.28.5", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.4", "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw=="], + "@babel/core": ["@babel/core@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-module-transforms": "^7.28.6", "@babel/helpers": "^7.28.6", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/traverse": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA=="], - "@babel/generator": ["@babel/generator@7.28.5", "", { "dependencies": { "@babel/parser": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ=="], + "@babel/generator": ["@babel/generator@7.29.1", "", { "dependencies": { "@babel/parser": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw=="], - "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.2", "", { "dependencies": { "@babel/compat-data": "^7.27.2", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ=="], + "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.28.6", "", { "dependencies": { "@babel/compat-data": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA=="], "@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="], - "@babel/helper-module-imports": ["@babel/helper-module-imports@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w=="], + "@babel/helper-module-imports": ["@babel/helper-module-imports@7.28.6", "", { "dependencies": { "@babel/traverse": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw=="], - "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw=="], + "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.6", "", { "dependencies": { "@babel/helper-module-imports": "^7.28.6", "@babel/helper-validator-identifier": "^7.28.5", "@babel/traverse": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA=="], - "@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.27.1", "", {}, "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw=="], + "@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.28.6", "", {}, "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug=="], "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="], @@ -215,56 +301,54 @@ "@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="], - "@babel/helpers": ["@babel/helpers@7.28.4", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.28.4" } }, "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w=="], + "@babel/helpers": ["@babel/helpers@7.28.6", "", { "dependencies": { "@babel/template": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw=="], - "@babel/parser": ["@babel/parser@7.28.5", "", { "dependencies": { "@babel/types": "^7.28.5" }, "bin": "./bin/babel-parser.js" }, "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ=="], + "@babel/parser": ["@babel/parser@7.29.0", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww=="], - "@babel/plugin-syntax-jsx": ["@babel/plugin-syntax-jsx@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w=="], + "@babel/plugin-syntax-jsx": ["@babel/plugin-syntax-jsx@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w=="], - "@babel/runtime": ["@babel/runtime@7.28.4", "", {}, "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ=="], + "@babel/template": ["@babel/template@7.28.6", "", { "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/parser": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ=="], - "@babel/template": ["@babel/template@7.27.2", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" } }, "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw=="], + "@babel/traverse": ["@babel/traverse@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/types": "^7.29.0", "debug": "^4.3.1" } }, "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA=="], - "@babel/traverse": ["@babel/traverse@7.28.5", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", "@babel/types": "^7.28.5", "debug": "^4.3.1" } }, "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ=="], + "@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="], - "@babel/types": ["@babel/types@7.28.5", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA=="], + "@biomejs/biome": ["@biomejs/biome@2.4.10", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.4.10", "@biomejs/cli-darwin-x64": "2.4.10", "@biomejs/cli-linux-arm64": "2.4.10", "@biomejs/cli-linux-arm64-musl": "2.4.10", "@biomejs/cli-linux-x64": "2.4.10", "@biomejs/cli-linux-x64-musl": "2.4.10", "@biomejs/cli-win32-arm64": "2.4.10", "@biomejs/cli-win32-x64": "2.4.10" }, "bin": { "biome": "bin/biome" } }, "sha512-xxA3AphFQ1geij4JTHXv4EeSTda1IFn22ye9LdyVPoJU19fNVl0uzfEuhsfQ4Yue/0FaLs2/ccVi4UDiE7R30w=="], - "@biomejs/biome": ["@biomejs/biome@2.3.11", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.3.11", "@biomejs/cli-darwin-x64": "2.3.11", "@biomejs/cli-linux-arm64": "2.3.11", "@biomejs/cli-linux-arm64-musl": "2.3.11", "@biomejs/cli-linux-x64": "2.3.11", "@biomejs/cli-linux-x64-musl": "2.3.11", "@biomejs/cli-win32-arm64": "2.3.11", "@biomejs/cli-win32-x64": "2.3.11" }, "bin": { "biome": "bin/biome" } }, "sha512-/zt+6qazBWguPG6+eWmiELqO+9jRsMZ/DBU3lfuU2ngtIQYzymocHhKiZRyrbra4aCOoyTg/BmY+6WH5mv9xmQ=="], + "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.4.10", "", { "os": "darwin", "cpu": "arm64" }, "sha512-vuzzI1cWqDVzOMIkYyHbKqp+AkQq4K7k+UCXWpkYcY/HDn1UxdsbsfgtVpa40shem8Kax4TLDLlx8kMAecgqiw=="], - "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.3.11", "", { "os": "darwin", "cpu": "arm64" }, "sha512-/uXXkBcPKVQY7rc9Ys2CrlirBJYbpESEDme7RKiBD6MmqR2w3j0+ZZXRIL2xiaNPsIMMNhP1YnA+jRRxoOAFrA=="], + "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.4.10", "", { "os": "darwin", "cpu": "x64" }, "sha512-14fzASRo+BPotwp7nWULy2W5xeUyFnTaq1V13Etrrxkrih+ez/2QfgFm5Ehtf5vSjtgx/IJycMMpn5kPd5ZNaA=="], - "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.3.11", "", { "os": "darwin", "cpu": "x64" }, "sha512-fh7nnvbweDPm2xEmFjfmq7zSUiox88plgdHF9OIW4i99WnXrAC3o2P3ag9judoUMv8FCSUnlwJCM1B64nO5Fbg=="], + "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.4.10", "", { "os": "linux", "cpu": "arm64" }, "sha512-7MH1CMW5uuxQ/s7FLST63qF8B3Hgu2HRdZ7tA1X1+mk+St4JOuIrqdhIBnnyqeyWJNI+Bww7Es5QZ0wIc1Cmkw=="], - "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.3.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-l4xkGa9E7Uc0/05qU2lMYfN1H+fzzkHgaJoy98wO+b/7Gl78srbCRRgwYSW+BTLixTBrM6Ede5NSBwt7rd/i6g=="], + "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.4.10", "", { "os": "linux", "cpu": "arm64" }, "sha512-WrJY6UuiSD/Dh+nwK2qOTu8kdMDlLV3dLMmychIghHPAysWFq1/DGC1pVZx8POE3ZkzKR3PUUnVrtZfMfaJjyQ=="], - "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.3.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-XPSQ+XIPZMLaZ6zveQdwNjbX+QdROEd1zPgMwD47zvHV+tCGB88VH+aynyGxAHdzL+Tm/+DtKST5SECs4iwCLg=="], + "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.4.10", "", { "os": "linux", "cpu": "x64" }, "sha512-tZLvEEi2u9Xu1zAqRjTcpIDGVtldigVvzug2fTuPG0ME/g8/mXpRPcNgLB22bGn6FvLJpHHnqLnwliOu8xjYrg=="], - "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.3.11", "", { "os": "linux", "cpu": "x64" }, "sha512-/1s9V/H3cSe0r0Mv/Z8JryF5x9ywRxywomqZVLHAoa/uN0eY7F8gEngWKNS5vbbN/BsfpCG5yeBT5ENh50Frxg=="], + "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.4.10", "", { "os": "linux", "cpu": "x64" }, "sha512-kDTi3pI6PBN6CiczsWYOyP2zk0IJI08EWEQyDMQWW221rPaaEz6FvjLhnU07KMzLv8q3qSuoB93ua6inSQ55Tw=="], - "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.3.11", "", { "os": "linux", "cpu": "x64" }, "sha512-vU7a8wLs5C9yJ4CB8a44r12aXYb8yYgBn+WeyzbMjaCMklzCv1oXr8x+VEyWodgJt9bDmhiaW/I0RHbn7rsNmw=="], + "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.4.10", "", { "os": "win32", "cpu": "arm64" }, "sha512-umwQU6qPzH+ISTf/eHyJ/QoQnJs3V9Vpjz2OjZXe9MVBZ7prgGafMy7yYeRGnlmDAn87AKTF3Q6weLoMGpeqdQ=="], - "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.3.11", "", { "os": "win32", "cpu": "arm64" }, "sha512-PZQ6ElCOnkYapSsysiTy0+fYX+agXPlWugh6+eQ6uPKI3vKAqNp6TnMhoM3oY2NltSB89hz59o8xIfOdyhi9Iw=="], + "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.4.10", "", { "os": "win32", "cpu": "x64" }, "sha512-aW/JU5GuyH4uxMrNYpoC2kjaHlyJGLgIa3XkhPEZI0uKhZhJZU8BuEyJmvgzSPQNGozBwWjC972RaNdcJ9KyJg=="], - "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.3.11", "", { "os": "win32", "cpu": "x64" }, "sha512-43VrG813EW+b5+YbDbz31uUsheX+qFKCpXeY9kfdAx+ww3naKxeVkTD9zLIWxUPfJquANMHrmW3wbe/037G0Qg=="], + "@cloudflare/kv-asset-handler": ["@cloudflare/kv-asset-handler@0.4.2", "", {}, "sha512-SIOD2DxrRRwQ+jgzlXCqoEFiKOFqaPjhnNTGKXSRLvp1HiOvapLaFG2kEr9dYQTYe8rKrd9uvDUzmAITeNyaHQ=="], - "@cloudflare/kv-asset-handler": ["@cloudflare/kv-asset-handler@0.4.1", "", { "dependencies": { "mime": "^3.0.0" } }, "sha512-Nu8ahitGFFJztxUml9oD/DLb7Z28C8cd8F46IVQ7y5Btz575pvMY8AqZsXkX7Gds29eCKdMgIHjIvzskHgPSFg=="], + "@cloudflare/unenv-preset": ["@cloudflare/unenv-preset@2.12.1", "", { "peerDependencies": { "unenv": "2.0.0-rc.24", "workerd": "^1.20260115.0" }, "optionalPeers": ["workerd"] }, "sha512-tP/Wi+40aBJovonSNJSsS7aFJY0xjuckKplmzDs2Xat06BJ68B6iG7YDUWXJL8gNn0gqW7YC5WhlYhO3QbugQA=="], - "@cloudflare/unenv-preset": ["@cloudflare/unenv-preset@2.8.0", "", { "peerDependencies": { "unenv": "2.0.0-rc.24", "workerd": "^1.20251202.0" }, "optionalPeers": ["workerd"] }, "sha512-oIAu6EdQ4zJuPwwKr9odIEqd8AV96z1aqi3RBEA4iKaJ+Vd3fvuI6m5EDC7/QCv+oaPIhy1SkYBYxmD09N+oZg=="], + "@cloudflare/workerd-darwin-64": ["@cloudflare/workerd-darwin-64@1.20260212.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-kLxuYutk88Wlo7edp8mlkN68TgZZ9237SUnuX9kNaD5jcOdblUqiBctMRZeRcPsuoX/3g2t0vS4ga02NBEVRNg=="], - "@cloudflare/workerd-darwin-64": ["@cloudflare/workerd-darwin-64@1.20260107.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-Srwe/IukVppkMU2qTndkFaKCmZBI7CnZoq4Y0U0gD/8158VGzMREHTqCii4IcCeHifwrtDqTWu8EcA1VBKI4mg=="], + "@cloudflare/workerd-darwin-arm64": ["@cloudflare/workerd-darwin-arm64@1.20260212.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-fqoqQWMA1D0ZzDOD8sp0allREM2M8GHdpxMXQ8EdZpZ70z5bJbJ9Vr4qe35++FNIZJspsDHfTw3Xm/M4ELm/dQ=="], - "@cloudflare/workerd-darwin-arm64": ["@cloudflare/workerd-darwin-arm64@1.20260107.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-aAYwU7zXW+UZFh/a4vHP5cs1ulTOcDRLzwU9547yKad06RlZ6ioRm7ovjdYvdqdmbI8mPd99v4LN9gMmecazQw=="], + "@cloudflare/workerd-linux-64": ["@cloudflare/workerd-linux-64@1.20260212.0", "", { "os": "linux", "cpu": "x64" }, "sha512-bCSQoZzDzV5MSh4ueWo1DgmOn4Hf3QBu4Yo3eQFXA2llYFIu/sZgRtkEehw1X2/SY5Sn6O0EMCqxJYRf82Wdeg=="], - "@cloudflare/workerd-linux-64": ["@cloudflare/workerd-linux-64@1.20260107.1", "", { "os": "linux", "cpu": "x64" }, "sha512-Wh7xWtFOkk6WY3CXe3lSqZ1anMkFcwy+qOGIjtmvQ/3nCOaG34vKNwPIE9iwryPupqkSuDmEqkosI1UUnSTh1A=="], + "@cloudflare/workerd-linux-arm64": ["@cloudflare/workerd-linux-arm64@1.20260212.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-GPvp1iiKQodtbUDi6OmR5I0vD75lawB54tdYGtmypuHC7ZOI2WhBmhb3wCxgnQNOG1z7mhCQrzRCoqrKwYbVWQ=="], - "@cloudflare/workerd-linux-arm64": ["@cloudflare/workerd-linux-arm64@1.20260107.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-NI0/5rdssdZZKYHxNG4umTmMzODByq86vSCEk8u4HQbGhRCQo7rV1eXn84ntSBdyWBzWdYGISCbeZMsgfIjSTg=="], + "@cloudflare/workerd-windows-64": ["@cloudflare/workerd-windows-64@1.20260212.0", "", { "os": "win32", "cpu": "x64" }, "sha512-wHRI218Xn4ndgWJCUHH4Zx0YlU5q/o6OmcxXkcw95tJOsQn4lDrhppioPh4eScxJZALf2X+ODeZcyQTCq5exGw=="], - "@cloudflare/workerd-windows-64": ["@cloudflare/workerd-windows-64@1.20260107.1", "", { "os": "win32", "cpu": "x64" }, "sha512-gmBMqs606Gd/IhBEBPSL/hJAqy2L8IyPUjKtoqd/Ccy7GQxbSc0rYlRkxbQ9YzmqnuhrTVYvXuLscyWrpmAJkw=="], + "@cloudflare/workers-types": ["@cloudflare/workers-types@4.20260403.1", "", {}, "sha512-p6oSNt3yUwcxSoXZ7qCog7+kgQbkSx1Beoci7TMb/xbRF05VR0cO/p1XUE2SLHZ7IgSIc3tNMpFKa0L0fa3Lzg=="], "@cspotcode/source-map-support": ["@cspotcode/source-map-support@0.8.1", "", { "dependencies": { "@jridgewell/trace-mapping": "0.3.9" } }, "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw=="], - "@dependents/detective-less": ["@dependents/detective-less@5.0.1", "", { "dependencies": { "gonzales-pe": "^4.3.0", "node-source-walk": "^7.0.1" } }, "sha512-Y6+WUMsTFWE5jb20IFP4YGa5IrGY/+a/FbOSjDF/wz9gepU2hwCYSXRHP/vPwBvwcY3SVMASt4yXxbXNXigmZQ=="], - "@docsearch/css": ["@docsearch/css@3.8.2", "", {}, "sha512-y05ayQFyUmCXze79+56v/4HpycYF3uFqB78pLPrSV5ZKAlDuIAAJNhaRi8tTdRNXh05yxX/TyNnzD6LwSM89vQ=="], "@docsearch/js": ["@docsearch/js@3.8.2", "", { "dependencies": { "@docsearch/react": "3.8.2", "preact": "^10.0.0" } }, "sha512-Q5wY66qHn0SwA7Taa0aDbHiJvaFJLOJyHmooQ7y8hlwwQLQ/5WwCcoX0g7ii04Qi2DJlHsd0XXzJ8Ypw9+9YmQ=="], @@ -273,105 +357,121 @@ "@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="], - "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="], + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.3", "", { "os": "aix", "cpu": "ppc64" }, "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg=="], - "@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="], + "@esbuild/android-arm": ["@esbuild/android-arm@0.27.3", "", { "os": "android", "cpu": "arm" }, "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA=="], - "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.12", "", { "os": "android", "cpu": "arm64" }, "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg=="], + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.3", "", { "os": "android", "cpu": "arm64" }, "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg=="], - "@esbuild/android-x64": ["@esbuild/android-x64@0.25.12", "", { "os": "android", "cpu": "x64" }, "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg=="], + "@esbuild/android-x64": ["@esbuild/android-x64@0.27.3", "", { "os": "android", "cpu": "x64" }, "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ=="], - "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg=="], + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg=="], - "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA=="], + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg=="], - "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg=="], + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.3", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w=="], - "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ=="], + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA=="], - "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.12", "", { "os": "linux", "cpu": "arm" }, "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw=="], + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.3", "", { "os": "linux", "cpu": "arm" }, "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw=="], - "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ=="], + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg=="], - "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA=="], + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.3", "", { "os": "linux", "cpu": "ia32" }, "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg=="], - "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng=="], + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA=="], - "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw=="], + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw=="], - "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA=="], + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA=="], - "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w=="], + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ=="], - "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg=="], + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw=="], - "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.12", "", { "os": "linux", "cpu": "x64" }, "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw=="], + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.3", "", { "os": "linux", "cpu": "x64" }, "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA=="], - "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg=="], + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA=="], - "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.12", "", { "os": "none", "cpu": "x64" }, "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ=="], + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.3", "", { "os": "none", "cpu": "x64" }, "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA=="], - "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.12", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A=="], + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.3", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw=="], - "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw=="], + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.3", "", { "os": "openbsd", "cpu": "x64" }, "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ=="], - "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg=="], + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g=="], - "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w=="], + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.3", "", { "os": "sunos", "cpu": "x64" }, "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA=="], - "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg=="], + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA=="], - "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ=="], + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q=="], - "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="], + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.3", "", { "os": "win32", "cpu": "x64" }, "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA=="], + + "@fails-components/webtransport": ["@fails-components/webtransport@1.5.3", "", { "dependencies": { "@types/debug": "^4.1.7", "bindings": "^1.5.0", "debug": "^4.3.4" } }, "sha512-ax+xQPaYm29hSPxEGaFzQkYkpLVsvDjXn3eabn9E0TlESW2y/HRgTIABG73HjypCaHnhDYP8Q6QkN/uWUhQH2A=="], + + "@fails-components/webtransport-transport-http3-quiche": ["@fails-components/webtransport-transport-http3-quiche@1.5.3", "", { "dependencies": { "@types/debug": "^4.1.7", "bindings": "^1.5.0", "cmake-js": "^8.0.0", "debug": "^4.3.4", "node-addon-api": "^7.0.0", "prebuild-install": "^7.1.1" } }, "sha512-PlR/jYHgEwbv6yQywH5D9czRs+2k05Mcc9/6Uh2b0ShCuOxQcbfPgJ9St9r75AMbKcDVu2Ibm0Lmt3JFCB5HEg=="], "@hexagon/base64": ["@hexagon/base64@2.0.4", "", {}, "sha512-H/ZY6rGyaEuk0mwQgZ3BVi9hMjFTYpBNFbmtOuec/pPibuGhCMXd8fGtwBaO0h44FkWMurysMsDrpkJsBRmoWQ=="], - "@iconify-json/simple-icons": ["@iconify-json/simple-icons@1.2.65", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-v/O0UeqrDz6ASuRVE5g2Puo5aWyej4M/CxX6WYDBARgswwxK0mp3VQbGgPFEAAUU9QN02IjTgjMuO021gpWf2w=="], + "@iconify-json/simple-icons": ["@iconify-json/simple-icons@1.2.70", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-CYNRCgN6nBTjN4dNkrBCjHXNR2e4hQihdsZUs/afUNFOWLSYjfihca4EFN05rRvDk4Xoy2n8tym6IxBZmcn+Qg=="], "@iconify/types": ["@iconify/types@2.0.0", "", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="], - "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.0.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ=="], + "@img/colour": ["@img/colour@1.0.0", "", {}, "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw=="], + + "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.2.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w=="], + + "@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.2.4" }, "os": "darwin", "cpu": "x64" }, "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw=="], + + "@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.2.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g=="], + + "@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.2.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg=="], + + "@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.2.4", "", { "os": "linux", "cpu": "arm" }, "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A=="], - "@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.0.4" }, "os": "darwin", "cpu": "x64" }, "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q=="], + "@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw=="], - "@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.0.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg=="], + "@img/sharp-libvips-linux-ppc64": ["@img/sharp-libvips-linux-ppc64@1.2.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA=="], - "@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.0.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ=="], + "@img/sharp-libvips-linux-riscv64": ["@img/sharp-libvips-linux-riscv64@1.2.4", "", { "os": "linux", "cpu": "none" }, "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA=="], - "@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.0.5", "", { "os": "linux", "cpu": "arm" }, "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g=="], + "@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.2.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ=="], - "@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.0.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA=="], + "@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw=="], - "@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.0.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA=="], + "@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw=="], - "@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.0.4", "", { "os": "linux", "cpu": "x64" }, "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw=="], + "@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg=="], - "@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.0.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA=="], + "@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.2.4" }, "os": "linux", "cpu": "arm" }, "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw=="], - "@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.0.4", "", { "os": "linux", "cpu": "x64" }, "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw=="], + "@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg=="], - "@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.0.5" }, "os": "linux", "cpu": "arm" }, "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ=="], + "@img/sharp-linux-ppc64": ["@img/sharp-linux-ppc64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-ppc64": "1.2.4" }, "os": "linux", "cpu": "ppc64" }, "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA=="], - "@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.0.4" }, "os": "linux", "cpu": "arm64" }, "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA=="], + "@img/sharp-linux-riscv64": ["@img/sharp-linux-riscv64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-riscv64": "1.2.4" }, "os": "linux", "cpu": "none" }, "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw=="], - "@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.0.4" }, "os": "linux", "cpu": "s390x" }, "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q=="], + "@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.2.4" }, "os": "linux", "cpu": "s390x" }, "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg=="], - "@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.0.4" }, "os": "linux", "cpu": "x64" }, "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA=="], + "@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ=="], - "@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" }, "os": "linux", "cpu": "arm64" }, "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g=="], + "@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg=="], - "@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.0.4" }, "os": "linux", "cpu": "x64" }, "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw=="], + "@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q=="], - "@img/sharp-wasm32": ["@img/sharp-wasm32@0.33.5", "", { "dependencies": { "@emnapi/runtime": "^1.2.0" }, "cpu": "none" }, "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg=="], + "@img/sharp-wasm32": ["@img/sharp-wasm32@0.34.5", "", { "dependencies": { "@emnapi/runtime": "^1.7.0" }, "cpu": "none" }, "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw=="], - "@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.33.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ=="], + "@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.34.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g=="], - "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.33.5", "", { "os": "win32", "cpu": "x64" }, "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg=="], + "@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.34.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg=="], - "@isaacs/balanced-match": ["@isaacs/balanced-match@4.0.1", "", {}, "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ=="], + "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.5", "", { "os": "win32", "cpu": "x64" }, "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw=="], - "@isaacs/brace-expansion": ["@isaacs/brace-expansion@5.0.0", "", { "dependencies": { "@isaacs/balanced-match": "^4.0.1" } }, "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA=="], + "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], + + "@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="], "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], @@ -391,21 +491,31 @@ "@libav.js/variant-opus-af": ["@libav.js/variant-opus-af@6.8.8", "", {}, "sha512-8KBQyA8n5goN7lyctOaPxpcx7dapOgqKh8dWW/NAcl87AgM/WoUGSex3fFc46oCtTHYrUKEm1OmZUrtkt3Q56A=="], + "@moq/boy": ["@moq/boy@workspace:js/moq-boy"], + "@moq/clock": ["@moq/clock@workspace:js/clock"], + "@moq/demo": ["@moq/demo@workspace:demo/web"], + + "@moq/demo-boy": ["@moq/demo-boy@workspace:demo/boy"], + "@moq/hang": ["@moq/hang@workspace:js/hang"], - "@moq/hang-demo": ["@moq/hang-demo@workspace:js/hang-demo"], + "@moq/loc": ["@moq/loc@workspace:js/loc"], + + "@moq/msf": ["@moq/msf@workspace:js/msf"], + + "@moq/net": ["@moq/net@workspace:js/net"], - "@moq/hang-ui": ["@moq/hang-ui@workspace:js/hang-ui"], + "@moq/publish": ["@moq/publish@workspace:js/publish"], - "@moq/lite": ["@moq/lite@workspace:js/lite"], + "@moq/qmux": ["@moq/qmux@0.0.6", "", {}, "sha512-ISuGz05lUvf1hzHW3Aw3VnsGRJe1w9Qdog3LQ66KS+l+5mzQsPANvW8yOioEe1Z9dJO2G3sAHoGPnzwnsY9SIQ=="], "@moq/signals": ["@moq/signals@workspace:js/signals"], "@moq/token": ["@moq/token@workspace:js/token"], - "@moq/web-transport-ws": ["@moq/web-transport-ws@0.1.2", "", {}, "sha512-mYha+AkLNPT3uOGnTA5YWjpxc9LO/yriFSoWzKkR0zN3UMZb9RXbsD8Gbhg1pJZod6QD4tevHoOWTBADYN7yAQ=="], + "@moq/watch": ["@moq/watch@workspace:js/watch"], "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], @@ -413,63 +523,79 @@ "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], + "@npmcli/config": ["@npmcli/config@8.3.4", "", { "dependencies": { "@npmcli/map-workspaces": "^3.0.2", "@npmcli/package-json": "^5.1.1", "ci-info": "^4.0.0", "ini": "^4.1.2", "nopt": "^7.2.1", "proc-log": "^4.2.0", "semver": "^7.3.5", "walk-up-path": "^3.0.1" } }, "sha512-01rtHedemDNhUXdicU7s+QYz/3JyV5Naj84cvdXGH4mgCdL+agmSYaLF4LUG4vMCLzhBO8YtS0gPpH1FGvbgAw=="], + + "@npmcli/git": ["@npmcli/git@5.0.8", "", { "dependencies": { "@npmcli/promise-spawn": "^7.0.0", "ini": "^4.1.3", "lru-cache": "^10.0.1", "npm-pick-manifest": "^9.0.0", "proc-log": "^4.0.0", "promise-inflight": "^1.0.1", "promise-retry": "^2.0.1", "semver": "^7.3.5", "which": "^4.0.0" } }, "sha512-liASfw5cqhjNW9UFd+ruwwdEf/lbOAQjLL2XY2dFW/bkJheXDYZgOyul/4gVvEV4BWkTXjYGmDqMw9uegdbJNQ=="], + + "@npmcli/map-workspaces": ["@npmcli/map-workspaces@3.0.6", "", { "dependencies": { "@npmcli/name-from-folder": "^2.0.0", "glob": "^10.2.2", "minimatch": "^9.0.0", "read-package-json-fast": "^3.0.0" } }, "sha512-tkYs0OYnzQm6iIRdfy+LcLBjcKuQCeE5YLb8KnrIlutJfheNaPvPpgoFEyEFgbjzl5PLZ3IA/BWAwRU0eHuQDA=="], + + "@npmcli/name-from-folder": ["@npmcli/name-from-folder@2.0.0", "", {}, "sha512-pwK+BfEBZJbKdNYpHHRTNBwBoqrN/iIMO0AiGvYsp3Hoaq0WbgGSWQR6SCldZovoDpY3yje5lkFUe6gsDgJ2vg=="], + + "@npmcli/package-json": ["@npmcli/package-json@5.2.1", "", { "dependencies": { "@npmcli/git": "^5.0.0", "glob": "^10.2.2", "hosted-git-info": "^7.0.0", "json-parse-even-better-errors": "^3.0.0", "normalize-package-data": "^6.0.0", "proc-log": "^4.0.0", "semver": "^7.5.3" } }, "sha512-f7zYC6kQautXHvNbLEWgD/uGu1+xCn9izgqBfgItWSx22U0ZDekxN08A1vM8cTxj/cRVe0Q94Ode+tdoYmIOOQ=="], + + "@npmcli/promise-spawn": ["@npmcli/promise-spawn@7.0.2", "", { "dependencies": { "which": "^4.0.0" } }, "sha512-xhfYPXoV5Dy4UkY0D+v2KkwvnDfiA/8Mt3sWCGI/hM03NsYIH8ZaG6QzS9x7pje5vHZBZJ2v6VRFVTWACnqcmQ=="], + + "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], + "@poppinss/colors": ["@poppinss/colors@4.1.6", "", { "dependencies": { "kleur": "^4.1.5" } }, "sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg=="], "@poppinss/dumper": ["@poppinss/dumper@0.6.5", "", { "dependencies": { "@poppinss/colors": "^4.1.5", "@sindresorhus/is": "^7.0.2", "supports-color": "^10.0.0" } }, "sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw=="], "@poppinss/exception": ["@poppinss/exception@1.2.3", "", {}, "sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw=="], - "@rollup/pluginutils": ["@rollup/pluginutils@5.3.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q=="], + "@publint/pack": ["@publint/pack@0.1.4", "", {}, "sha512-HDVTWq3H0uTXiU0eeSQntcVUTPP3GamzeXI41+x7uU9J65JgWQh3qWZHblR1i0npXfFtF+mxBiU2nJH8znxWnQ=="], + + "@rollup/pluginutils": ["@rollup/pluginutils@4.2.1", "", { "dependencies": { "estree-walker": "^2.0.1", "picomatch": "^2.2.2" } }, "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ=="], - "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.55.1", "", { "os": "android", "cpu": "arm" }, "sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg=="], + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.57.1", "", { "os": "android", "cpu": "arm" }, "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg=="], - "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.55.1", "", { "os": "android", "cpu": "arm64" }, "sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg=="], + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.57.1", "", { "os": "android", "cpu": "arm64" }, "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w=="], - "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.55.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg=="], + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.57.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg=="], - "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.55.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ=="], + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.57.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w=="], - "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.55.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg=="], + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.57.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug=="], - "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.55.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw=="], + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.57.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q=="], - "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.55.1", "", { "os": "linux", "cpu": "arm" }, "sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ=="], + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.57.1", "", { "os": "linux", "cpu": "arm" }, "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw=="], - "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.55.1", "", { "os": "linux", "cpu": "arm" }, "sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg=="], + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.57.1", "", { "os": "linux", "cpu": "arm" }, "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw=="], - "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.55.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ=="], + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.57.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g=="], - "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.55.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA=="], + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.57.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q=="], - "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.55.1", "", { "os": "linux", "cpu": "none" }, "sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g=="], + "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA=="], - "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.55.1", "", { "os": "linux", "cpu": "none" }, "sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw=="], + "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw=="], - "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.55.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw=="], + "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.57.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w=="], - "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.55.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw=="], + "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.57.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw=="], - "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.55.1", "", { "os": "linux", "cpu": "none" }, "sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw=="], + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A=="], - "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.55.1", "", { "os": "linux", "cpu": "none" }, "sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg=="], + "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw=="], - "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.55.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg=="], + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.57.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg=="], - "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.55.1", "", { "os": "linux", "cpu": "x64" }, "sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg=="], + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.57.1", "", { "os": "linux", "cpu": "x64" }, "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg=="], - "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.55.1", "", { "os": "linux", "cpu": "x64" }, "sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w=="], + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.57.1", "", { "os": "linux", "cpu": "x64" }, "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw=="], - "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.55.1", "", { "os": "openbsd", "cpu": "x64" }, "sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg=="], + "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.57.1", "", { "os": "openbsd", "cpu": "x64" }, "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw=="], - "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.55.1", "", { "os": "none", "cpu": "arm64" }, "sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw=="], + "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.57.1", "", { "os": "none", "cpu": "arm64" }, "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ=="], - "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.55.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g=="], + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.57.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ=="], - "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.55.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA=="], + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.57.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew=="], - "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.55.1", "", { "os": "win32", "cpu": "x64" }, "sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg=="], + "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.57.1", "", { "os": "win32", "cpu": "x64" }, "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ=="], - "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.55.1", "", { "os": "win32", "cpu": "x64" }, "sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw=="], + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.57.1", "", { "os": "win32", "cpu": "x64" }, "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA=="], "@shikijs/core": ["@shikijs/core@2.5.0", "", { "dependencies": { "@shikijs/engine-javascript": "2.5.0", "@shikijs/engine-oniguruma": "2.5.0", "@shikijs/types": "2.5.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.4" } }, "sha512-uu/8RExTKtavlpH7XqnVYBrfBkUc20ngXiX9NSrBhOVZYv/7XQRKUyhtkeflY5QsxC0GbJThCerruZfsUaSldg=="], @@ -489,10 +615,12 @@ "@sindresorhus/is": ["@sindresorhus/is@7.2.0", "", {}, "sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw=="], - "@solidjs/testing-library": ["@solidjs/testing-library@0.8.10", "", { "dependencies": { "@testing-library/dom": "^10.4.0" }, "peerDependencies": { "@solidjs/router": ">=0.9.0", "solid-js": ">=1.0.0" }, "optionalPeers": ["@solidjs/router"] }, "sha512-qdeuIerwyq7oQTIrrKvV0aL9aFeuwTd86VYD3afdq5HYEwoox1OBTJy4y8A3TFZr8oAR0nujYgCzY/8wgHGfeQ=="], - "@speed-highlight/core": ["@speed-highlight/core@1.2.14", "", {}, "sha512-G4ewlBNhUtlLvrJTb88d2mdy2KRijzs4UhnlrOSRT4bmjh/IqNElZa3zkrZ+TC47TwtlDWzVLFADljF1Ijp5hA=="], + "@svta/cml-iso-bmff": ["@svta/cml-iso-bmff@1.0.1", "", { "peerDependencies": { "@svta/cml-utils": "1.4.0" } }, "sha512-MOhATJYQ6cVrIcoY3nj8p/vGYDpG3wjQIIhBPHNt9yjFijdwFdBNqdZbCXv3aFhRjdx5Saca5TkgNJusKhnI/w=="], + + "@svta/cml-utils": ["@svta/cml-utils@1.4.0", "", {}, "sha512-vNtHtv/z+9I9ysxFwNrgwxic1oceVPr8TpcpV/NA1l8Gy4phynwtOppkCIBB+PmoyKDcqE4lO85g+lfsuSTBBA=="], + "@tailwindcss/node": ["@tailwindcss/node@4.1.18", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "enhanced-resolve": "^5.18.3", "jiti": "^2.6.1", "lightningcss": "1.30.2", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.1.18" } }, "sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ=="], "@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.18", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.18", "@tailwindcss/oxide-darwin-arm64": "4.1.18", "@tailwindcss/oxide-darwin-x64": "4.1.18", "@tailwindcss/oxide-freebsd-x64": "4.1.18", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.18", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.18", "@tailwindcss/oxide-linux-arm64-musl": "4.1.18", "@tailwindcss/oxide-linux-x64-gnu": "4.1.18", "@tailwindcss/oxide-linux-x64-musl": "4.1.18", "@tailwindcss/oxide-wasm32-wasi": "4.1.18", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.18", "@tailwindcss/oxide-win32-x64-msvc": "4.1.18" } }, "sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A=="], @@ -525,20 +653,6 @@ "@tailwindcss/vite": ["@tailwindcss/vite@4.1.18", "", { "dependencies": { "@tailwindcss/node": "4.1.18", "@tailwindcss/oxide": "4.1.18", "tailwindcss": "4.1.18" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-jVA+/UpKL1vRLg6Hkao5jldawNmRo7mQYrZtNHMIVpLfLhDml5nMRUo/8MwoX2vNXvnaXNNMedrMfMugAVX1nA=="], - "@testing-library/dom": ["@testing-library/dom@10.4.1", "", { "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", "@types/aria-query": "^5.0.1", "aria-query": "5.3.0", "dom-accessibility-api": "^0.5.9", "lz-string": "^1.5.0", "picocolors": "1.1.1", "pretty-format": "^27.0.2" } }, "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg=="], - - "@testing-library/jest-dom": ["@testing-library/jest-dom@6.9.1", "", { "dependencies": { "@adobe/css-tools": "^4.4.0", "aria-query": "^5.0.0", "css.escape": "^1.5.1", "dom-accessibility-api": "^0.6.3", "picocolors": "^1.1.1", "redent": "^3.0.0" } }, "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA=="], - - "@ts-graphviz/adapter": ["@ts-graphviz/adapter@2.0.6", "", { "dependencies": { "@ts-graphviz/common": "^2.1.5" } }, "sha512-kJ10lIMSWMJkLkkCG5gt927SnGZcBuG0s0HHswGzcHTgvtUe7yk5/3zTEr0bafzsodsOq5Gi6FhQeV775nC35Q=="], - - "@ts-graphviz/ast": ["@ts-graphviz/ast@2.0.7", "", { "dependencies": { "@ts-graphviz/common": "^2.1.5" } }, "sha512-e6+2qtNV99UT6DJSoLbHfkzfyqY84aIuoV8Xlb9+hZAjgpum8iVHprGeAMQ4rF6sKUAxrmY8rfF/vgAwoPc3gw=="], - - "@ts-graphviz/common": ["@ts-graphviz/common@2.1.5", "", {}, "sha512-S6/9+T6x8j6cr/gNhp+U2olwo1n0jKj/682QVqsh7yXWV6ednHYqxFw0ZsY3LyzT0N8jaZ6jQY9YD99le3cmvg=="], - - "@ts-graphviz/core": ["@ts-graphviz/core@2.0.7", "", { "dependencies": { "@ts-graphviz/ast": "^2.0.7", "@ts-graphviz/common": "^2.1.5" } }, "sha512-w071DSzP94YfN6XiWhOxnLpYT3uqtxJBDYdh6Jdjzt+Ce6DNspJsPQgpC7rbts/B8tEkq0LHoYuIF/O5Jh5rPg=="], - - "@types/aria-query": ["@types/aria-query@5.0.4", "", {}, "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw=="], - "@types/audioworklet": ["@types/audioworklet@0.0.77", "", {}, "sha512-aPQ0DurtnDRWO3qvu8iK1R0aDlKS7sDOWx7MVhMWkGTmlyfnf50GPKYJlKdq8UP159ntPiqPJ5XZ/2v1R0V0Bw=="], "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], @@ -549,16 +663,20 @@ "@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="], - "@types/chai": ["@types/chai@5.2.3", "", { "dependencies": { "@types/deep-eql": "*", "assertion-error": "^2.0.1" } }, "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA=="], + "@types/bun": ["@types/bun@1.3.11", "", { "dependencies": { "bun-types": "1.3.11" } }, "sha512-5vPne5QvtpjGpsGYXiFyycfpDF2ECyPcTSsFBMa0fraoxiQyMJ3SmuQIGhzPg2WJuWxVBoxWJ2kClYTcw/4fAg=="], - "@types/deep-eql": ["@types/deep-eql@4.0.2", "", {}, "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw=="], + "@types/concat-stream": ["@types/concat-stream@2.0.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-3qe4oQAPNwVNwK4C9c8u+VJqv9kez+2MR4qJpoPFfXtgxxif1QbFusvXzK0/Wra2VX07smostI2VMmJNSpZjuQ=="], - "@types/deno": ["@types/deno@2.5.0", "", {}, "sha512-g8JS38vmc0S87jKsFzre+0ZyMOUDHPVokEJymSCRlL57h6f/FdKPWBXgdFh3Z8Ees9sz11qt9VWELU9Y9ZkiVw=="], + "@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="], "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], + "@types/estree-jsx": ["@types/estree-jsx@1.0.5", "", { "dependencies": { "@types/estree": "*" } }, "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg=="], + "@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="], + "@types/is-empty": ["@types/is-empty@1.2.3", "", {}, "sha512-4J1l5d79hoIvsrKh5VUKVRA1aIdsOb10Hu5j3J2VfP/msDnfTdGPmNp2E1Wg+vs97Bktzo+MZePFFXSGoykYJw=="], + "@types/linkify-it": ["@types/linkify-it@5.0.0", "", {}, "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q=="], "@types/markdown-it": ["@types/markdown-it@14.1.2", "", { "dependencies": { "@types/linkify-it": "^5", "@types/mdurl": "^2" } }, "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog=="], @@ -567,27 +685,19 @@ "@types/mdurl": ["@types/mdurl@2.0.0", "", {}, "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg=="], - "@types/node": ["@types/node@24.10.7", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-+054pVMzVTmRQV8BhpGv3UyfZ2Llgl8rdpDTon+cUH9+na0ncBVXj3wTUKh14+Kiz18ziM3b4ikpP5/Pc0rQEQ=="], - - "@types/react": ["@types/react@19.2.8", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-3MbSL37jEchWZz2p2mjntRZtPt837ij10ApxKfgmXCTuHWagYg7iA5bqPw6C8BMPfwidlvfPI/fxOc42HLhcyg=="], - - "@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="], - - "@types/web-bluetooth": ["@types/web-bluetooth@0.0.21", "", {}, "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA=="], + "@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="], - "@types/whatwg-mimetype": ["@types/whatwg-mimetype@3.0.2", "", {}, "sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA=="], + "@types/node": ["@types/node@24.10.13", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-oH72nZRfDv9lADUBSo104Aq7gPHpQZc4BTx38r9xf9pg5LfP6EzSyH2n7qFmmxRQXh7YlUXODcYsg6PuTDSxGg=="], - "@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="], + "@types/react": ["@types/react@19.2.14", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w=="], - "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.52.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.52.0", "@typescript-eslint/types": "^8.52.0", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-xD0MfdSdEmeFa3OmVqonHi+Cciab96ls1UhIF/qX/O/gPu5KXD0bY9lu33jj04fjzrXHcuvjBcBC+D3SNSadaw=="], + "@types/supports-color": ["@types/supports-color@8.1.3", "", {}, "sha512-Hy6UMpxhE3j1tLpl27exp1XqHD7n8chAiNPzWfz16LPZoMMoSc4dzLl6w9qijkEb/r5O1ozdu1CWGA2L83ZeZg=="], - "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.52.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-jl+8fzr/SdzdxWJznq5nvoI7qn2tNYV/ZBAEcaFMVXf+K6jmXvAFrgo/+5rxgnL152f//pDEAYAhhBAZGrVfwg=="], + "@types/text-table": ["@types/text-table@0.2.5", "", {}, "sha512-hcZhlNvMkQG/k1vcZ6yHOl6WAYftQ2MLfTHcYRZ2xYZFD8tGVnE3qFV0lj1smQeDSR7/yY0PyuUalauf33bJeA=="], - "@typescript-eslint/types": ["@typescript-eslint/types@8.52.0", "", {}, "sha512-LWQV1V4q9V4cT4H5JCIx3481iIFxH1UkVk+ZkGGAV1ZGcjGI9IoFOfg3O6ywz8QqCDEp7Inlg6kovMofsNRaGg=="], - - "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.52.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.52.0", "@typescript-eslint/tsconfig-utils": "8.52.0", "@typescript-eslint/types": "8.52.0", "@typescript-eslint/visitor-keys": "8.52.0", "debug": "^4.4.3", "minimatch": "^9.0.5", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-XP3LClsCc0FsTK5/frGjolyADTh3QmsLp6nKd476xNI9CsSsLnmn4f0jrzNoAulmxlmNIpeXuHYeEQv61Q6qeQ=="], + "@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="], - "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.52.0", "", { "dependencies": { "@typescript-eslint/types": "8.52.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-ink3/Zofus34nmBsPjow63FP5M7IGff0RKAgqR6+CFpdk22M7aLwC9gOcLGYqr7MczLPzZVERW9hRog3O4n1sQ=="], + "@types/web-bluetooth": ["@types/web-bluetooth@0.0.21", "", {}, "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA=="], "@typescript/lib-dom": ["@types/web@0.0.241", "", {}, "sha512-aHz73musjS4z8Sm0wLaEj4lOaRxhKZRD4XerKL4rxNhhqmvthKkYzS0kHLEVsjOFRN2zo3gQAlyf0EKL1QYYQg=="], @@ -597,27 +707,13 @@ "@vitejs/plugin-vue": ["@vitejs/plugin-vue@5.2.4", "", { "peerDependencies": { "vite": "^5.0.0 || ^6.0.0", "vue": "^3.2.25" } }, "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA=="], - "@vitest/expect": ["@vitest/expect@3.2.4", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/spy": "3.2.4", "@vitest/utils": "3.2.4", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" } }, "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig=="], - - "@vitest/mocker": ["@vitest/mocker@3.2.4", "", { "dependencies": { "@vitest/spy": "3.2.4", "estree-walker": "^3.0.3", "magic-string": "^0.30.17" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "optionalPeers": ["msw", "vite"] }, "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ=="], - - "@vitest/pretty-format": ["@vitest/pretty-format@3.2.4", "", { "dependencies": { "tinyrainbow": "^2.0.0" } }, "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA=="], - - "@vitest/runner": ["@vitest/runner@3.2.4", "", { "dependencies": { "@vitest/utils": "3.2.4", "pathe": "^2.0.3", "strip-literal": "^3.0.0" } }, "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ=="], + "@vue/compiler-core": ["@vue/compiler-core@3.5.28", "", { "dependencies": { "@babel/parser": "^7.29.0", "@vue/shared": "3.5.28", "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-kviccYxTgoE8n6OCw96BNdYlBg2GOWfBuOW4Vqwrt7mSKWKwFVvI8egdTltqRgITGPsTFYtKYfxIG8ptX2PJHQ=="], - "@vitest/snapshot": ["@vitest/snapshot@3.2.4", "", { "dependencies": { "@vitest/pretty-format": "3.2.4", "magic-string": "^0.30.17", "pathe": "^2.0.3" } }, "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ=="], + "@vue/compiler-dom": ["@vue/compiler-dom@3.5.28", "", { "dependencies": { "@vue/compiler-core": "3.5.28", "@vue/shared": "3.5.28" } }, "sha512-/1ZepxAb159jKR1btkefDP+J2xuWL5V3WtleRmxaT+K2Aqiek/Ab/+Ebrw2pPj0sdHO8ViAyyJWfhXXOP/+LQA=="], - "@vitest/spy": ["@vitest/spy@3.2.4", "", { "dependencies": { "tinyspy": "^4.0.3" } }, "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw=="], + "@vue/compiler-sfc": ["@vue/compiler-sfc@3.5.28", "", { "dependencies": { "@babel/parser": "^7.29.0", "@vue/compiler-core": "3.5.28", "@vue/compiler-dom": "3.5.28", "@vue/compiler-ssr": "3.5.28", "@vue/shared": "3.5.28", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", "postcss": "^8.5.6", "source-map-js": "^1.2.1" } }, "sha512-6TnKMiNkd6u6VeVDhZn/07KhEZuBSn43Wd2No5zaP5s3xm8IqFTHBj84HJah4UepSUJTro5SoqqlOY22FKY96g=="], - "@vitest/utils": ["@vitest/utils@3.2.4", "", { "dependencies": { "@vitest/pretty-format": "3.2.4", "loupe": "^3.1.4", "tinyrainbow": "^2.0.0" } }, "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA=="], - - "@vue/compiler-core": ["@vue/compiler-core@3.5.26", "", { "dependencies": { "@babel/parser": "^7.28.5", "@vue/shared": "3.5.26", "entities": "^7.0.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-vXyI5GMfuoBCnv5ucIT7jhHKl55Y477yxP6fc4eUswjP8FG3FFVFd41eNDArR+Uk3QKn2Z85NavjaxLxOC19/w=="], - - "@vue/compiler-dom": ["@vue/compiler-dom@3.5.26", "", { "dependencies": { "@vue/compiler-core": "3.5.26", "@vue/shared": "3.5.26" } }, "sha512-y1Tcd3eXs834QjswshSilCBnKGeQjQXB6PqFn/1nxcQw4pmG42G8lwz+FZPAZAby6gZeHSt/8LMPfZ4Rb+Bd/A=="], - - "@vue/compiler-sfc": ["@vue/compiler-sfc@3.5.26", "", { "dependencies": { "@babel/parser": "^7.28.5", "@vue/compiler-core": "3.5.26", "@vue/compiler-dom": "3.5.26", "@vue/compiler-ssr": "3.5.26", "@vue/shared": "3.5.26", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", "postcss": "^8.5.6", "source-map-js": "^1.2.1" } }, "sha512-egp69qDTSEZcf4bGOSsprUr4xI73wfrY5oRs6GSgXFTiHrWj4Y3X5Ydtip9QMqiCMCPVwLglB9GBxXtTadJ3mA=="], - - "@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.26", "", { "dependencies": { "@vue/compiler-dom": "3.5.26", "@vue/shared": "3.5.26" } }, "sha512-lZT9/Y0nSIRUPVvapFJEVDbEXruZh2IYHMk2zTtEgJSlP5gVOqeWXH54xDKAaFS4rTnDeDBQUYDtxKyoW9FwDw=="], + "@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.28", "", { "dependencies": { "@vue/compiler-dom": "3.5.28", "@vue/shared": "3.5.28" } }, "sha512-JCq//9w1qmC6UGLWJX7RXzrGpKkroubey/ZFqTpvEIDJEKGgntuDMqkuWiZvzTzTA5h2qZvFBFHY7fAAa9475g=="], "@vue/devtools-api": ["@vue/devtools-api@7.7.9", "", { "dependencies": { "@vue/devtools-kit": "^7.7.9" } }, "sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g=="], @@ -625,15 +721,15 @@ "@vue/devtools-shared": ["@vue/devtools-shared@7.7.9", "", { "dependencies": { "rfdc": "^1.4.1" } }, "sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA=="], - "@vue/reactivity": ["@vue/reactivity@3.5.26", "", { "dependencies": { "@vue/shared": "3.5.26" } }, "sha512-9EnYB1/DIiUYYnzlnUBgwU32NNvLp/nhxLXeWRhHUEeWNTn1ECxX8aGO7RTXeX6PPcxe3LLuNBFoJbV4QZ+CFQ=="], + "@vue/reactivity": ["@vue/reactivity@3.5.28", "", { "dependencies": { "@vue/shared": "3.5.28" } }, "sha512-gr5hEsxvn+RNyu9/9o1WtdYdwDjg5FgjUSBEkZWqgTKlo/fvwZ2+8W6AfKsc9YN2k/+iHYdS9vZYAhpi10kNaw=="], - "@vue/runtime-core": ["@vue/runtime-core@3.5.26", "", { "dependencies": { "@vue/reactivity": "3.5.26", "@vue/shared": "3.5.26" } }, "sha512-xJWM9KH1kd201w5DvMDOwDHYhrdPTrAatn56oB/LRG4plEQeZRQLw0Bpwih9KYoqmzaxF0OKSn6swzYi84e1/Q=="], + "@vue/runtime-core": ["@vue/runtime-core@3.5.28", "", { "dependencies": { "@vue/reactivity": "3.5.28", "@vue/shared": "3.5.28" } }, "sha512-POVHTdbgnrBBIpnbYU4y7pOMNlPn2QVxVzkvEA2pEgvzbelQq4ZOUxbp2oiyo+BOtiYlm8Q44wShHJoBvDPAjQ=="], - "@vue/runtime-dom": ["@vue/runtime-dom@3.5.26", "", { "dependencies": { "@vue/reactivity": "3.5.26", "@vue/runtime-core": "3.5.26", "@vue/shared": "3.5.26", "csstype": "^3.2.3" } }, "sha512-XLLd/+4sPC2ZkN/6+V4O4gjJu6kSDbHAChvsyWgm1oGbdSO3efvGYnm25yCjtFm/K7rrSDvSfPDgN1pHgS4VNQ=="], + "@vue/runtime-dom": ["@vue/runtime-dom@3.5.28", "", { "dependencies": { "@vue/reactivity": "3.5.28", "@vue/runtime-core": "3.5.28", "@vue/shared": "3.5.28", "csstype": "^3.2.3" } }, "sha512-4SXxSF8SXYMuhAIkT+eBRqOkWEfPu6nhccrzrkioA6l0boiq7sp18HCOov9qWJA5HML61kW8p/cB4MmBiG9dSA=="], - "@vue/server-renderer": ["@vue/server-renderer@3.5.26", "", { "dependencies": { "@vue/compiler-ssr": "3.5.26", "@vue/shared": "3.5.26" }, "peerDependencies": { "vue": "3.5.26" } }, "sha512-TYKLXmrwWKSodyVuO1WAubucd+1XlLg4set0YoV+Hu8Lo79mp/YMwWV5mC5FgtsDxX3qo1ONrxFaTP1OQgy1uA=="], + "@vue/server-renderer": ["@vue/server-renderer@3.5.28", "", { "dependencies": { "@vue/compiler-ssr": "3.5.28", "@vue/shared": "3.5.28" }, "peerDependencies": { "vue": "3.5.28" } }, "sha512-pf+5ECKGj8fX95bNincbzJ6yp6nyzuLDhYZCeFxUNp8EBrQpPpQaLX3nNCp49+UbgbPun3CeVE+5CXVV1Xydfg=="], - "@vue/shared": ["@vue/shared@3.5.26", "", {}, "sha512-7Z6/y3uFI5PRoKeorTOSXKcDj0MSasfNNltcslbFrPpcw6aXRUALq4IfJlaTRspiWIUOEZbrpM+iQGmCOiWe4A=="], + "@vue/shared": ["@vue/shared@3.5.28", "", {}, "sha512-cfWa1fCGBxrvaHRhvV3Is0MgmrbSCxYTXCSCau2I0a1Xw1N1pHAvkWCiXPRAqjvToILvguNyEwjevUqAuBQWvQ=="], "@vueuse/core": ["@vueuse/core@12.8.2", "", { "dependencies": { "@types/web-bluetooth": "^0.0.21", "@vueuse/metadata": "12.8.2", "@vueuse/shared": "12.8.2", "vue": "^3.5.13" } }, "sha512-HbvCmZdzAu3VGi/pWYm5Ut+Kd9mn1ZHnn4L5G8kOQTPs/IwIAmJoBrmYk2ckLArgMXZj0AW3n5CAejLUO+PhdQ=="], @@ -643,25 +739,17 @@ "@vueuse/shared": ["@vueuse/shared@12.8.2", "", { "dependencies": { "vue": "^3.5.13" } }, "sha512-dznP38YzxZoNloI0qpEfpkms8knDtaoQ6Y/sfS0L7Yki4zh40LFHEhur0odJC6xTHG5dxWVPiUWBXn+wCG2s5w=="], - "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], + "abbrev": ["abbrev@2.0.0", "", {}, "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ=="], - "acorn-walk": ["acorn-walk@8.3.2", "", {}, "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A=="], + "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], - "algoliasearch": ["algoliasearch@5.46.2", "", { "dependencies": { "@algolia/abtesting": "1.12.2", "@algolia/client-abtesting": "5.46.2", "@algolia/client-analytics": "5.46.2", "@algolia/client-common": "5.46.2", "@algolia/client-insights": "5.46.2", "@algolia/client-personalization": "5.46.2", "@algolia/client-query-suggestions": "5.46.2", "@algolia/client-search": "5.46.2", "@algolia/ingestion": "1.46.2", "@algolia/monitoring": "1.46.2", "@algolia/recommend": "5.46.2", "@algolia/requester-browser-xhr": "5.46.2", "@algolia/requester-fetch": "5.46.2", "@algolia/requester-node-http": "5.46.2" } }, "sha512-qqAXW9QvKf2tTyhpDA4qXv1IfBwD2eduSW6tUEBFIfCeE9gn9HQ9I5+MaKoenRuHrzk5sQoNh1/iof8mY7uD6Q=="], + "algoliasearch": ["algoliasearch@5.48.1", "", { "dependencies": { "@algolia/abtesting": "1.14.1", "@algolia/client-abtesting": "5.48.1", "@algolia/client-analytics": "5.48.1", "@algolia/client-common": "5.48.1", "@algolia/client-insights": "5.48.1", "@algolia/client-personalization": "5.48.1", "@algolia/client-query-suggestions": "5.48.1", "@algolia/client-search": "5.48.1", "@algolia/ingestion": "1.48.1", "@algolia/monitoring": "1.48.1", "@algolia/recommend": "5.48.1", "@algolia/requester-browser-xhr": "5.48.1", "@algolia/requester-fetch": "5.48.1", "@algolia/requester-node-http": "5.48.1" } }, "sha512-Rf7xmeuIo7nb6S4mp4abW2faW8DauZyE2faBIKFaUfP3wnpOvNSbiI5AwVhqBNj0jPgBWEvhyCu0sLjN2q77Rg=="], - "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], - "any-promise": ["any-promise@1.3.0", "", {}, "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="], - - "app-module-path": ["app-module-path@2.2.0", "", {}, "sha512-gkco+qxENJV+8vFcDiiFhuoSvRXb2a/QPqpSoWhVz829VNJfOTnELbBmPmNKFxf3xdNnw4DWCkzkDaavcX/1YQ=="], - - "aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="], - - "assertion-error": ["assertion-error@2.0.1", "", {}, "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="], - - "ast-module-types": ["ast-module-types@6.0.1", "", {}, "sha512-WHw67kLXYbZuHTmcdbIrVArCq5wxo6NEuj3hiYAWr8mwJeC+C2mMCIBIWCiDoCye/OF/xelc+teJ1ERoWmnEIA=="], + "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], "async": ["async@3.2.6", "", {}, "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA=="], @@ -671,11 +759,17 @@ "babel-preset-solid": ["babel-preset-solid@1.9.10", "", { "dependencies": { "babel-plugin-jsx-dom-expressions": "^0.40.3" }, "peerDependencies": { "@babel/core": "^7.0.0", "solid-js": "^1.9.10" }, "optionalPeers": ["solid-js"] }, "sha512-HCelrgua/Y+kqO8RyL04JBWS/cVdrtUv/h45GntgQY+cJl4eBcKkCDV3TdMjtKx1nXwRaR9QXslM/Npm1dxdZQ=="], - "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "bail": ["bail@2.0.2", "", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="], + + "balanced-match": ["balanced-match@4.0.2", "", { "dependencies": { "jackspeak": "^4.2.3" } }, "sha512-x0K50QvKQ97fdEz2kPehIerj+YTeptKF9hyYkKf6egnwmMWAkADiO0QCzSp0R5xN8FTZgYaBfSaue46Ej62nMg=="], "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], - "baseline-browser-mapping": ["baseline-browser-mapping@2.9.14", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-B0xUquLkiGLgHhpPBqvl7GWegWBUNuujQ6kXd/r1U38ElPT6Ok8KZ8e+FpUGEc2ZoRQUzq/aUnaKFc/svWUGSg=="], + "baseline-browser-mapping": ["baseline-browser-mapping@2.9.19", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg=="], + + "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="], + + "bindings": ["bindings@1.5.0", "", { "dependencies": { "file-uri-to-path": "1.0.0" } }, "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ=="], "birpc": ["birpc@2.9.0", "", {}, "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw=="], @@ -685,7 +779,7 @@ "boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="], - "brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + "brace-expansion": ["brace-expansion@5.0.2", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw=="], "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], @@ -695,55 +789,51 @@ "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], - "cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="], + "bun-types": ["bun-types@1.3.11", "", { "dependencies": { "@types/node": "*" } }, "sha512-1KGPpoxQWl9f6wcZh57LvrPIInQMn2TQ7jsgxqpRzg+l0QPOFvJVH7HmvHo/AiPgwXy+/Thf6Ov3EdVn1vOabg=="], "camel-case": ["camel-case@4.1.2", "", { "dependencies": { "pascal-case": "^3.1.2", "tslib": "^2.0.3" } }, "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw=="], - "caniuse-lite": ["caniuse-lite@1.0.30001764", "", {}, "sha512-9JGuzl2M+vPL+pz70gtMF9sHdMFbY9FJaQBi186cHKH3pSzDvzoUJUPV6fqiKIMyXbud9ZLg4F3Yza1vJ1+93g=="], + "caniuse-lite": ["caniuse-lite@1.0.30001769", "", {}, "sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg=="], "ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="], - "chai": ["chai@5.3.3", "", { "dependencies": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", "deep-eql": "^5.0.1", "loupe": "^3.1.0", "pathval": "^2.0.0" } }, "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw=="], - "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + "character-entities": ["character-entities@2.0.2", "", {}, "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ=="], + "character-entities-html4": ["character-entities-html4@2.1.0", "", {}, "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA=="], "character-entities-legacy": ["character-entities-legacy@3.0.0", "", {}, "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="], - "check-error": ["check-error@2.1.3", "", {}, "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA=="], + "character-reference-invalid": ["character-reference-invalid@2.0.1", "", {}, "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw=="], - "clean-css": ["clean-css@5.3.3", "", { "dependencies": { "source-map": "~0.6.0" } }, "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg=="], + "chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], - "cli-cursor": ["cli-cursor@3.1.0", "", { "dependencies": { "restore-cursor": "^3.1.0" } }, "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw=="], + "chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="], - "cli-spinners": ["cli-spinners@2.9.2", "", {}, "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg=="], + "ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], + + "clean-css": ["clean-css@5.3.3", "", { "dependencies": { "source-map": "~0.6.0" } }, "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg=="], "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], - "clone": ["clone@1.0.4", "", {}, "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg=="], + "cmake-js": ["cmake-js@8.0.0", "", { "dependencies": { "debug": "^4.4.3", "fs-extra": "^11.3.3", "node-api-headers": "^1.8.0", "rc": "1.2.8", "semver": "^7.7.3", "tar": "^7.5.6", "url-join": "^4.0.1", "which": "^6.0.0", "yargs": "^17.7.2" }, "bin": { "cmake-js": "bin/cmake-js" } }, "sha512-YbUP88RDwCvoQkZhRtGURYm9RIpWdtvZuhT87fKNoLjk8kIFIFeARpKfuZQGdwfH99GZpUmqSfcDrK62X7lTgg=="], - "color": ["color@4.2.3", "", { "dependencies": { "color-convert": "^2.0.1", "color-string": "^1.9.0" } }, "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A=="], + "collapse-white-space": ["collapse-white-space@2.1.0", "", {}, "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw=="], "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], - "color-string": ["color-string@1.9.1", "", { "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" } }, "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg=="], - "colorette": ["colorette@2.0.20", "", {}, "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w=="], - "comlink": ["comlink@4.4.2", "", {}, "sha512-OxGdvBmJuNKSCMO4NTl1L47VRp6xn2wG4F/2hYzB6tiCb709otOxtEYCSvK80PtjODfXXZu8ds+Nw5kVCjqd2g=="], - "comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="], - "commander": ["commander@14.0.2", "", {}, "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ=="], - - "commondir": ["commondir@1.0.1", "", {}, "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg=="], + "commander": ["commander@14.0.3", "", {}, "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw=="], "component-register": ["component-register@0.8.8", "", {}, "sha512-djhwcxjY+X9dacaYUEOkOm7tda8uOEDiMDigWysu3xv54M8o6XDlsjR1qt5Y8QLGiKg51fqXFIR2HUTmt9ys0Q=="], - "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], + "concat-stream": ["concat-stream@2.0.0", "", { "dependencies": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.0.2", "typedarray": "^0.0.6" } }, "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A=="], "concurrently": ["concurrently@9.2.1", "", { "dependencies": { "chalk": "4.1.2", "rxjs": "7.8.2", "shell-quote": "1.8.3", "supports-color": "8.1.1", "tree-kill": "1.2.2", "yargs": "17.7.2" }, "bin": { "conc": "dist/bin/concurrently.js", "concurrently": "dist/bin/concurrently.js" } }, "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng=="], @@ -757,52 +847,30 @@ "copy-anything": ["copy-anything@4.0.5", "", { "dependencies": { "is-what": "^5.2.0" } }, "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA=="], + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + "css-select": ["css-select@4.3.0", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.0.1", "domhandler": "^4.3.1", "domutils": "^2.8.0", "nth-check": "^2.0.1" } }, "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ=="], "css-what": ["css-what@6.2.2", "", {}, "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA=="], - "css.escape": ["css.escape@1.5.1", "", {}, "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg=="], - "cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="], "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], - "deep-eql": ["deep-eql@5.0.2", "", {}, "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q=="], - - "deep-extend": ["deep-extend@0.6.0", "", {}, "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="], + "decode-named-character-reference": ["decode-named-character-reference@1.3.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q=="], - "defaults": ["defaults@1.0.4", "", { "dependencies": { "clone": "^1.0.2" } }, "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A=="], + "decompress-response": ["decompress-response@6.0.0", "", { "dependencies": { "mimic-response": "^3.1.0" } }, "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ=="], - "dependency-tree": ["dependency-tree@11.2.0", "", { "dependencies": { "commander": "^12.1.0", "filing-cabinet": "^5.0.3", "precinct": "^12.2.0", "typescript": "^5.8.3" }, "bin": { "dependency-tree": "bin/cli.js" } }, "sha512-+C1H3mXhcvMCeu5i2Jpg9dc0N29TWTuT6vJD7mHLAfVmAbo9zW8NlkvQ1tYd3PDMab0IRQM0ccoyX68EZtx9xw=="], + "deep-extend": ["deep-extend@0.6.0", "", {}, "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="], "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="], "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], - "detective-amd": ["detective-amd@6.0.1", "", { "dependencies": { "ast-module-types": "^6.0.1", "escodegen": "^2.1.0", "get-amd-module-type": "^6.0.1", "node-source-walk": "^7.0.1" }, "bin": { "detective-amd": "bin/cli.js" } }, "sha512-TtyZ3OhwUoEEIhTFoc1C9IyJIud3y+xYkSRjmvCt65+ycQuc3VcBrPRTMWoO/AnuCyOB8T5gky+xf7Igxtjd3g=="], - - "detective-cjs": ["detective-cjs@6.0.1", "", { "dependencies": { "ast-module-types": "^6.0.1", "node-source-walk": "^7.0.1" } }, "sha512-tLTQsWvd2WMcmn/60T2inEJNhJoi7a//PQ7DwRKEj1yEeiQs4mrONgsUtEJKnZmrGWBBmE0kJ1vqOG/NAxwaJw=="], - - "detective-es6": ["detective-es6@5.0.1", "", { "dependencies": { "node-source-walk": "^7.0.1" } }, "sha512-XusTPuewnSUdoxRSx8OOI6xIA/uld/wMQwYsouvFN2LAg7HgP06NF1lHRV3x6BZxyL2Kkoih4ewcq8hcbGtwew=="], - - "detective-postcss": ["detective-postcss@7.0.1", "", { "dependencies": { "is-url": "^1.2.4", "postcss-values-parser": "^6.0.2" }, "peerDependencies": { "postcss": "^8.4.47" } }, "sha512-bEOVpHU9picRZux5XnwGsmCN4+8oZo7vSW0O0/Enq/TO5R2pIAP2279NsszpJR7ocnQt4WXU0+nnh/0JuK4KHQ=="], - - "detective-sass": ["detective-sass@6.0.1", "", { "dependencies": { "gonzales-pe": "^4.3.0", "node-source-walk": "^7.0.1" } }, "sha512-jSGPO8QDy7K7pztUmGC6aiHkexBQT4GIH+mBAL9ZyBmnUIOFbkfZnO8wPRRJFP/QP83irObgsZHCoDHZ173tRw=="], - - "detective-scss": ["detective-scss@5.0.1", "", { "dependencies": { "gonzales-pe": "^4.3.0", "node-source-walk": "^7.0.1" } }, "sha512-MAyPYRgS6DCiS6n6AoSBJXLGVOydsr9huwXORUlJ37K3YLyiN0vYHpzs3AdJOgHobBfispokoqrEon9rbmKacg=="], - - "detective-stylus": ["detective-stylus@5.0.1", "", {}, "sha512-Dgn0bUqdGbE3oZJ+WCKf8Dmu7VWLcmRJGc6RCzBgG31DLIyai9WAoEhYRgIHpt/BCRMrnXLbGWGPQuBUrnF0TA=="], - - "detective-typescript": ["detective-typescript@14.0.0", "", { "dependencies": { "@typescript-eslint/typescript-estree": "^8.23.0", "ast-module-types": "^6.0.1", "node-source-walk": "^7.0.1" }, "peerDependencies": { "typescript": "^5.4.4" } }, "sha512-pgN43/80MmWVSEi5LUuiVvO/0a9ss5V7fwVfrJ4QzAQRd3cwqU1SfWGXJFcNKUqoD5cS+uIovhw5t/0rSeC5Mw=="], - - "detective-vue2": ["detective-vue2@2.2.0", "", { "dependencies": { "@dependents/detective-less": "^5.0.1", "@vue/compiler-sfc": "^3.5.13", "detective-es6": "^5.0.1", "detective-sass": "^6.0.1", "detective-scss": "^5.0.1", "detective-stylus": "^5.0.1", "detective-typescript": "^14.0.0" }, "peerDependencies": { "typescript": "^5.4.4" } }, "sha512-sVg/t6O2z1zna8a/UIV6xL5KUa2cMTQbdTIIvqNM0NIPswp52fe43Nwmbahzj3ww4D844u/vC2PYfiGLvD3zFA=="], - "devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "^2.0.0" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="], - "dom-accessibility-api": ["dom-accessibility-api@0.6.3", "", {}, "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w=="], - "dom-serializer": ["dom-serializer@1.4.1", "", { "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", "entities": "^2.0.0" } }, "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag=="], "domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="], @@ -817,88 +885,82 @@ "dotenv-expand": ["dotenv-expand@8.0.3", "", {}, "sha512-SErOMvge0ZUyWd5B0NXMQlDkN+8r+HhVUsxgOO7IoPDOdDRD2JjExpN6y3KnFR66jsJMwSn1pqIivhU5rcJiNg=="], + "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], + "ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="], - "electron-to-chromium": ["electron-to-chromium@1.5.267", "", {}, "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw=="], + "electron-to-chromium": ["electron-to-chromium@1.5.286", "", {}, "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A=="], "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], "emoji-regex-xs": ["emoji-regex-xs@1.0.0", "", {}, "sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg=="], - "enhanced-resolve": ["enhanced-resolve@5.18.4", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q=="], + "end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="], - "entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], + "enhanced-resolve": ["enhanced-resolve@5.19.0", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.0" } }, "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg=="], - "error-stack-parser-es": ["error-stack-parser-es@1.0.5", "", {}, "sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA=="], - - "es-module-lexer": ["es-module-lexer@1.7.0", "", {}, "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA=="], - - "esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="], + "entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], - "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + "err-code": ["err-code@2.0.3", "", {}, "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA=="], - "escodegen": ["escodegen@2.1.0", "", { "dependencies": { "esprima": "^4.0.1", "estraverse": "^5.2.0", "esutils": "^2.0.2" }, "optionalDependencies": { "source-map": "~0.6.1" }, "bin": { "esgenerate": "bin/esgenerate.js", "escodegen": "bin/escodegen.js" } }, "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w=="], + "error-ex": ["error-ex@1.3.4", "", { "dependencies": { "is-arrayish": "^0.2.1" } }, "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ=="], - "eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="], + "error-stack-parser-es": ["error-stack-parser-es@1.0.5", "", {}, "sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA=="], - "esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="], + "esbuild": ["esbuild@0.27.3", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.3", "@esbuild/android-arm": "0.27.3", "@esbuild/android-arm64": "0.27.3", "@esbuild/android-x64": "0.27.3", "@esbuild/darwin-arm64": "0.27.3", "@esbuild/darwin-x64": "0.27.3", "@esbuild/freebsd-arm64": "0.27.3", "@esbuild/freebsd-x64": "0.27.3", "@esbuild/linux-arm": "0.27.3", "@esbuild/linux-arm64": "0.27.3", "@esbuild/linux-ia32": "0.27.3", "@esbuild/linux-loong64": "0.27.3", "@esbuild/linux-mips64el": "0.27.3", "@esbuild/linux-ppc64": "0.27.3", "@esbuild/linux-riscv64": "0.27.3", "@esbuild/linux-s390x": "0.27.3", "@esbuild/linux-x64": "0.27.3", "@esbuild/netbsd-arm64": "0.27.3", "@esbuild/netbsd-x64": "0.27.3", "@esbuild/openbsd-arm64": "0.27.3", "@esbuild/openbsd-x64": "0.27.3", "@esbuild/openharmony-arm64": "0.27.3", "@esbuild/sunos-x64": "0.27.3", "@esbuild/win32-arm64": "0.27.3", "@esbuild/win32-ia32": "0.27.3", "@esbuild/win32-x64": "0.27.3" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg=="], - "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], + "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], - "estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="], + "escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="], - "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], + "estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], - "exit-hook": ["exit-hook@2.2.1", "", {}, "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw=="], + "expand-template": ["expand-template@2.0.3", "", {}, "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg=="], - "expect-type": ["expect-type@1.3.0", "", {}, "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA=="], + "extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="], "fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], "fastq": ["fastq@1.20.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw=="], + "fault": ["fault@2.0.1", "", { "dependencies": { "format": "^0.2.0" } }, "sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ=="], + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], - "filelist": ["filelist@1.0.4", "", { "dependencies": { "minimatch": "^5.0.1" } }, "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q=="], + "file-uri-to-path": ["file-uri-to-path@1.0.0", "", {}, "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="], - "filing-cabinet": ["filing-cabinet@5.0.3", "", { "dependencies": { "app-module-path": "^2.2.0", "commander": "^12.1.0", "enhanced-resolve": "^5.18.0", "module-definition": "^6.0.1", "module-lookup-amd": "^9.0.3", "resolve": "^1.22.10", "resolve-dependency-path": "^4.0.1", "sass-lookup": "^6.1.0", "stylus-lookup": "^6.1.0", "tsconfig-paths": "^4.2.0", "typescript": "^5.7.3" }, "bin": { "filing-cabinet": "bin/cli.js" } }, "sha512-PlPcMwVWg60NQkhvfoxZs4wEHjhlOO/y7OAm4sKM60o1Z9nttRY4mcdQxp/iZ+kg/Vv6Hw1OAaTbYVM9DA9pYg=="], + "filelist": ["filelist@1.0.4", "", { "dependencies": { "minimatch": "^5.0.1" } }, "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q=="], "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], "focus-trap": ["focus-trap@7.8.0", "", { "dependencies": { "tabbable": "^6.4.0" } }, "sha512-/yNdlIkpWbM0ptxno3ONTuf+2g318kh2ez3KSeZN5dZ8YC6AAmgeWz+GasYYiBJPFaYcSAPeu4GfhUaChzIJXA=="], - "fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="], + "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], - "fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="], + "format": ["format@0.2.2", "", {}, "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww=="], - "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + "fs-constants": ["fs-constants@1.0.0", "", {}, "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="], - "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], + "fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="], - "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], - "get-amd-module-type": ["get-amd-module-type@6.0.1", "", { "dependencies": { "ast-module-types": "^6.0.1", "node-source-walk": "^7.0.1" } }, "sha512-MtjsmYiCXcYDDrGqtNbeIYdAl85n+5mSv2r3FbzER/YV3ZILw4HNNIw34HuV5pyl0jzs6GFYU1VHVEefhgcNHQ=="], + "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], - "get-own-enumerable-property-symbols": ["get-own-enumerable-property-symbols@3.0.2", "", {}, "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g=="], - - "glob": ["glob@13.0.0", "", { "dependencies": { "minimatch": "^10.1.1", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA=="], + "get-tsconfig": ["get-tsconfig@4.13.6", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw=="], - "glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + "github-from-package": ["github-from-package@0.0.0", "", {}, "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw=="], - "glob-to-regexp": ["glob-to-regexp@0.4.1", "", {}, "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="], + "glob": ["glob@13.0.3", "", { "dependencies": { "minimatch": "^10.2.0", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-/g3B0mC+4x724v1TgtBlBtt2hPi/EWptsIAmXUx9Z2rvBYleQcsrmaOzd5LyL50jf/Soi83ZDJmw2+XqvH/EeA=="], - "gonzales-pe": ["gonzales-pe@4.3.0", "", { "dependencies": { "minimist": "^1.2.5" }, "bin": { "gonzales": "bin/gonzales.js" } }, "sha512-otgSPpUmdWJ43VXyiNgEYE4luzHCL2pz4wQ0OnDluC6Eg4Ko3Vexy/SrSynglw/eR+OhkzmqFCZa/OFa/RgAOQ=="], + "glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], - "happy-dom": ["happy-dom@20.1.0", "", { "dependencies": { "@types/node": "^20.0.0", "@types/whatwg-mimetype": "^3.0.2", "@types/ws": "^8.18.1", "whatwg-mimetype": "^3.0.0", "ws": "^8.18.3" } }, "sha512-ebvqjBqzenBk2LjzNEAzoj7yhw7rW/R2/wVevMu6Mrq3MXtcI/RUz4+ozpcOcqVLEWPqLfg2v9EAU7fFXZUUJw=="], - "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], - "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], - "hast-util-to-html": ["hast-util-to-html@9.0.5", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "ccount": "^2.0.0", "comma-separated-tokens": "^2.0.0", "hast-util-whitespace": "^3.0.0", "html-void-elements": "^3.0.0", "mdast-util-to-hast": "^13.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "stringify-entities": "^4.0.0", "zwitch": "^2.0.4" } }, "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw=="], "hast-util-whitespace": ["hast-util-whitespace@3.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw=="], @@ -909,6 +971,8 @@ "hookable": ["hookable@5.5.3", "", {}, "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="], + "hosted-git-info": ["hosted-git-info@7.0.2", "", { "dependencies": { "lru-cache": "^10.0.1" } }, "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w=="], + "html-entities": ["html-entities@2.3.3", "", {}, "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA=="], "html-minifier-terser": ["html-minifier-terser@6.1.0", "", { "dependencies": { "camel-case": "^4.1.2", "clean-css": "^5.2.2", "commander": "^8.3.0", "he": "^1.2.0", "param-case": "^3.0.4", "relateurl": "^0.2.7", "terser": "^5.10.0" }, "bin": { "html-minifier-terser": "cli.js" } }, "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw=="], @@ -917,17 +981,25 @@ "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], - "indent-string": ["indent-string@4.0.0", "", {}, "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg=="], + "ignore": ["ignore@6.0.2", "", {}, "sha512-InwqeHHN2XpumIkMvpl/DCJVrAHgCsG5+cn1XlnLWGwtZBm8QJfSusItfrwx81CTp5agNZqpKU2J/ccC5nGT4A=="], - "inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="], + "import-meta-resolve": ["import-meta-resolve@4.2.0", "", {}, "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg=="], "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], "ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="], - "is-arrayish": ["is-arrayish@0.3.4", "", {}, "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA=="], + "is-alphabetical": ["is-alphabetical@2.0.1", "", {}, "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ=="], + + "is-alphanumerical": ["is-alphanumerical@2.0.1", "", { "dependencies": { "is-alphabetical": "^2.0.0", "is-decimal": "^2.0.0" } }, "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw=="], + + "is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="], + + "is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="], - "is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="], + "is-decimal": ["is-decimal@2.0.1", "", {}, "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A=="], + + "is-empty": ["is-empty@1.2.0", "", {}, "sha512-F2FnH/otLNJv0J6wc73A5Xo7oHLNnqplYqZhUu01tD54DIPvxIRSTSLkrUB/M0nHO4vo1O9PDfN4KoTxCzLh/w=="], "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], @@ -935,21 +1007,17 @@ "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], - "is-interactive": ["is-interactive@1.0.0", "", {}, "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w=="], + "is-hexadecimal": ["is-hexadecimal@2.0.1", "", {}, "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg=="], "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], - "is-obj": ["is-obj@1.0.1", "", {}, "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg=="], - - "is-regexp": ["is-regexp@1.0.0", "", {}, "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA=="], - - "is-unicode-supported": ["is-unicode-supported@0.1.0", "", {}, "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw=="], + "is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="], - "is-url": ["is-url@1.2.4", "", {}, "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww=="], + "is-what": ["is-what@4.1.16", "", {}, "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A=="], - "is-url-superb": ["is-url-superb@4.0.0", "", {}, "sha512-GI+WjezhPPcbM+tqE9LnmsY5qqjwHzTvjJ36wxYX5ujNXefSUJ/T17r5bqDV8yLhcgB59KTPNOc9O9cmHTPWsA=="], + "isexe": ["isexe@4.0.0", "", {}, "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw=="], - "is-what": ["is-what@4.1.16", "", {}, "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A=="], + "jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], "jake": ["jake@10.9.4", "", { "dependencies": { "async": "^3.2.6", "filelist": "^1.0.4", "picocolors": "^1.1.1" }, "bin": { "jake": "bin/cli.js" } }, "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA=="], @@ -957,10 +1025,12 @@ "jose": ["jose@6.1.3", "", {}, "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ=="], - "js-tokens": ["js-tokens@9.0.1", "", {}, "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ=="], + "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], + "json-parse-even-better-errors": ["json-parse-even-better-errors@3.0.2", "", {}, "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ=="], + "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], "jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], @@ -991,49 +1061,103 @@ "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw=="], - "log-symbols": ["log-symbols@4.1.0", "", { "dependencies": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" } }, "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg=="], + "lines-and-columns": ["lines-and-columns@2.0.4", "", {}, "sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A=="], - "loupe": ["loupe@3.2.1", "", {}, "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ=="], + "load-plugin": ["load-plugin@6.0.3", "", { "dependencies": { "@npmcli/config": "^8.0.0", "import-meta-resolve": "^4.0.0" } }, "sha512-kc0X2FEUZr145odl68frm+lMJuQ23+rTXYmR6TImqPtbpmXC4vVXbWKDQ9IzndA0HfyQamWfKLhzsqGSTxE63w=="], - "lower-case": ["lower-case@2.0.2", "", { "dependencies": { "tslib": "^2.0.3" } }, "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg=="], - - "lru-cache": ["lru-cache@11.2.4", "", {}, "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg=="], + "longest-streak": ["longest-streak@3.1.0", "", {}, "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g=="], - "lz-string": ["lz-string@1.5.0", "", { "bin": { "lz-string": "bin/bin.js" } }, "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ=="], + "lower-case": ["lower-case@2.0.2", "", { "dependencies": { "tslib": "^2.0.3" } }, "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg=="], - "madge": ["madge@8.0.0", "", { "dependencies": { "chalk": "^4.1.2", "commander": "^7.2.0", "commondir": "^1.0.1", "debug": "^4.3.4", "dependency-tree": "^11.0.0", "ora": "^5.4.1", "pluralize": "^8.0.0", "pretty-ms": "^7.0.1", "rc": "^1.2.8", "stream-to-array": "^2.3.0", "ts-graphviz": "^2.1.2", "walkdir": "^0.4.1" }, "peerDependencies": { "typescript": "^5.4.4" }, "optionalPeers": ["typescript"], "bin": { "madge": "bin/cli.js" } }, "sha512-9sSsi3TBPhmkTCIpVQF0SPiChj1L7Rq9kU2KDG1o6v2XH9cCw086MopjVCD+vuoL5v8S77DTbVopTO8OUiQpIw=="], + "lru-cache": ["lru-cache@11.2.6", "", {}, "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ=="], "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], "mark.js": ["mark.js@8.11.1", "", {}, "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ=="], + "markdown-extensions": ["markdown-extensions@2.0.0", "", {}, "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q=="], + + "mdast-comment-marker": ["mdast-comment-marker@3.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-mdx-expression": "^2.0.0" } }, "sha512-bt08sLmTNg00/UtVDiqZKocxqvQqqyQZAg1uaRuO/4ysXV5motg7RolF5o5yy/sY1rG0v2XgZEqFWho1+2UquA=="], + + "mdast-util-directive": ["mdast-util-directive@3.1.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "ccount": "^2.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0", "parse-entities": "^4.0.0", "stringify-entities": "^4.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-I3fNFt+DHmpWCYAT7quoM6lHf9wuqtI+oCOfvILnoicNIqjh5E3dEJWiXuYME2gNe8vl1iMQwyUHa7bgFmak6Q=="], + + "mdast-util-from-markdown": ["mdast-util-from-markdown@2.0.3", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "mdast-util-to-string": "^4.0.0", "micromark": "^4.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-decode-string": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q=="], + + "mdast-util-frontmatter": ["mdast-util-frontmatter@2.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "escape-string-regexp": "^5.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0", "micromark-extension-frontmatter": "^2.0.0" } }, "sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA=="], + + "mdast-util-heading-style": ["mdast-util-heading-style@3.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0" } }, "sha512-tsUfM9Kj9msjlemA/38Z3pvraQay880E3zP2NgIthMoGcpU9bcPX9oSM6QC/+eFXGGB4ba+VCB1dKAPHB7Veug=="], + + "mdast-util-mdx": ["mdast-util-mdx@3.0.0", "", { "dependencies": { "mdast-util-from-markdown": "^2.0.0", "mdast-util-mdx-expression": "^2.0.0", "mdast-util-mdx-jsx": "^3.0.0", "mdast-util-mdxjs-esm": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w=="], + + "mdast-util-mdx-expression": ["mdast-util-mdx-expression@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ=="], + + "mdast-util-mdx-jsx": ["mdast-util-mdx-jsx@3.2.0", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "ccount": "^2.0.0", "devlop": "^1.1.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0", "parse-entities": "^4.0.0", "stringify-entities": "^4.0.0", "unist-util-stringify-position": "^4.0.0", "vfile-message": "^4.0.0" } }, "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q=="], + + "mdast-util-mdxjs-esm": ["mdast-util-mdxjs-esm@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg=="], + + "mdast-util-phrasing": ["mdast-util-phrasing@4.1.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "unist-util-is": "^6.0.0" } }, "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w=="], + "mdast-util-to-hast": ["mdast-util-to-hast@13.2.1", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "@ungap/structured-clone": "^1.0.0", "devlop": "^1.0.0", "micromark-util-sanitize-uri": "^2.0.0", "trim-lines": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" } }, "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA=="], + "mdast-util-to-markdown": ["mdast-util-to-markdown@2.1.2", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "longest-streak": "^3.0.0", "mdast-util-phrasing": "^4.0.0", "mdast-util-to-string": "^4.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-decode-string": "^2.0.0", "unist-util-visit": "^5.0.0", "zwitch": "^2.0.0" } }, "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA=="], + + "mdast-util-to-string": ["mdast-util-to-string@4.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0" } }, "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg=="], + "merge-anything": ["merge-anything@5.1.7", "", { "dependencies": { "is-what": "^4.1.8" } }, "sha512-eRtbOb1N5iyH0tkQDAoQ4Ipsp/5qSR79Dzrz8hEPxRX10RWWR/iQXdoKmBSRCThY1Fh5EhISDtpSc93fpxUniQ=="], "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], + "micromark": ["micromark@4.0.2", "", { "dependencies": { "@types/debug": "^4.0.0", "debug": "^4.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-combine-extensions": "^2.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA=="], + + "micromark-core-commonmark": ["micromark-core-commonmark@2.0.3", "", { "dependencies": { "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-factory-destination": "^2.0.0", "micromark-factory-label": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-factory-title": "^2.0.0", "micromark-factory-whitespace": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-html-tag-name": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg=="], + + "micromark-extension-frontmatter": ["micromark-extension-frontmatter@2.0.0", "", { "dependencies": { "fault": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg=="], + + "micromark-factory-destination": ["micromark-factory-destination@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA=="], + + "micromark-factory-label": ["micromark-factory-label@2.0.1", "", { "dependencies": { "devlop": "^1.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg=="], + + "micromark-factory-space": ["micromark-factory-space@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg=="], + + "micromark-factory-title": ["micromark-factory-title@2.0.1", "", { "dependencies": { "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw=="], + + "micromark-factory-whitespace": ["micromark-factory-whitespace@2.0.1", "", { "dependencies": { "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ=="], + "micromark-util-character": ["micromark-util-character@2.1.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q=="], + "micromark-util-chunked": ["micromark-util-chunked@2.0.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA=="], + + "micromark-util-classify-character": ["micromark-util-classify-character@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q=="], + + "micromark-util-combine-extensions": ["micromark-util-combine-extensions@2.0.1", "", { "dependencies": { "micromark-util-chunked": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg=="], + + "micromark-util-decode-numeric-character-reference": ["micromark-util-decode-numeric-character-reference@2.0.2", "", { "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw=="], + + "micromark-util-decode-string": ["micromark-util-decode-string@2.0.1", "", { "dependencies": { "decode-named-character-reference": "^1.0.0", "micromark-util-character": "^2.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-symbol": "^2.0.0" } }, "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ=="], + "micromark-util-encode": ["micromark-util-encode@2.0.1", "", {}, "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw=="], + "micromark-util-html-tag-name": ["micromark-util-html-tag-name@2.0.1", "", {}, "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA=="], + + "micromark-util-normalize-identifier": ["micromark-util-normalize-identifier@2.0.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q=="], + + "micromark-util-resolve-all": ["micromark-util-resolve-all@2.0.1", "", { "dependencies": { "micromark-util-types": "^2.0.0" } }, "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg=="], + "micromark-util-sanitize-uri": ["micromark-util-sanitize-uri@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-symbol": "^2.0.0" } }, "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ=="], + "micromark-util-subtokenize": ["micromark-util-subtokenize@2.1.0", "", { "dependencies": { "devlop": "^1.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA=="], + "micromark-util-symbol": ["micromark-util-symbol@2.0.1", "", {}, "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q=="], "micromark-util-types": ["micromark-util-types@2.0.2", "", {}, "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA=="], "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], - "mime": ["mime@3.0.0", "", { "bin": { "mime": "cli.js" } }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="], - - "mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="], + "mimic-response": ["mimic-response@3.1.0", "", {}, "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="], - "min-indent": ["min-indent@1.0.1", "", {}, "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg=="], + "miniflare": ["miniflare@4.20260212.0", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "sharp": "^0.34.5", "undici": "7.18.2", "workerd": "1.20260212.0", "ws": "8.18.0", "youch": "4.1.0-beta.10" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-Lgxq83EuR2q/0/DAVOSGXhXS1V7GDB04HVggoPsenQng8sqEDR3hO4FigIw5ZI2Sv2X7kIc30NCzGHJlCFIYWg=="], - "miniflare": ["miniflare@4.20260107.0", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "acorn": "8.14.0", "acorn-walk": "8.3.2", "exit-hook": "2.2.1", "glob-to-regexp": "0.4.1", "sharp": "^0.33.5", "stoppable": "1.1.0", "undici": "7.14.0", "workerd": "1.20260107.1", "ws": "8.18.0", "youch": "4.1.0-beta.10", "zod": "^3.25.76" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-X93sXczqbBq9ixoM6jnesmdTqp+4baVC/aM/DuPpRS0LK0XtcqaO75qPzNEvDEzBAHxwMAWRIum/9hg32YB8iA=="], - - "minimatch": ["minimatch@10.1.1", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ=="], + "minimatch": ["minimatch@10.2.0", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-ugkC31VaVg9cF0DFVoADH12k6061zNZkZON+aX8AWsR9GhPcErkcMBceb6znR8wLERM2AkkOxy2nWRLpT9Jq5w=="], "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], @@ -1041,57 +1165,75 @@ "minisearch": ["minisearch@7.2.0", "", {}, "sha512-dqT2XBYUOZOiC5t2HRnwADjhNS2cecp9u+TJRiJ1Qp/f5qjkeT5APcGPjHw+bz89Ms8Jp+cG4AlE+QZ/QnDglg=="], - "mitt": ["mitt@3.0.1", "", {}, "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw=="], + "minizlib": ["minizlib@3.1.0", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw=="], - "module-definition": ["module-definition@6.0.1", "", { "dependencies": { "ast-module-types": "^6.0.1", "node-source-walk": "^7.0.1" }, "bin": { "module-definition": "bin/cli.js" } }, "sha512-FeVc50FTfVVQnolk/WQT8MX+2WVcDnTGiq6Wo+/+lJ2ET1bRVi3HG3YlJUfqagNMc/kUlFSoR96AJkxGpKz13g=="], + "mitt": ["mitt@3.0.1", "", {}, "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw=="], - "module-lookup-amd": ["module-lookup-amd@9.0.5", "", { "dependencies": { "commander": "^12.1.0", "glob": "^7.2.3", "requirejs": "^2.3.7", "requirejs-config-file": "^4.0.0" }, "bin": { "lookup-amd": "bin/cli.js" } }, "sha512-Rs5FVpVcBYRHPLuhHOjgbRhosaQYLtEo3JIeDIbmNo7mSssi1CTzwMh8v36gAzpbzLGXI9wB/yHh+5+3fY1QVw=="], + "mkdirp-classic": ["mkdirp-classic@0.5.3", "", {}, "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="], "moq-doc": ["moq-doc@workspace:doc"], + "mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="], + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + "napi-build-utils": ["napi-build-utils@2.0.0", "", {}, "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA=="], + "no-case": ["no-case@3.0.4", "", { "dependencies": { "lower-case": "^2.0.2", "tslib": "^2.0.3" } }, "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg=="], + "node-abi": ["node-abi@3.87.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-+CGM1L1CgmtheLcBuleyYOn7NWPVu0s0EJH2C4puxgEZb9h8QpR9G2dBfZJOAUhi7VQxuBPMd0hiISWcTyiYyQ=="], + + "node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="], + + "node-api-headers": ["node-api-headers@1.8.0", "", {}, "sha512-jfnmiKWjRAGbdD1yQS28bknFM1tbHC1oucyuMPjmkEs+kpiu76aRs40WlTmBmyEgzDM76ge1DQ7XJ3R5deiVjQ=="], + "node-html-parser": ["node-html-parser@5.4.2", "", { "dependencies": { "css-select": "^4.2.1", "he": "1.2.0" } }, "sha512-RaBPP3+51hPne/OolXxcz89iYvQvKOydaqoePpOgXcrOKZhjVIzmpKZz+Hd/RBO2/zN2q6CNJhQzucVz+u3Jyw=="], "node-releases": ["node-releases@2.0.27", "", {}, "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="], - "node-source-walk": ["node-source-walk@7.0.1", "", { "dependencies": { "@babel/parser": "^7.26.7" } }, "sha512-3VW/8JpPqPvnJvseXowjZcirPisssnBuDikk6JIZ8jQzF7KJQX52iPFX4RYYxLycYH7IbMRSPUOga/esVjy5Yg=="], + "nopt": ["nopt@7.2.1", "", { "dependencies": { "abbrev": "^2.0.0" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w=="], + + "normalize-package-data": ["normalize-package-data@6.0.2", "", { "dependencies": { "hosted-git-info": "^7.0.0", "semver": "^7.3.5", "validate-npm-package-license": "^3.0.4" } }, "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g=="], + + "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], + + "npm-install-checks": ["npm-install-checks@6.3.0", "", { "dependencies": { "semver": "^7.1.1" } }, "sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw=="], + + "npm-normalize-package-bin": ["npm-normalize-package-bin@3.0.1", "", {}, "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ=="], + + "npm-package-arg": ["npm-package-arg@11.0.3", "", { "dependencies": { "hosted-git-info": "^7.0.0", "proc-log": "^4.0.0", "semver": "^7.3.5", "validate-npm-package-name": "^5.0.0" } }, "sha512-sHGJy8sOC1YraBywpzQlIKBE4pBbGbiF95U6Auspzyem956E0+FtDtsx1ZxlOJkQCZ1AFXAY/yuvtFYrOxF+Bw=="], + + "npm-pick-manifest": ["npm-pick-manifest@9.1.0", "", { "dependencies": { "npm-install-checks": "^6.0.0", "npm-normalize-package-bin": "^3.0.0", "npm-package-arg": "^11.0.0", "semver": "^7.3.5" } }, "sha512-nkc+3pIIhqHVQr085X9d2JzPzLyjzQS96zbruppqC9aZRm/x8xx6xhI98gHtsfELP2bE+loHq8ZaHFHhe+NauA=="], "nth-check": ["nth-check@2.1.1", "", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="], "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], - "onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="], - "oniguruma-to-es": ["oniguruma-to-es@3.1.1", "", { "dependencies": { "emoji-regex-xs": "^1.0.0", "regex": "^6.0.1", "regex-recursion": "^6.0.2" } }, "sha512-bUH8SDvPkH3ho3dvwJwfonjlQ4R80vjyvrU8YpxuROddv55vAEJrTuCuCVUhhsHbtlD9tGGbaNApGQckXhS8iQ=="], - "ora": ["ora@5.4.1", "", { "dependencies": { "bl": "^4.1.0", "chalk": "^4.1.0", "cli-cursor": "^3.1.0", "cli-spinners": "^2.5.0", "is-interactive": "^1.0.0", "is-unicode-supported": "^0.1.0", "log-symbols": "^4.1.0", "strip-ansi": "^6.0.0", "wcwidth": "^1.0.1" } }, "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ=="], - "package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="], + "package-manager-detector": ["package-manager-detector@1.6.0", "", {}, "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA=="], + "param-case": ["param-case@3.0.4", "", { "dependencies": { "dot-case": "^3.0.4", "tslib": "^2.0.3" } }, "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A=="], - "parse-ms": ["parse-ms@2.1.0", "", {}, "sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA=="], + "parse-entities": ["parse-entities@4.0.2", "", { "dependencies": { "@types/unist": "^2.0.0", "character-entities-legacy": "^3.0.0", "character-reference-invalid": "^2.0.0", "decode-named-character-reference": "^1.0.0", "is-alphanumerical": "^2.0.0", "is-decimal": "^2.0.0", "is-hexadecimal": "^2.0.0" } }, "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw=="], + + "parse-json": ["parse-json@7.1.1", "", { "dependencies": { "@babel/code-frame": "^7.21.4", "error-ex": "^1.3.2", "json-parse-even-better-errors": "^3.0.0", "lines-and-columns": "^2.0.3", "type-fest": "^3.8.0" } }, "sha512-SgOTCX/EZXtZxBE5eJ97P4yGM5n37BwRU+YMsH4vNzFqJV/oWFXXCmwFlgWUM4PrakybVOueJJ6pwHqSVhTFDw=="], "parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="], "pascal-case": ["pascal-case@3.1.2", "", { "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3" } }, "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g=="], - "path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="], - - "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], "path-scurry": ["path-scurry@2.0.1", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA=="], "path-to-regexp": ["path-to-regexp@6.3.0", "", {}, "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ=="], - "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], - - "pathval": ["pathval@2.0.1", "", {}, "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ=="], + "pathe": ["pathe@0.2.0", "", {}, "sha512-sTitTPYnn23esFR3RlqYBWn4c45WGeLcsKzQiUpXJAyfcWkolvlYpV8FLo7JishK946oQwMFUCHXQ9AjGPKExw=="], "perfect-debounce": ["perfect-debounce@1.0.0", "", {}, "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA=="], @@ -1105,29 +1247,31 @@ "postcss-selector-parser": ["postcss-selector-parser@6.0.10", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w=="], - "postcss-values-parser": ["postcss-values-parser@6.0.2", "", { "dependencies": { "color-name": "^1.1.4", "is-url-superb": "^4.0.0", "quote-unquote": "^1.0.0" }, "peerDependencies": { "postcss": "^8.2.9" } }, "sha512-YLJpK0N1brcNJrs9WatuJFtHaV9q5aAOj+S4DI5S7jgHlRfm0PIbDCAFRYMQD5SHq7Fy6xsDhyutgS0QOAs0qw=="], + "preact": ["preact@10.28.3", "", {}, "sha512-tCmoRkPQLpBeWzpmbhryairGnhW9tKV6c6gr/w+RhoRoKEJwsjzipwp//1oCpGPOchvSLaAPlpcJi9MwMmoPyA=="], - "preact": ["preact@10.28.2", "", {}, "sha512-lbteaWGzGHdlIuiJ0l2Jq454m6kcpI1zNje6d8MlGAFlYvP2GO4ibnat7P74Esfz4sPTdM6UxtTwh/d3pwM9JA=="], + "prebuild-install": ["prebuild-install@7.1.3", "", { "dependencies": { "detect-libc": "^2.0.0", "expand-template": "^2.0.3", "github-from-package": "0.0.0", "minimist": "^1.2.3", "mkdirp-classic": "^0.5.3", "napi-build-utils": "^2.0.0", "node-abi": "^3.3.0", "pump": "^3.0.0", "rc": "^1.2.7", "simple-get": "^4.0.0", "tar-fs": "^2.0.0", "tunnel-agent": "^0.6.0" }, "bin": { "prebuild-install": "bin.js" } }, "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug=="], - "precinct": ["precinct@12.2.0", "", { "dependencies": { "@dependents/detective-less": "^5.0.1", "commander": "^12.1.0", "detective-amd": "^6.0.1", "detective-cjs": "^6.0.1", "detective-es6": "^5.0.1", "detective-postcss": "^7.0.1", "detective-sass": "^6.0.1", "detective-scss": "^5.0.1", "detective-stylus": "^5.0.1", "detective-typescript": "^14.0.0", "detective-vue2": "^2.2.0", "module-definition": "^6.0.1", "node-source-walk": "^7.0.1", "postcss": "^8.5.1", "typescript": "^5.7.3" }, "bin": { "precinct": "bin/cli.js" } }, "sha512-NFBMuwIfaJ4SocE9YXPU/n4AcNSoFMVFjP72nvl3cx69j/ke61/hPOWFREVxLkFhhEGnA8ZuVfTqJBa+PK3b5w=="], + "proc-log": ["proc-log@4.2.0", "", {}, "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA=="], - "pretty-format": ["pretty-format@27.5.1", "", { "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", "react-is": "^17.0.1" } }, "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ=="], + "promise-inflight": ["promise-inflight@1.0.1", "", {}, "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g=="], - "pretty-ms": ["pretty-ms@7.0.1", "", { "dependencies": { "parse-ms": "^2.1.0" } }, "sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q=="], + "promise-retry": ["promise-retry@2.0.1", "", { "dependencies": { "err-code": "^2.0.2", "retry": "^0.12.0" } }, "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g=="], "property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="], - "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], + "publint": ["publint@0.3.18", "", { "dependencies": { "@publint/pack": "^0.1.4", "package-manager-detector": "^1.6.0", "picocolors": "^1.1.1", "sade": "^1.8.1" }, "bin": { "publint": "src/cli.js" } }, "sha512-JRJFeBTrfx4qLwEuGFPk+haJOJN97KnPuK01yj+4k/Wj5BgoOK5uNsivporiqBjk2JDaslg7qJOhGRnpltGeog=="], + + "pump": ["pump@3.0.3", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA=="], - "quote-unquote": ["quote-unquote@1.0.0", "", {}, "sha512-twwRO/ilhlG/FIgYeKGFqyHhoEhqgnKVkcmqMKi2r524gz3ZbDTcyFt38E9xjJI2vT+KbRNHVbnJ/e0I25Azwg=="], + "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], "rc": ["rc@1.2.8", "", { "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, "bin": { "rc": "./cli.js" } }, "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw=="], - "react-is": ["react-is@17.0.2", "", {}, "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="], + "read-package-json-fast": ["read-package-json-fast@3.0.2", "", { "dependencies": { "json-parse-even-better-errors": "^3.0.0", "npm-normalize-package-bin": "^3.0.0" } }, "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw=="], "readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], - "redent": ["redent@3.0.0", "", { "dependencies": { "indent-string": "^4.0.0", "strip-indent": "^3.0.0" } }, "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg=="], + "readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], "regex": ["regex@6.1.0", "", { "dependencies": { "regex-utilities": "^2.3.0" } }, "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg=="], @@ -1137,17 +1281,83 @@ "relateurl": ["relateurl@0.2.7", "", {}, "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog=="], - "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], + "remark": ["remark@15.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "remark-parse": "^11.0.0", "remark-stringify": "^11.0.0", "unified": "^11.0.0" } }, "sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A=="], + + "remark-cli": ["remark-cli@12.0.1", "", { "dependencies": { "import-meta-resolve": "^4.0.0", "markdown-extensions": "^2.0.0", "remark": "^15.0.0", "unified-args": "^11.0.0" }, "bin": { "remark": "cli.js" } }, "sha512-2NAEOACoTgo+e+YAaCTODqbrWyhMVmlUyjxNCkTrDRHHQvH6+NbrnqVvQaLH/Q8Ket3v90A43dgAJmXv8y5Tkw=="], + + "remark-frontmatter": ["remark-frontmatter@5.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-frontmatter": "^2.0.0", "micromark-extension-frontmatter": "^2.0.0", "unified": "^11.0.0" } }, "sha512-XTFYvNASMe5iPN0719nPrdItC9aU0ssC4v14mH1BCi1u0n1gAocqcujWUrByftZTbLhRtiKRyjYTSIOcr69UVQ=="], + + "remark-lint": ["remark-lint@10.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "remark-message-control": "^8.0.0", "unified": "^11.0.0" } }, "sha512-1+PYGFziOg4pH7DDf1uMd4AR3YuO2EMnds/SdIWMPGT7CAfDRSnAmpxPsJD0Ds3IKpn97h3d5KPGf1WFOg6hXQ=="], + + "remark-lint-blockquote-indentation": ["remark-lint-blockquote-indentation@4.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-phrasing": "^4.0.0", "pluralize": "^8.0.0", "unified-lint-rule": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-7BhOsImFgTD7IIliu2tt+yJbx5gbMbXCOspc3VdYf/87iLJdWKqJoMy2V6DZG7kBjBlBsIZi38fDDngJttXt4w=="], - "requirejs": ["requirejs@2.3.8", "", { "bin": { "r.js": "bin/r.js", "r_js": "bin/r.js" } }, "sha512-7/cTSLOdYkNBNJcDMWf+luFvMriVm7eYxp4BcFCsAX0wF421Vyce5SXP17c+Jd5otXKGNehIonFlyQXSowL6Mw=="], + "remark-lint-checkbox-character-style": ["remark-lint-checkbox-character-style@5.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-phrasing": "^4.0.0", "unified-lint-rule": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit-parents": "^6.0.0", "vfile-message": "^4.0.0" } }, "sha512-6qilm7XQXOcTvjFEqqNY57Ki7md9rkSdpMIfIzVXdEnI4Npl2BnUff6ANrGRM7qTgJTrloaf8H0eQ91urcU6Og=="], - "requirejs-config-file": ["requirejs-config-file@4.0.0", "", { "dependencies": { "esprima": "^4.0.0", "stringify-object": "^3.2.1" } }, "sha512-jnIre8cbWOyvr8a5F2KuqBnY+SDA4NXr/hzEZJG79Mxm2WiFQz2dzhC8ibtPJS7zkmBEl1mxSwp5HhC1W4qpxw=="], + "remark-lint-code-block-style": ["remark-lint-code-block-style@4.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-phrasing": "^4.0.0", "unified-lint-rule": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit-parents": "^6.0.0", "vfile-message": "^4.0.0" } }, "sha512-d4mHsEpv1yqXWl2dd+28tGRX0Lzk5qw7cfxAQVkOXPUONhsMFwXJEBeeqZokeG4lOKtkKdIJR7ezScDfWR0X4w=="], - "resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="], + "remark-lint-emphasis-marker": ["remark-lint-emphasis-marker@4.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "unified-lint-rule": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit-parents": "^6.0.0", "vfile-message": "^4.0.0" } }, "sha512-BF1WWsAxai3XoKk48sfiqT3L8m02AZLj3BnipWkHDRXuLfz6VwsHVaHWyNvvE0p6b2B3A5dSYbcfJu5RmPx4tQ=="], - "resolve-dependency-path": ["resolve-dependency-path@4.0.1", "", {}, "sha512-YQftIIC4vzO9UMhO/sCgXukNyiwVRCVaxiWskCBy7Zpqkplm8kTAISZ8O1MoKW1ca6xzgLUBjZTcDgypXvXxiQ=="], + "remark-lint-fenced-code-marker": ["remark-lint-fenced-code-marker@4.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-phrasing": "^4.0.0", "unified-lint-rule": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit-parents": "^6.0.0", "vfile-message": "^4.0.0" } }, "sha512-uI91OcVPKjNxV+vpjDW9T64hkE0a/CRn3JhwdMxUAJYpVsKnA7PFPSFJOx/abNsVZHNSe7ZFGgGdaH/lqgSizA=="], - "restore-cursor": ["restore-cursor@3.1.0", "", { "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" } }, "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA=="], + "remark-lint-final-newline": ["remark-lint-final-newline@3.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "unified-lint-rule": "^3.0.0", "vfile-location": "^5.0.0" } }, "sha512-q5diKHD6BMbzqWqgvYPOB8AJgLrMzEMBAprNXjcpKoZ/uCRqly+gxjco+qVUMtMWSd+P+KXZZEqoa7Y6QiOudw=="], + + "remark-lint-hard-break-spaces": ["remark-lint-hard-break-spaces@4.1.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "unified-lint-rule": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit": "^5.0.0" } }, "sha512-AKDPDt39fvmr3yk38OKZEWJxxCOOUBE+96AsBfs+ExS5LW6oLa9041X5ahFDQHvHGzdoremEIaaElursaPEkNg=="], + + "remark-lint-heading-style": ["remark-lint-heading-style@4.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-heading-style": "^3.0.0", "mdast-util-phrasing": "^4.0.0", "unified-lint-rule": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit-parents": "^6.0.0", "vfile-message": "^4.0.0" } }, "sha512-+rUpJ/N2CGC5xPgZ18XgsCsUBtadgEhdTi0BJPrsFmHPzL22BUHajeg9im8Y7zphUcbi1qFiKuxZd2nzDgZSXQ=="], + + "remark-lint-link-title-style": ["remark-lint-link-title-style@4.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "unified-lint-rule": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit-parents": "^6.0.0", "vfile-message": "^4.0.0" } }, "sha512-MtmnYrhjhRXR0zeiyYf/7GBlUF5KAPypJb345KjyDluOhI4Wj4VAXvVQuov/MFc3y8p/1yVwv3QDYv6yue8/wQ=="], + + "remark-lint-list-item-bullet-indent": ["remark-lint-list-item-bullet-indent@5.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "pluralize": "^8.0.0", "unified-lint-rule": "^3.0.0", "unist-util-position": "^5.0.0" } }, "sha512-LKuTxkw5aYChzZoF3BkfaBheSCHs0T8n8dPHLQEuOLo6iC5wy98iyryz0KZ61GD8stlZgQO2KdWSdnP6vr40Iw=="], + + "remark-lint-list-item-content-indent": ["remark-lint-list-item-content-indent@4.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-phrasing": "^4.0.0", "pluralize": "^8.0.0", "unified-lint-rule": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit-parents": "^6.0.0", "vfile-message": "^4.0.0" } }, "sha512-KSopxxp64O6dLuTQ2sWaTqgjKWr1+AoB1QCTektMJ3mfHfn0QyZzC2CZbBU22KGzBhiYXv9cIxlJlxUtq2NqHg=="], + + "remark-lint-list-item-indent": ["remark-lint-list-item-indent@4.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-phrasing": "^4.0.0", "pluralize": "^8.0.0", "unified-lint-rule": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-gJd1Q+jOAeTgmGRsdMpnRh01DUrAm0O5PCQxE8ttv1QZOV015p/qJH+B4N6QSmcUuPokHLAh9USuq05C73qpiA=="], + + "remark-lint-maximum-line-length": ["remark-lint-maximum-line-length@4.1.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-mdx": "^3.0.0", "pluralize": "^8.0.0", "unified-lint-rule": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit": "^5.0.0" } }, "sha512-oIncZkI0oIXZk+1kJOMnE3WPbyMTUbds0q1E8WbCwtjN9pAZsQD2e+wK+xdi5VqOLPkvLER+yzbmi/A3Tp+XEg=="], + + "remark-lint-no-blockquote-without-marker": ["remark-lint-no-blockquote-without-marker@6.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-directive": "^3.0.0", "mdast-util-phrasing": "^4.0.0", "pluralize": "^8.0.0", "unified-lint-rule": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit-parents": "^6.0.0", "vfile-location": "^5.0.0" } }, "sha512-b4IOkNcG7C16HYAdKUeAhO7qPt45m+v7SeYbVrqvbSFtlD3EUBL8fgHRgLK1mdujFXDP1VguOEMx+Txv8JOT4w=="], + + "remark-lint-no-duplicate-definitions": ["remark-lint-no-duplicate-definitions@4.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-phrasing": "^4.0.0", "unified-lint-rule": "^3.0.0", "unist-util-visit-parents": "^6.0.0", "vfile-message": "^4.0.0" } }, "sha512-Ek+A/xDkv5Nn+BXCFmf+uOrFSajCHj6CjhsHjtROgVUeEPj726yYekDBoDRA0Y3+z+U30AsJoHgf/9Jj1IFSug=="], + + "remark-lint-no-duplicate-headings": ["remark-lint-no-duplicate-headings@4.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-mdx": "^3.0.0", "mdast-util-to-string": "^4.0.0", "unified-lint-rule": "^3.0.0", "unist-util-visit-parents": "^6.0.0", "vfile-message": "^4.0.0" } }, "sha512-6lggqnpIe5FepikjYF2me3ovKV4oD/rAz8WmwVbLR2cLkce1iH+PB7jyxk/A2gQQqrDcIlRMA5Ct2Yj56cEwhQ=="], + + "remark-lint-no-heading-content-indent": ["remark-lint-no-heading-content-indent@5.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-phrasing": "^4.0.0", "pluralize": "^8.0.0", "unified-lint-rule": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-YIWktnZo7M9aw7PGnHdshvetSH3Y0qW+Fm143R66zsk5lLzn1XA5NEd/MtDzP8tSxxV+gcv+bDd5St1QUI4oSQ=="], + + "remark-lint-no-literal-urls": ["remark-lint-no-literal-urls@4.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-to-string": "^4.0.0", "micromark-util-character": "^2.0.0", "unified-lint-rule": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-RhTANFkFFXE6bM+WxWcPo2TTPEfkWG3lJZU50ycW7tJJmxUzDNzRed/z80EVJIdGwFa0NntVooLUJp3xrogalQ=="], + + "remark-lint-no-shortcut-reference-image": ["remark-lint-no-shortcut-reference-image@4.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "unified-lint-rule": "^3.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-hQhJ3Dr8ZWRdj7qm6+9vcPpqtGchhENA2UHOmcTraLf6dN1cFATCgY/HbTbRIN6NkG/EEClTgRC1QCokWR2Mmw=="], + + "remark-lint-no-shortcut-reference-link": ["remark-lint-no-shortcut-reference-link@4.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "unified-lint-rule": "^3.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-YxciuUZc90QaJYhayGO80lS3zxEOBgwwLW1MKYB7AfUdkrLcLVlS+DFloiq0MZ7EDVXuuGUEnIzyjyLSbI5BUA=="], + + "remark-lint-no-undefined-references": ["remark-lint-no-undefined-references@5.0.2", "", { "dependencies": { "@types/mdast": "^4.0.0", "collapse-white-space": "^2.0.0", "devlop": "^1.0.0", "micromark-util-normalize-identifier": "^2.0.0", "unified-lint-rule": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit-parents": "^6.0.0", "vfile-location": "^5.0.0" } }, "sha512-5prkVb1tKwJwr5+kct/UjsLjvMdEDO7uClPeGfrxfAcN59+pWU8OUSYiqYmpSKWJPIdyxPRS8Oyf1HtaYvg8VQ=="], + + "remark-lint-no-unused-definitions": ["remark-lint-no-unused-definitions@4.0.2", "", { "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "unified-lint-rule": "^3.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-KRzPmvfq6b3LSEcAQZobAn+5eDfPTle0dPyDEywgPSc3E7MIdRZQenL9UL8iIqHQWK4FvdUD0GX8FXGqu5EuCw=="], + + "remark-lint-ordered-list-marker-style": ["remark-lint-ordered-list-marker-style@4.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-phrasing": "^4.0.0", "micromark-util-character": "^2.0.0", "unified-lint-rule": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit-parents": "^6.0.0", "vfile-message": "^4.0.0" } }, "sha512-vZTAbstcBPbGwJacwldGzdGmKwy5/4r29SZ9nQkME4alEl5B1ReSBlYa8t7QnTSW7+tqvA9Sg71RPadgAKWa4w=="], + + "remark-lint-ordered-list-marker-value": ["remark-lint-ordered-list-marker-value@4.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-phrasing": "^4.0.0", "micromark-util-character": "^2.0.0", "unified-lint-rule": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit-parents": "^6.0.0", "vfile-message": "^4.0.0" } }, "sha512-HQb1MrArvApREC1/I6bkiFlZVDjngsuII29n8E8StnAaHOMN3hVYy6wJ9Uk+O3+X9O8v7fDsZPqFUHSfJhERXQ=="], + + "remark-lint-rule-style": ["remark-lint-rule-style@4.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-phrasing": "^4.0.0", "unified-lint-rule": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit-parents": "^6.0.0", "vfile-message": "^4.0.0" } }, "sha512-gl1Ft13oTS3dJUCsWZzxD/5dAwI1HON67KU7uNfODD5gXJ8Y11deOWbun190ma7XbYdD7P0l8VT2HeRtEQzrWg=="], + + "remark-lint-strong-marker": ["remark-lint-strong-marker@4.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "unified-lint-rule": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit-parents": "^6.0.0", "vfile-message": "^4.0.0" } }, "sha512-KaGtj/OWEP4eoafevnlp3NsEVwC7yGEjBJ6uFMzfjNoXyjATdfZ2euB/AfKVt/A/FdZeeMeVoAUFH4DL+hScLQ=="], + + "remark-lint-table-cell-padding": ["remark-lint-table-cell-padding@5.1.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "devlop": "^1.0.0", "mdast-util-phrasing": "^4.0.0", "pluralize": "^8.0.0", "unified-lint-rule": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit-parents": "^6.0.0", "vfile-message": "^4.0.0" } }, "sha512-6fgVA1iINBoAJaZMOnSsxrF9Qj9+hmCqrsrqZqgJJETjT1ODGH64iAN1/6vHR7dIwmy73d6ysB2WrGyKhVlK3A=="], + + "remark-message-control": ["remark-message-control@8.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-comment-marker": "^3.0.0", "unified-message-control": "^5.0.0", "vfile": "^6.0.0" } }, "sha512-brpzOO+jdyE/mLqvqqvbogmhGxKygjpCUCG/PwSCU43+JZQ+RM+sSzkCWBcYvgF3KIAVNIoPsvXjBkzO7EdsYQ=="], + + "remark-parse": ["remark-parse@11.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-from-markdown": "^2.0.0", "micromark-util-types": "^2.0.0", "unified": "^11.0.0" } }, "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA=="], + + "remark-preset-lint-consistent": ["remark-preset-lint-consistent@6.0.1", "", { "dependencies": { "remark-lint": "^10.0.0", "remark-lint-blockquote-indentation": "^4.0.0", "remark-lint-checkbox-character-style": "^5.0.0", "remark-lint-code-block-style": "^4.0.0", "remark-lint-emphasis-marker": "^4.0.0", "remark-lint-fenced-code-marker": "^4.0.0", "remark-lint-heading-style": "^4.0.0", "remark-lint-link-title-style": "^4.0.0", "remark-lint-list-item-content-indent": "^4.0.0", "remark-lint-ordered-list-marker-style": "^4.0.0", "remark-lint-ordered-list-marker-value": "^4.0.0", "remark-lint-rule-style": "^4.0.0", "remark-lint-strong-marker": "^4.0.0", "remark-lint-table-cell-padding": "^5.0.0", "unified": "^11.0.0" } }, "sha512-SOLdA36UOU1hiGFm6HAqN9+DORGJPVWxU/EvPVkknTr9V4ULhlzHEJ8OVRMVX3jqoy4lrwb4IqiboVz0YLA7+Q=="], + + "remark-preset-lint-recommended": ["remark-preset-lint-recommended@7.0.1", "", { "dependencies": { "remark-lint": "^10.0.0", "remark-lint-final-newline": "^3.0.0", "remark-lint-hard-break-spaces": "^4.0.0", "remark-lint-list-item-bullet-indent": "^5.0.0", "remark-lint-list-item-indent": "^4.0.0", "remark-lint-no-blockquote-without-marker": "^6.0.0", "remark-lint-no-duplicate-definitions": "^4.0.0", "remark-lint-no-heading-content-indent": "^5.0.0", "remark-lint-no-literal-urls": "^4.0.0", "remark-lint-no-shortcut-reference-image": "^4.0.0", "remark-lint-no-shortcut-reference-link": "^4.0.0", "remark-lint-no-undefined-references": "^5.0.0", "remark-lint-no-unused-definitions": "^4.0.0", "remark-lint-ordered-list-marker-style": "^4.0.0", "unified": "^11.0.0" } }, "sha512-j1CY5u48PtZl872BQ40uWSQMT3R4gXKp0FUgevMu5gW7hFMtvaCiDq+BfhzeR8XKKiW9nIMZGfIMZHostz5X4g=="], + + "remark-stringify": ["remark-stringify@11.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-to-markdown": "^2.0.0", "unified": "^11.0.0" } }, "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw=="], + + "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], + + "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], + + "retry": ["retry@0.12.0", "", {}, "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow=="], "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], @@ -1155,39 +1365,43 @@ "rimraf": ["rimraf@6.1.2", "", { "dependencies": { "glob": "^13.0.0", "package-json-from-dist": "^1.0.1" }, "bin": { "rimraf": "dist/esm/bin.mjs" } }, "sha512-cFCkPslJv7BAXJsYlK1dZsbP8/ZNLkCAQ0bi1hf5EKX2QHegmDFEFA6QhuYJlk7UDdc+02JjO80YSOrWPpw06g=="], - "rollup": ["rollup@4.55.1", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.55.1", "@rollup/rollup-android-arm64": "4.55.1", "@rollup/rollup-darwin-arm64": "4.55.1", "@rollup/rollup-darwin-x64": "4.55.1", "@rollup/rollup-freebsd-arm64": "4.55.1", "@rollup/rollup-freebsd-x64": "4.55.1", "@rollup/rollup-linux-arm-gnueabihf": "4.55.1", "@rollup/rollup-linux-arm-musleabihf": "4.55.1", "@rollup/rollup-linux-arm64-gnu": "4.55.1", "@rollup/rollup-linux-arm64-musl": "4.55.1", "@rollup/rollup-linux-loong64-gnu": "4.55.1", "@rollup/rollup-linux-loong64-musl": "4.55.1", "@rollup/rollup-linux-ppc64-gnu": "4.55.1", "@rollup/rollup-linux-ppc64-musl": "4.55.1", "@rollup/rollup-linux-riscv64-gnu": "4.55.1", "@rollup/rollup-linux-riscv64-musl": "4.55.1", "@rollup/rollup-linux-s390x-gnu": "4.55.1", "@rollup/rollup-linux-x64-gnu": "4.55.1", "@rollup/rollup-linux-x64-musl": "4.55.1", "@rollup/rollup-openbsd-x64": "4.55.1", "@rollup/rollup-openharmony-arm64": "4.55.1", "@rollup/rollup-win32-arm64-msvc": "4.55.1", "@rollup/rollup-win32-ia32-msvc": "4.55.1", "@rollup/rollup-win32-x64-gnu": "4.55.1", "@rollup/rollup-win32-x64-msvc": "4.55.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A=="], + "rollup": ["rollup@4.57.1", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.57.1", "@rollup/rollup-android-arm64": "4.57.1", "@rollup/rollup-darwin-arm64": "4.57.1", "@rollup/rollup-darwin-x64": "4.57.1", "@rollup/rollup-freebsd-arm64": "4.57.1", "@rollup/rollup-freebsd-x64": "4.57.1", "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", "@rollup/rollup-linux-arm-musleabihf": "4.57.1", "@rollup/rollup-linux-arm64-gnu": "4.57.1", "@rollup/rollup-linux-arm64-musl": "4.57.1", "@rollup/rollup-linux-loong64-gnu": "4.57.1", "@rollup/rollup-linux-loong64-musl": "4.57.1", "@rollup/rollup-linux-ppc64-gnu": "4.57.1", "@rollup/rollup-linux-ppc64-musl": "4.57.1", "@rollup/rollup-linux-riscv64-gnu": "4.57.1", "@rollup/rollup-linux-riscv64-musl": "4.57.1", "@rollup/rollup-linux-s390x-gnu": "4.57.1", "@rollup/rollup-linux-x64-gnu": "4.57.1", "@rollup/rollup-linux-x64-musl": "4.57.1", "@rollup/rollup-openbsd-x64": "4.57.1", "@rollup/rollup-openharmony-arm64": "4.57.1", "@rollup/rollup-win32-arm64-msvc": "4.57.1", "@rollup/rollup-win32-ia32-msvc": "4.57.1", "@rollup/rollup-win32-x64-gnu": "4.57.1", "@rollup/rollup-win32-x64-msvc": "4.57.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A=="], "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], "rxjs": ["rxjs@7.8.2", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA=="], - "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + "sade": ["sade@1.8.1", "", { "dependencies": { "mri": "^1.1.0" } }, "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A=="], - "sass-lookup": ["sass-lookup@6.1.0", "", { "dependencies": { "commander": "^12.1.0", "enhanced-resolve": "^5.18.0" }, "bin": { "sass-lookup": "bin/cli.js" } }, "sha512-Zx+lVyoWqXZxHuYWlTA17Z5sczJ6braNT2C7rmClw+c4E7r/n911Zwss3h1uHI9reR5AgHZyNHF7c2+VIp5AUA=="], + "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], "search-insights": ["search-insights@2.17.3", "", {}, "sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ=="], "semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - "seroval": ["seroval@1.3.2", "", {}, "sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ=="], + "seroval": ["seroval@1.5.0", "", {}, "sha512-OE4cvmJ1uSPrKorFIH9/w/Qwuvi/IMcGbv5RKgcJ/zjA/IohDLU6SVaxFN9FwajbP7nsX0dQqMDes1whk3y+yw=="], - "seroval-plugins": ["seroval-plugins@1.3.3", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-16OL3NnUBw8JG1jBLUoZJsLnQq0n5Ua6aHalhJK4fMQkz1lqR7Osz1sA30trBtd9VUDc2NgkuRCn8+/pBwqZ+w=="], + "seroval-plugins": ["seroval-plugins@1.5.0", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-EAHqADIQondwRZIdeW2I636zgsODzoBDwb3PT/+7TLDWyw1Dy/Xv7iGUIEXXav7usHDE9HVhOU61irI3EnyyHA=="], - "sharp": ["sharp@0.33.5", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.3", "semver": "^7.6.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.33.5", "@img/sharp-darwin-x64": "0.33.5", "@img/sharp-libvips-darwin-arm64": "1.0.4", "@img/sharp-libvips-darwin-x64": "1.0.4", "@img/sharp-libvips-linux-arm": "1.0.5", "@img/sharp-libvips-linux-arm64": "1.0.4", "@img/sharp-libvips-linux-s390x": "1.0.4", "@img/sharp-libvips-linux-x64": "1.0.4", "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", "@img/sharp-libvips-linuxmusl-x64": "1.0.4", "@img/sharp-linux-arm": "0.33.5", "@img/sharp-linux-arm64": "0.33.5", "@img/sharp-linux-s390x": "0.33.5", "@img/sharp-linux-x64": "0.33.5", "@img/sharp-linuxmusl-arm64": "0.33.5", "@img/sharp-linuxmusl-x64": "0.33.5", "@img/sharp-wasm32": "0.33.5", "@img/sharp-win32-ia32": "0.33.5", "@img/sharp-win32-x64": "0.33.5" } }, "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw=="], + "sharp": ["sharp@0.34.5", "", { "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", "semver": "^7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.5", "@img/sharp-darwin-x64": "0.34.5", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", "@img/sharp-libvips-linux-arm64": "1.2.4", "@img/sharp-libvips-linux-ppc64": "1.2.4", "@img/sharp-libvips-linux-riscv64": "1.2.4", "@img/sharp-libvips-linux-s390x": "1.2.4", "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", "@img/sharp-linux-arm": "0.34.5", "@img/sharp-linux-arm64": "0.34.5", "@img/sharp-linux-ppc64": "0.34.5", "@img/sharp-linux-riscv64": "0.34.5", "@img/sharp-linux-s390x": "0.34.5", "@img/sharp-linux-x64": "0.34.5", "@img/sharp-linuxmusl-arm64": "0.34.5", "@img/sharp-linuxmusl-x64": "0.34.5", "@img/sharp-wasm32": "0.34.5", "@img/sharp-win32-arm64": "0.34.5", "@img/sharp-win32-ia32": "0.34.5", "@img/sharp-win32-x64": "0.34.5" } }, "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg=="], + + "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], "shell-quote": ["shell-quote@1.8.3", "", {}, "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw=="], "shiki": ["shiki@2.5.0", "", { "dependencies": { "@shikijs/core": "2.5.0", "@shikijs/engine-javascript": "2.5.0", "@shikijs/engine-oniguruma": "2.5.0", "@shikijs/langs": "2.5.0", "@shikijs/themes": "2.5.0", "@shikijs/types": "2.5.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-mI//trrsaiCIPsja5CNfsyNOqgAZUb6VpJA+340toL42UpzQlXpwRV9nch69X6gaUxrr9kaOOa6e3y3uAkGFxQ=="], - "siginfo": ["siginfo@2.0.0", "", {}, "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g=="], + "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], - "signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], + "simple-concat": ["simple-concat@1.0.1", "", {}, "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q=="], - "simple-swizzle": ["simple-swizzle@0.2.4", "", { "dependencies": { "is-arrayish": "^0.3.1" } }, "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw=="], + "simple-get": ["simple-get@4.0.1", "", { "dependencies": { "decompress-response": "^6.0.0", "once": "^1.3.1", "simple-concat": "^1.0.0" } }, "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA=="], "solid-element": ["solid-element@1.9.1", "", { "dependencies": { "component-register": "^0.8.7" }, "peerDependencies": { "solid-js": "^1.9.3" } }, "sha512-baJy6Qz27oAUgkPlqOf3Y+7RsBiuVQrS51Nrh1ddDbrqrNPvJbIvehpUsTzLNFb2ZHIoHuNnDg330go/ZKcRdg=="], - "solid-js": ["solid-js@1.9.10", "", { "dependencies": { "csstype": "^3.1.0", "seroval": "~1.3.0", "seroval-plugins": "~1.3.0" } }, "sha512-Coz956cos/EPDlhs6+jsdTxKuJDPT7B5SVIWgABwROyxjY7Xbr8wkzD68Et+NxnV7DLJ3nJdAC2r9InuV/4Jew=="], + "solid-js": ["solid-js@1.9.11", "", { "dependencies": { "csstype": "^3.1.0", "seroval": "~1.5.0", "seroval-plugins": "~1.5.0" } }, "sha512-WEJtcc5mkh/BnHA6Yrg4whlF8g6QwpmXXRg4P2ztPmcKeHHlH4+djYecBLhSpecZY2RRECXYUwIc/C2r3yzQ4Q=="], "solid-refresh": ["solid-refresh@0.6.3", "", { "dependencies": { "@babel/generator": "^7.23.6", "@babel/helper-module-imports": "^7.22.15", "@babel/types": "^7.23.6" }, "peerDependencies": { "solid-js": "^1.3" } }, "sha512-F3aPsX6hVw9ttm5LYlth8Q15x6MlI/J3Dn+o3EQyRTtTxidepSTwAYdozt01/YA+7ObcciagGEyXIopGZzQtbA=="], @@ -1199,61 +1413,51 @@ "space-separated-tokens": ["space-separated-tokens@2.0.2", "", {}, "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="], - "speakingurl": ["speakingurl@14.0.1", "", {}, "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ=="], + "spdx-correct": ["spdx-correct@3.2.0", "", { "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" } }, "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA=="], - "stackback": ["stackback@0.0.2", "", {}, "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="], + "spdx-exceptions": ["spdx-exceptions@2.5.0", "", {}, "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w=="], - "std-env": ["std-env@3.10.0", "", {}, "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="], + "spdx-expression-parse": ["spdx-expression-parse@3.0.1", "", { "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q=="], - "stoppable": ["stoppable@1.1.0", "", {}, "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw=="], + "spdx-license-ids": ["spdx-license-ids@3.0.23", "", {}, "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw=="], - "stream-to-array": ["stream-to-array@2.3.0", "", { "dependencies": { "any-promise": "^1.1.0" } }, "sha512-UsZtOYEn4tWU2RGLOXr/o/xjRBftZRlG3dEWoaHr8j4GuypJ3isitGbVyjQKAuMu+xbiop8q224TjiZWc4XTZA=="], + "speakingurl": ["speakingurl@14.0.1", "", {}, "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ=="], "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + "string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], "stringify-entities": ["stringify-entities@4.0.4", "", { "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" } }, "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg=="], - "stringify-object": ["stringify-object@3.3.0", "", { "dependencies": { "get-own-enumerable-property-symbols": "^3.0.0", "is-obj": "^1.0.1", "is-regexp": "^1.0.0" } }, "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw=="], - - "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], - "strip-bom": ["strip-bom@3.0.0", "", {}, "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA=="], - - "strip-indent": ["strip-indent@3.0.0", "", { "dependencies": { "min-indent": "^1.0.0" } }, "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ=="], + "strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], "strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="], - "strip-literal": ["strip-literal@3.1.0", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg=="], - - "stylus-lookup": ["stylus-lookup@6.1.0", "", { "dependencies": { "commander": "^12.1.0" }, "bin": { "stylus-lookup": "bin/cli.js" } }, "sha512-5QSwgxAzXPMN+yugy61C60PhoANdItfdjSEZR8siFwz7yL9jTmV0UBKDCfn3K8GkGB4g0Y9py7vTCX8rFu4/pQ=="], - "superjson": ["superjson@2.2.6", "", { "dependencies": { "copy-anything": "^4" } }, "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA=="], "supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], - "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], - "tabbable": ["tabbable@6.4.0", "", {}, "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg=="], "tailwindcss": ["tailwindcss@4.1.18", "", {}, "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw=="], "tapable": ["tapable@2.3.0", "", {}, "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="], - "terser": ["terser@5.44.1", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.15.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" } }, "sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw=="], - - "tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="], + "tar": ["tar@7.5.7", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ=="], - "tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], + "tar-fs": ["tar-fs@2.1.4", "", { "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", "pump": "^3.0.0", "tar-stream": "^2.1.4" } }, "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ=="], - "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], + "tar-stream": ["tar-stream@2.2.0", "", { "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" } }, "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ=="], - "tinypool": ["tinypool@1.1.1", "", {}, "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg=="], + "terser": ["terser@5.46.0", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.15.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" } }, "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg=="], - "tinyrainbow": ["tinyrainbow@2.0.0", "", {}, "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw=="], + "text-table": ["text-table@0.2.0", "", {}, "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw=="], - "tinyspy": ["tinyspy@4.0.4", "", {}, "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q=="], + "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], @@ -1261,49 +1465,73 @@ "trim-lines": ["trim-lines@3.0.1", "", {}, "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="], - "ts-api-utils": ["ts-api-utils@2.4.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA=="], + "trough": ["trough@2.2.0", "", {}, "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw=="], - "ts-graphviz": ["ts-graphviz@2.1.6", "", { "dependencies": { "@ts-graphviz/adapter": "^2.0.6", "@ts-graphviz/ast": "^2.0.7", "@ts-graphviz/common": "^2.1.5", "@ts-graphviz/core": "^2.0.7" } }, "sha512-XyLVuhBVvdJTJr2FJJV2L1pc4MwSjMhcunRVgDE9k4wbb2ee7ORYnPewxMWUav12vxyfUM686MSGsqnVRIInuw=="], + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], - "tsconfig-paths": ["tsconfig-paths@4.2.0", "", { "dependencies": { "json5": "^2.2.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg=="], + "tsx": ["tsx@4.21.0", "", { "dependencies": { "esbuild": "~0.27.0", "get-tsconfig": "^4.7.5" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw=="], - "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + "tunnel-agent": ["tunnel-agent@0.6.0", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w=="], - "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + "type-fest": ["type-fest@3.13.1", "", {}, "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g=="], - "undici": ["undici@7.14.0", "", {}, "sha512-Vqs8HTzjpQXZeXdpsfChQTlafcMQaaIwnGwLam1wudSSjlJeQ3bw1j+TLPePgrCnCpUXx7Ba5Pdpf5OBih62NQ=="], + "typedarray": ["typedarray@0.0.6", "", {}, "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="], + + "typescript": ["typescript@6.0.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ=="], + + "undici": ["undici@7.18.2", "", {}, "sha512-y+8YjDFzWdQlSE9N5nzKMT3g4a5UBX1HKowfdXh0uvAnTaqqwqB92Jt4UXBAeKekDs5IaDKyJFR4X1gYVCgXcw=="], "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], "unenv": ["unenv@2.0.0-rc.24", "", { "dependencies": { "pathe": "^2.0.3" } }, "sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw=="], + "unified": ["unified@11.0.5", "", { "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", "devlop": "^1.0.0", "extend": "^3.0.0", "is-plain-obj": "^4.0.0", "trough": "^2.0.0", "vfile": "^6.0.0" } }, "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA=="], + + "unified-args": ["unified-args@11.0.1", "", { "dependencies": { "@types/text-table": "^0.2.0", "chalk": "^5.0.0", "chokidar": "^3.0.0", "comma-separated-tokens": "^2.0.0", "json5": "^2.0.0", "minimist": "^1.0.0", "strip-ansi": "^7.0.0", "text-table": "^0.2.0", "unified-engine": "^11.0.0" } }, "sha512-WEQghE91+0s3xPVs0YW6a5zUduNLjmANswX7YbBfksHNDGMjHxaWCql4SR7c9q0yov/XiIEdk6r/LqfPjaYGcw=="], + + "unified-engine": ["unified-engine@11.2.2", "", { "dependencies": { "@types/concat-stream": "^2.0.0", "@types/debug": "^4.0.0", "@types/is-empty": "^1.0.0", "@types/node": "^22.0.0", "@types/unist": "^3.0.0", "concat-stream": "^2.0.0", "debug": "^4.0.0", "extend": "^3.0.0", "glob": "^10.0.0", "ignore": "^6.0.0", "is-empty": "^1.0.0", "is-plain-obj": "^4.0.0", "load-plugin": "^6.0.0", "parse-json": "^7.0.0", "trough": "^2.0.0", "unist-util-inspect": "^8.0.0", "vfile": "^6.0.0", "vfile-message": "^4.0.0", "vfile-reporter": "^8.0.0", "vfile-statistics": "^3.0.0", "yaml": "^2.0.0" } }, "sha512-15g/gWE7qQl9tQ3nAEbMd5h9HV1EACtFs6N9xaRBZICoCwnNGbal1kOs++ICf4aiTdItZxU2s/kYWhW7htlqJg=="], + + "unified-lint-rule": ["unified-lint-rule@3.0.1", "", { "dependencies": { "@types/unist": "^3.0.0", "trough": "^2.0.0", "unified": "^11.0.0", "vfile": "^6.0.0" } }, "sha512-HxIeQOmwL19DGsxHXbeyzKHBsoSCFO7UtRVUvT2v61ptw/G+GbysWcrpHdfs5jqbIFDA11MoKngIhQK0BeTVjA=="], + + "unified-message-control": ["unified-message-control@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "devlop": "^1.0.0", "space-separated-tokens": "^2.0.0", "unist-util-is": "^6.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0", "vfile-location": "^5.0.0", "vfile-message": "^4.0.0" } }, "sha512-B2cSAkpuMVVmPP90KCfKdBhm1e9KYJ+zK3x5BCa0N65zpq1Ybkc9C77+M5qwR8FWO7RF3LM5QRRPZtgjW6DUCw=="], + + "unist-util-inspect": ["unist-util-inspect@8.1.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-mOlg8Mp33pR0eeFpo5d2902ojqFFOKMMG2hF8bmH7ZlhnmjFgh0NI3/ZDwdaBJNbvrS7LZFVrBVtIE9KZ9s7vQ=="], + "unist-util-is": ["unist-util-is@6.0.1", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g=="], "unist-util-position": ["unist-util-position@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA=="], "unist-util-stringify-position": ["unist-util-stringify-position@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ=="], - "unist-util-visit": ["unist-util-visit@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg=="], + "unist-util-visit": ["unist-util-visit@5.1.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg=="], "unist-util-visit-parents": ["unist-util-visit-parents@6.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ=="], "universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], - "unplugin": ["unplugin@2.3.11", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "acorn": "^8.15.0", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww=="], - - "unplugin-solid": ["unplugin-solid@1.0.0", "", { "dependencies": { "@babel/core": "^7.28.3", "@rollup/pluginutils": "^5.2.0", "babel-preset-solid": "^1.9.9", "merge-anything": "^6.0.6", "solid-refresh": "^0.7.5", "unplugin": "^2.3.10", "vitefu": "^1.1.1" }, "peerDependencies": { "solid-js": "^1.9.9" } }, "sha512-pv1CS3XMtf3WwX8Dq9Bvo4qH6mfjN2xOgbaPcnqW1dLhyP/JQCvueGEsN0dYIZ4JvxaD/G/Ot1JnBzNQGHkfeA=="], - "update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="], + "url-join": ["url-join@4.0.1", "", {}, "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA=="], + "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], + "validate-npm-package-license": ["validate-npm-package-license@3.0.4", "", { "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" } }, "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew=="], + + "validate-npm-package-name": ["validate-npm-package-name@5.0.1", "", {}, "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ=="], + "vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="], + "vfile-location": ["vfile-location@5.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile": "^6.0.0" } }, "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg=="], + "vfile-message": ["vfile-message@4.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw=="], - "vite": ["vite@6.4.1", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g=="], + "vfile-reporter": ["vfile-reporter@8.1.1", "", { "dependencies": { "@types/supports-color": "^8.0.0", "string-width": "^6.0.0", "supports-color": "^9.0.0", "unist-util-stringify-position": "^4.0.0", "vfile": "^6.0.0", "vfile-message": "^4.0.0", "vfile-sort": "^4.0.0", "vfile-statistics": "^3.0.0" } }, "sha512-qxRZcnFSQt6pWKn3PAk81yLK2rO2i7CDXpy8v8ZquiEOMLSnPw6BMSi9Y1sUCwGGl7a9b3CJT1CKpnRF7pp66g=="], + + "vfile-sort": ["vfile-sort@4.0.0", "", { "dependencies": { "vfile": "^6.0.0", "vfile-message": "^4.0.0" } }, "sha512-lffPI1JrbHDTToJwcq0rl6rBmkjQmMuXkAxsZPRS9DXbaJQvc642eCg6EGxcX2i1L+esbuhq+2l9tBll5v8AeQ=="], + + "vfile-statistics": ["vfile-statistics@3.0.0", "", { "dependencies": { "vfile": "^6.0.0", "vfile-message": "^4.0.0" } }, "sha512-/qlwqwWBWFOmpXujL/20P+Iuydil0rZZNglR+VNm6J0gpLHwuVM5s7g2TfVoswbXjZ4HuIhLMySEyIw5i7/D8w=="], - "vite-node": ["vite-node@3.2.4", "", { "dependencies": { "cac": "^6.7.14", "debug": "^4.4.1", "es-module-lexer": "^1.7.0", "pathe": "^2.0.3", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "bin": { "vite-node": "vite-node.mjs" } }, "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg=="], + "vite": ["vite@7.3.1", "", { "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA=="], "vite-plugin-html": ["vite-plugin-html@3.2.2", "", { "dependencies": { "@rollup/pluginutils": "^4.2.0", "colorette": "^2.0.16", "connect-history-api-fallback": "^1.6.0", "consola": "^2.15.3", "dotenv": "^16.0.0", "dotenv-expand": "^8.0.2", "ejs": "^3.1.6", "fast-glob": "^3.2.11", "fs-extra": "^10.0.1", "html-minifier-terser": "^6.1.0", "node-html-parser": "^5.3.3", "pathe": "^0.2.0" }, "peerDependencies": { "vite": ">=2.0.0" } }, "sha512-vb9C9kcdzcIo/Oc3CLZVS03dL5pDlOFuhGlZYDCJ840BhWl/0nGeZWf3Qy7NlOayscY4Cm/QRgULCQkEZige5Q=="], @@ -1313,33 +1541,29 @@ "vitepress": ["vitepress@1.6.4", "", { "dependencies": { "@docsearch/css": "3.8.2", "@docsearch/js": "3.8.2", "@iconify-json/simple-icons": "^1.2.21", "@shikijs/core": "^2.1.0", "@shikijs/transformers": "^2.1.0", "@shikijs/types": "^2.1.0", "@types/markdown-it": "^14.1.2", "@vitejs/plugin-vue": "^5.2.1", "@vue/devtools-api": "^7.7.0", "@vue/shared": "^3.5.13", "@vueuse/core": "^12.4.0", "@vueuse/integrations": "^12.4.0", "focus-trap": "^7.6.4", "mark.js": "8.11.1", "minisearch": "^7.1.1", "shiki": "^2.1.0", "vite": "^5.4.14", "vue": "^3.5.13" }, "peerDependencies": { "markdown-it-mathjax3": "^4", "postcss": "^8" }, "optionalPeers": ["markdown-it-mathjax3", "postcss"], "bin": { "vitepress": "bin/vitepress.js" } }, "sha512-+2ym1/+0VVrbhNyRoFFesVvBvHAVMZMK0rw60E3X/5349M1GuVdKeazuksqopEdvkKwKGs21Q729jX81/bkBJg=="], - "vitest": ["vitest@3.2.4", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.4", "@vitest/mocker": "3.2.4", "@vitest/pretty-format": "^3.2.4", "@vitest/runner": "3.2.4", "@vitest/snapshot": "3.2.4", "@vitest/spy": "3.2.4", "@vitest/utils": "3.2.4", "chai": "^5.2.0", "debug": "^4.4.1", "expect-type": "^1.2.1", "magic-string": "^0.30.17", "pathe": "^2.0.3", "picomatch": "^4.0.2", "std-env": "^3.9.0", "tinybench": "^2.9.0", "tinyexec": "^0.3.2", "tinyglobby": "^0.2.14", "tinypool": "^1.1.1", "tinyrainbow": "^2.0.0", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", "vite-node": "3.2.4", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@types/debug": "^4.1.12", "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "@vitest/browser": "3.2.4", "@vitest/ui": "3.2.4", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@types/debug", "@types/node", "@vitest/browser", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A=="], + "vue": ["vue@3.5.28", "", { "dependencies": { "@vue/compiler-dom": "3.5.28", "@vue/compiler-sfc": "3.5.28", "@vue/runtime-dom": "3.5.28", "@vue/server-renderer": "3.5.28", "@vue/shared": "3.5.28" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-BRdrNfeoccSoIZeIhyPBfvWSLFP4q8J3u8Ju8Ug5vu3LdD+yTM13Sg4sKtljxozbnuMu1NB1X5HBHRYUzFocKg=="], - "vue": ["vue@3.5.26", "", { "dependencies": { "@vue/compiler-dom": "3.5.26", "@vue/compiler-sfc": "3.5.26", "@vue/runtime-dom": "3.5.26", "@vue/server-renderer": "3.5.26", "@vue/shared": "3.5.26" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-SJ/NTccVyAoNUJmkM9KUqPcYlY+u8OVL1X5EW9RIs3ch5H2uERxyyIUI4MRxVCSOiEcupX9xNGde1tL9ZKpimA=="], + "walk-up-path": ["walk-up-path@3.0.1", "", {}, "sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA=="], - "walkdir": ["walkdir@0.4.1", "", {}, "sha512-3eBwRyEln6E1MSzcxcVpQIhRG8Q1jLvEqRmCZqS3dsfXEDR/AhOF4d+jHg1qvDCpYaVRZjENPQyrVxAkQqxPgQ=="], + "which": ["which@6.0.1", "", { "dependencies": { "isexe": "^4.0.0" }, "bin": { "node-which": "bin/which.js" } }, "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg=="], - "wcwidth": ["wcwidth@1.0.1", "", { "dependencies": { "defaults": "^1.0.3" } }, "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg=="], + "workerd": ["workerd@1.20260212.0", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20260212.0", "@cloudflare/workerd-darwin-arm64": "1.20260212.0", "@cloudflare/workerd-linux-64": "1.20260212.0", "@cloudflare/workerd-linux-arm64": "1.20260212.0", "@cloudflare/workerd-windows-64": "1.20260212.0" }, "bin": { "workerd": "bin/workerd" } }, "sha512-4B9BoZUzKSRv3pVZGEPh7OX+Q817hpUqAUtz5O0TxJVqo4OsYJAUA/sY177Q5ha/twjT9KaJt2DtQzE+oyCOzw=="], - "webpack-virtual-modules": ["webpack-virtual-modules@0.6.2", "", {}, "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ=="], - - "whatwg-mimetype": ["whatwg-mimetype@3.0.0", "", {}, "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q=="], - - "why-is-node-running": ["why-is-node-running@2.3.0", "", { "dependencies": { "siginfo": "^2.0.0", "stackback": "0.0.2" }, "bin": { "why-is-node-running": "cli.js" } }, "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w=="], - - "workerd": ["workerd@1.20260107.1", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20260107.1", "@cloudflare/workerd-darwin-arm64": "1.20260107.1", "@cloudflare/workerd-linux-64": "1.20260107.1", "@cloudflare/workerd-linux-arm64": "1.20260107.1", "@cloudflare/workerd-windows-64": "1.20260107.1" }, "bin": { "workerd": "bin/workerd" } }, "sha512-4ylAQJDdJZdMAUl2SbJgTa77YHpa88l6qmhiuCLNactP933+rifs7I0w1DslhUIFgydArUX5dNLAZnZhT7Bh7g=="], - - "wrangler": ["wrangler@4.58.0", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.4.1", "@cloudflare/unenv-preset": "2.8.0", "blake3-wasm": "2.1.5", "esbuild": "0.27.0", "miniflare": "4.20260107.0", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.24", "workerd": "1.20260107.1" }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20260107.1" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-Jm6EYtlt8iUcznOCPSMYC54DYkwrMNESzbH0Vh3GFHv/7XVw5gBC13YJAB+nWMRGJ+6B2dMzy/NVQS4ONL51Pw=="], + "wrangler": ["wrangler@4.65.0", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.4.2", "@cloudflare/unenv-preset": "2.12.1", "blake3-wasm": "2.1.5", "esbuild": "0.27.3", "miniflare": "4.20260212.0", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.24", "workerd": "1.20260212.0" }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20260212.0" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-R+n3o3tlGzLK9I4fGocPReOuvcnjhtOL2aCVKkHMeuEwt9pPbOO4FxJtx/ec5cIUG/otRyJnfQGCAr9DplBVng=="], "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + "wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], - "ws": ["ws@8.19.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg=="], + "ws": ["ws@8.18.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw=="], "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], - "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], + "yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], + + "yaml": ["yaml@2.8.3", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg=="], "yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], @@ -1349,283 +1573,237 @@ "youch-core": ["youch-core@0.3.3", "", { "dependencies": { "@poppinss/exception": "^1.2.2", "error-stack-parser-es": "^1.0.5" } }, "sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA=="], - "zod": ["zod@4.3.5", "", {}, "sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g=="], + "zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="], - "@babel/code-frame/js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], - "@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], "@cspotcode/source-map-support/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.9", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="], - "@moq/hang-ui/vite": ["vite@7.3.1", "", { "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA=="], - - "@poppinss/dumper/supports-color": ["supports-color@10.2.2", "", {}, "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g=="], - - "@rollup/pluginutils/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], - - "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="], - - "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="], - - "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="], - - "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.1", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" }, "bundled": true }, "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A=="], - - "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], - - "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], - - "@testing-library/dom/aria-query": ["aria-query@5.3.0", "", { "dependencies": { "dequal": "^2.0.3" } }, "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A=="], - - "@testing-library/dom/dom-accessibility-api": ["dom-accessibility-api@0.5.16", "", {}, "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg=="], - - "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], - - "@typescript-eslint/typescript-estree/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], - - "@vue/compiler-core/entities": ["entities@7.0.0", "", {}, "sha512-FDWG5cmEYf2Z00IkYRhbFrwIwvdFKH07uV8dvNy0omp/Qb1xcyCWp2UDtcwJF4QZZvk0sLudP6/hAu42TaqVhQ=="], - - "@vue/compiler-core/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], - - "@vue/compiler-sfc/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], - - "babel-plugin-jsx-dom-expressions/@babel/helper-module-imports": ["@babel/helper-module-imports@7.18.6", "", { "dependencies": { "@babel/types": "^7.18.6" } }, "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA=="], - - "chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], - - "copy-anything/is-what": ["is-what@5.5.0", "", {}, "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw=="], - - "dependency-tree/commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="], - - "dom-serializer/entities": ["entities@2.2.0", "", {}, "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="], + "@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], - "filelist/minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="], + "@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], - "filing-cabinet/commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="], + "@npmcli/config/ini": ["ini@4.1.3", "", {}, "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg=="], - "happy-dom/@types/node": ["@types/node@20.19.28", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-VyKBr25BuFDzBFCK5sUM6ZXiWfqgCTwTAOK8qzGV/m9FCirXYDlmczJ+d5dXBAQALGCdRRdbteKYfJ84NGEusw=="], + "@npmcli/config/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], - "html-minifier-terser/commander": ["commander@8.3.0", "", {}, "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww=="], + "@npmcli/git/ini": ["ini@4.1.3", "", {}, "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg=="], - "madge/commander": ["commander@7.2.0", "", {}, "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="], + "@npmcli/git/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], - "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "@npmcli/git/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], - "miniflare/acorn": ["acorn@8.14.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA=="], + "@npmcli/git/which": ["which@4.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg=="], - "miniflare/ws": ["ws@8.18.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw=="], + "@npmcli/map-workspaces/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], - "miniflare/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@npmcli/map-workspaces/minimatch": ["minimatch@9.0.9", "", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="], - "module-lookup-amd/commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="], + "@npmcli/package-json/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], - "module-lookup-amd/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + "@npmcli/package-json/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], - "precinct/commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="], + "@npmcli/promise-spawn/which": ["which@4.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg=="], - "pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="], - - "sass-lookup/commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="], - - "sharp/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + "@poppinss/dumper/supports-color": ["supports-color@10.2.2", "", {}, "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g=="], - "stylus-lookup/commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="], + "@rollup/pluginutils/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - "terser/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], + "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="], - "unplugin-solid/merge-anything": ["merge-anything@6.0.6", "", { "dependencies": { "is-what": "^5.2.0" } }, "sha512-F3K1W45PvTjRZzbcYIhXntNr8cux00gUxR8IzNPPG+80gNlAHZGVBwFyN4x5yjw/7QkLPKDbRQBK4KrJKo69mw=="], + "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="], - "unplugin-solid/solid-refresh": ["solid-refresh@0.7.5", "", { "dependencies": { "@babel/generator": "^7.23.6", "@babel/types": "^7.23.6" }, "peerDependencies": { "solid-js": "^1.3" } }, "sha512-ZYMbjWsy7IwSF3+oZCNnReiTYSyCAFRvC7oLUKxxh1wPa6/6YIWqsxa+Ma2kM4F/ypWT69B1c0fmKeZRdLueGw=="], + "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="], - "vite-node/vite": ["vite@7.3.1", "", { "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA=="], + "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.1", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" }, "bundled": true }, "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A=="], - "vite-plugin-html/@rollup/pluginutils": ["@rollup/pluginutils@4.2.1", "", { "dependencies": { "estree-walker": "^2.0.1", "picomatch": "^2.2.2" } }, "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ=="], + "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], - "vite-plugin-html/pathe": ["pathe@0.2.0", "", {}, "sha512-sTitTPYnn23esFR3RlqYBWn4c45WGeLcsKzQiUpXJAyfcWkolvlYpV8FLo7JishK946oQwMFUCHXQ9AjGPKExw=="], + "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], - "vitepress/vite": ["vite@5.4.21", "", { "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", "rollup": "^4.20.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "optionalPeers": ["@types/node", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser"], "bin": { "vite": "bin/vite.js" } }, "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw=="], + "@vitejs/plugin-vue/vite": ["vite@5.4.21", "", { "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", "rollup": "^4.20.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "optionalPeers": ["@types/node", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser"], "bin": { "vite": "bin/vite.js" } }, "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw=="], - "vitest/vite": ["vite@7.3.1", "", { "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA=="], + "@vue/compiler-core/entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="], - "wrangler/esbuild": ["esbuild@0.27.0", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.0", "@esbuild/android-arm": "0.27.0", "@esbuild/android-arm64": "0.27.0", "@esbuild/android-x64": "0.27.0", "@esbuild/darwin-arm64": "0.27.0", "@esbuild/darwin-x64": "0.27.0", "@esbuild/freebsd-arm64": "0.27.0", "@esbuild/freebsd-x64": "0.27.0", "@esbuild/linux-arm": "0.27.0", "@esbuild/linux-arm64": "0.27.0", "@esbuild/linux-ia32": "0.27.0", "@esbuild/linux-loong64": "0.27.0", "@esbuild/linux-mips64el": "0.27.0", "@esbuild/linux-ppc64": "0.27.0", "@esbuild/linux-riscv64": "0.27.0", "@esbuild/linux-s390x": "0.27.0", "@esbuild/linux-x64": "0.27.0", "@esbuild/netbsd-arm64": "0.27.0", "@esbuild/netbsd-x64": "0.27.0", "@esbuild/openbsd-arm64": "0.27.0", "@esbuild/openbsd-x64": "0.27.0", "@esbuild/openharmony-arm64": "0.27.0", "@esbuild/sunos-x64": "0.27.0", "@esbuild/win32-arm64": "0.27.0", "@esbuild/win32-ia32": "0.27.0", "@esbuild/win32-x64": "0.27.0" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA=="], + "anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - "@moq/hang-ui/vite/esbuild": ["esbuild@0.27.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.2", "@esbuild/android-arm": "0.27.2", "@esbuild/android-arm64": "0.27.2", "@esbuild/android-x64": "0.27.2", "@esbuild/darwin-arm64": "0.27.2", "@esbuild/darwin-x64": "0.27.2", "@esbuild/freebsd-arm64": "0.27.2", "@esbuild/freebsd-x64": "0.27.2", "@esbuild/linux-arm": "0.27.2", "@esbuild/linux-arm64": "0.27.2", "@esbuild/linux-ia32": "0.27.2", "@esbuild/linux-loong64": "0.27.2", "@esbuild/linux-mips64el": "0.27.2", "@esbuild/linux-ppc64": "0.27.2", "@esbuild/linux-riscv64": "0.27.2", "@esbuild/linux-s390x": "0.27.2", "@esbuild/linux-x64": "0.27.2", "@esbuild/netbsd-arm64": "0.27.2", "@esbuild/netbsd-x64": "0.27.2", "@esbuild/openbsd-arm64": "0.27.2", "@esbuild/openbsd-x64": "0.27.2", "@esbuild/openharmony-arm64": "0.27.2", "@esbuild/sunos-x64": "0.27.2", "@esbuild/win32-arm64": "0.27.2", "@esbuild/win32-ia32": "0.27.2", "@esbuild/win32-x64": "0.27.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw=="], + "babel-plugin-jsx-dom-expressions/@babel/helper-module-imports": ["@babel/helper-module-imports@7.18.6", "", { "dependencies": { "@babel/types": "^7.18.6" } }, "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA=="], - "happy-dom/@types/node/undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], + "balanced-match/jackspeak": ["jackspeak@4.2.3", "", { "dependencies": { "@isaacs/cliui": "^9.0.0" } }, "sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg=="], - "module-lookup-amd/glob/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + "chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], - "unplugin-solid/merge-anything/is-what": ["is-what@5.5.0", "", {}, "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw=="], + "cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - "vite-node/vite/esbuild": ["esbuild@0.27.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.2", "@esbuild/android-arm": "0.27.2", "@esbuild/android-arm64": "0.27.2", "@esbuild/android-x64": "0.27.2", "@esbuild/darwin-arm64": "0.27.2", "@esbuild/darwin-x64": "0.27.2", "@esbuild/freebsd-arm64": "0.27.2", "@esbuild/freebsd-x64": "0.27.2", "@esbuild/linux-arm": "0.27.2", "@esbuild/linux-arm64": "0.27.2", "@esbuild/linux-ia32": "0.27.2", "@esbuild/linux-loong64": "0.27.2", "@esbuild/linux-mips64el": "0.27.2", "@esbuild/linux-ppc64": "0.27.2", "@esbuild/linux-riscv64": "0.27.2", "@esbuild/linux-s390x": "0.27.2", "@esbuild/linux-x64": "0.27.2", "@esbuild/netbsd-arm64": "0.27.2", "@esbuild/netbsd-x64": "0.27.2", "@esbuild/openbsd-arm64": "0.27.2", "@esbuild/openbsd-x64": "0.27.2", "@esbuild/openharmony-arm64": "0.27.2", "@esbuild/sunos-x64": "0.27.2", "@esbuild/win32-arm64": "0.27.2", "@esbuild/win32-ia32": "0.27.2", "@esbuild/win32-x64": "0.27.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw=="], + "cmake-js/fs-extra": ["fs-extra@11.3.3", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg=="], - "vite-plugin-html/@rollup/pluginutils/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], + "cmake-js/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], - "vite-plugin-html/@rollup/pluginutils/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "copy-anything/is-what": ["is-what@5.5.0", "", {}, "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw=="], - "vitepress/vite/esbuild": ["esbuild@0.21.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.21.5", "@esbuild/android-arm": "0.21.5", "@esbuild/android-arm64": "0.21.5", "@esbuild/android-x64": "0.21.5", "@esbuild/darwin-arm64": "0.21.5", "@esbuild/darwin-x64": "0.21.5", "@esbuild/freebsd-arm64": "0.21.5", "@esbuild/freebsd-x64": "0.21.5", "@esbuild/linux-arm": "0.21.5", "@esbuild/linux-arm64": "0.21.5", "@esbuild/linux-ia32": "0.21.5", "@esbuild/linux-loong64": "0.21.5", "@esbuild/linux-mips64el": "0.21.5", "@esbuild/linux-ppc64": "0.21.5", "@esbuild/linux-riscv64": "0.21.5", "@esbuild/linux-s390x": "0.21.5", "@esbuild/linux-x64": "0.21.5", "@esbuild/netbsd-x64": "0.21.5", "@esbuild/openbsd-x64": "0.21.5", "@esbuild/sunos-x64": "0.21.5", "@esbuild/win32-arm64": "0.21.5", "@esbuild/win32-ia32": "0.21.5", "@esbuild/win32-x64": "0.21.5" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw=="], + "cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], - "vitest/vite/esbuild": ["esbuild@0.27.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.2", "@esbuild/android-arm": "0.27.2", "@esbuild/android-arm64": "0.27.2", "@esbuild/android-x64": "0.27.2", "@esbuild/darwin-arm64": "0.27.2", "@esbuild/darwin-x64": "0.27.2", "@esbuild/freebsd-arm64": "0.27.2", "@esbuild/freebsd-x64": "0.27.2", "@esbuild/linux-arm": "0.27.2", "@esbuild/linux-arm64": "0.27.2", "@esbuild/linux-ia32": "0.27.2", "@esbuild/linux-loong64": "0.27.2", "@esbuild/linux-mips64el": "0.27.2", "@esbuild/linux-ppc64": "0.27.2", "@esbuild/linux-riscv64": "0.27.2", "@esbuild/linux-s390x": "0.27.2", "@esbuild/linux-x64": "0.27.2", "@esbuild/netbsd-arm64": "0.27.2", "@esbuild/netbsd-x64": "0.27.2", "@esbuild/openbsd-arm64": "0.27.2", "@esbuild/openbsd-x64": "0.27.2", "@esbuild/openharmony-arm64": "0.27.2", "@esbuild/sunos-x64": "0.27.2", "@esbuild/win32-arm64": "0.27.2", "@esbuild/win32-ia32": "0.27.2", "@esbuild/win32-x64": "0.27.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw=="], + "dom-serializer/entities": ["entities@2.2.0", "", {}, "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="], - "wrangler/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.0", "", { "os": "aix", "cpu": "ppc64" }, "sha512-KuZrd2hRjz01y5JK9mEBSD3Vj3mbCvemhT466rSuJYeE/hjuBrHfjjcjMdTm/sz7au+++sdbJZJmuBwQLuw68A=="], + "filelist/minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="], - "wrangler/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.27.0", "", { "os": "android", "cpu": "arm" }, "sha512-j67aezrPNYWJEOHUNLPj9maeJte7uSMM6gMoxfPC9hOg8N02JuQi/T7ewumf4tNvJadFkvLZMlAq73b9uwdMyQ=="], + "hosted-git-info/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], - "wrangler/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.0", "", { "os": "android", "cpu": "arm64" }, "sha512-CC3vt4+1xZrs97/PKDkl0yN7w8edvU2vZvAFGD16n9F0Cvniy5qvzRXjfO1l94efczkkQE6g1x0i73Qf5uthOQ=="], + "html-minifier-terser/commander": ["commander@8.3.0", "", {}, "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww=="], - "wrangler/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.27.0", "", { "os": "android", "cpu": "x64" }, "sha512-wurMkF1nmQajBO1+0CJmcN17U4BP6GqNSROP8t0X/Jiw2ltYGLHpEksp9MpoBqkrFR3kv2/te6Sha26k3+yZ9Q=="], + "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - "wrangler/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-uJOQKYCcHhg07DL7i8MzjvS2LaP7W7Pn/7uA0B5S1EnqAirJtbyw4yC5jQ5qcFjHK9l6o/MX9QisBg12kNkdHg=="], + "node-abi/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], - "wrangler/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-8mG6arH3yB/4ZXiEnXof5MK72dE6zM9cDvUcPtxhUZsDjESl9JipZYW60C3JGreKCEP+p8P/72r69m4AZGJd5g=="], + "normalize-package-data/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], - "wrangler/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-9FHtyO988CwNMMOE3YIeci+UV+x5Zy8fI2qHNpsEtSF83YPBmE8UWmfYAQg6Ux7Gsmd4FejZqnEUZCMGaNQHQw=="], + "npm-install-checks/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], - "wrangler/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-zCMeMXI4HS/tXvJz8vWGexpZj2YVtRAihHLk1imZj4efx1BQzN76YFeKqlDr3bUWI26wHwLWPd3rwh6pe4EV7g=="], + "npm-package-arg/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], - "wrangler/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.0", "", { "os": "linux", "cpu": "arm" }, "sha512-t76XLQDpxgmq2cNXKTVEB7O7YMb42atj2Re2Haf45HkaUpjM2J0UuJZDuaGbPbamzZ7bawyGFUkodL+zcE+jvQ=="], + "npm-pick-manifest/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], - "wrangler/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-AS18v0V+vZiLJyi/4LphvBE+OIX682Pu7ZYNsdUHyUKSoRwdnOsMf6FDekwoAFKej14WAkOef3zAORJgAtXnlQ=="], + "parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], - "wrangler/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.0", "", { "os": "linux", "cpu": "ia32" }, "sha512-Mz1jxqm/kfgKkc/KLHC5qIujMvnnarD9ra1cEcrs7qshTUSksPihGrWHVG5+osAIQ68577Zpww7SGapmzSt4Nw=="], + "readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - "wrangler/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.0", "", { "os": "linux", "cpu": "none" }, "sha512-QbEREjdJeIreIAbdG2hLU1yXm1uu+LTdzoq1KCo4G4pFOLlvIspBm36QrQOar9LFduavoWX2msNFAAAY9j4BDg=="], + "sharp/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], - "wrangler/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.0", "", { "os": "linux", "cpu": "none" }, "sha512-sJz3zRNe4tO2wxvDpH/HYJilb6+2YJxo/ZNbVdtFiKDufzWq4JmKAiHy9iGoLjAV7r/W32VgaHGkk35cUXlNOg=="], + "string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - "wrangler/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-z9N10FBD0DCS2dmSABDBb5TLAyF1/ydVb+N4pi88T45efQ/w4ohr/F/QYCkxDPnkhkp6AIpIcQKQ8F0ANoA2JA=="], + "string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - "wrangler/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.0", "", { "os": "linux", "cpu": "none" }, "sha512-pQdyAIZ0BWIC5GyvVFn5awDiO14TkT/19FTmFcPdDec94KJ1uZcmFs21Fo8auMXzD4Tt+diXu1LW1gHus9fhFQ=="], + "strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - "wrangler/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-hPlRWR4eIDDEci953RI1BLZitgi5uqcsjKMxwYfmi4LcwyWo2IcRP+lThVnKjNtk90pLS8nKdroXYOqW+QQH+w=="], + "tar-fs/chownr": ["chownr@1.1.4", "", {}, "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="], - "wrangler/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.0", "", { "os": "linux", "cpu": "x64" }, "sha512-1hBWx4OUJE2cab++aVZ7pObD6s+DK4mPGpemtnAORBvb5l/g5xFGk0vc0PjSkrDs0XaXj9yyob3d14XqvnQ4gw=="], + "terser/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], - "wrangler/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.0", "", { "os": "none", "cpu": "arm64" }, "sha512-6m0sfQfxfQfy1qRuecMkJlf1cIzTOgyaeXaiVaaki8/v+WB+U4hc6ik15ZW6TAllRlg/WuQXxWj1jx6C+dfy3w=="], + "unenv/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], - "wrangler/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.0", "", { "os": "none", "cpu": "x64" }, "sha512-xbbOdfn06FtcJ9d0ShxxvSn2iUsGd/lgPIO2V3VZIPDbEaIj1/3nBBe1AwuEZKXVXkMmpr6LUAgMkLD/4D2PPA=="], + "unified-args/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], - "wrangler/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.0", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fWgqR8uNbCQ/GGv0yhzttj6sU/9Z5/Sv/VGU3F5OuXK6J6SlriONKrQ7tNlwBrJZXRYk5jUhuWvF7GYzGguBZQ=="], + "unified-engine/@types/node": ["@types/node@22.19.15", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-F0R/h2+dsy5wJAUe3tAU6oqa2qbWY5TpNfL/RGmo1y38hiyO1w3x2jPtt76wmuaJI4DQnOBu21cNXQ2STIUUWg=="], - "wrangler/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.0", "", { "os": "openbsd", "cpu": "x64" }, "sha512-aCwlRdSNMNxkGGqQajMUza6uXzR/U0dIl1QmLjPtRbLOx3Gy3otfFu/VjATy4yQzo9yFDGTxYDo1FfAD9oRD2A=="], + "unified-engine/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], - "wrangler/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.0", "", { "os": "none", "cpu": "arm64" }, "sha512-nyvsBccxNAsNYz2jVFYwEGuRRomqZ149A39SHWk4hV0jWxKM0hjBPm3AmdxcbHiFLbBSwG6SbpIcUbXjgyECfA=="], + "vfile-reporter/string-width": ["string-width@6.1.0", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^10.2.1", "strip-ansi": "^7.0.1" } }, "sha512-k01swCJAgQmuADB0YIc+7TuatfNvTBVOoaUWJjTB9R4VJzR5vNWzf5t42ESVZFPS8xTySF7CAdV4t/aaIm3UnQ=="], - "wrangler/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.0", "", { "os": "sunos", "cpu": "x64" }, "sha512-Q1KY1iJafM+UX6CFEL+F4HRTgygmEW568YMqDA5UV97AuZSm21b7SXIrRJDwXWPzr8MGr75fUZPV67FdtMHlHA=="], + "vfile-reporter/supports-color": ["supports-color@9.4.0", "", {}, "sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw=="], - "wrangler/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-W1eyGNi6d+8kOmZIwi/EDjrL9nxQIQ0MiGqe/AWc6+IaHloxHSGoeRgDRKHFISThLmsewZ5nHFvGFWdBYlgKPg=="], + "vitepress/vite": ["vite@5.4.21", "", { "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", "rollup": "^4.20.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "optionalPeers": ["@types/node", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser"], "bin": { "vite": "bin/vite.js" } }, "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw=="], - "wrangler/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-30z1aKL9h22kQhilnYkORFYt+3wp7yZsHWus+wSKAJR8JtdfI76LJ4SBdMsCopTR3z/ORqVu5L1vtnHZWVj4cQ=="], + "wrap-ansi/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - "wrangler/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.0", "", { "os": "win32", "cpu": "x64" }, "sha512-aIitBcjQeyOhMTImhLZmtxfdOcuNRpwlPNmlFKPcHQYPhEssw75Cl1TSXJXpMkzaua9FUetx/4OQKq7eJul5Cg=="], + "wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - "@moq/hang-ui/vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw=="], + "@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], - "@moq/hang-ui/vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.27.2", "", { "os": "android", "cpu": "arm" }, "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA=="], + "@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], - "@moq/hang-ui/vite/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.2", "", { "os": "android", "cpu": "arm64" }, "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA=="], + "@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], - "@moq/hang-ui/vite/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.27.2", "", { "os": "android", "cpu": "x64" }, "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A=="], + "@npmcli/git/which/isexe": ["isexe@3.1.5", "", {}, "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w=="], - "@moq/hang-ui/vite/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg=="], + "@npmcli/map-workspaces/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], - "@moq/hang-ui/vite/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA=="], + "@npmcli/map-workspaces/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], - "@moq/hang-ui/vite/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g=="], + "@npmcli/package-json/glob/minimatch": ["minimatch@9.0.9", "", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="], - "@moq/hang-ui/vite/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA=="], + "@npmcli/package-json/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], - "@moq/hang-ui/vite/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.2", "", { "os": "linux", "cpu": "arm" }, "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw=="], + "@npmcli/promise-spawn/which/isexe": ["isexe@3.1.5", "", {}, "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w=="], - "@moq/hang-ui/vite/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw=="], + "@vitejs/plugin-vue/vite/esbuild": ["esbuild@0.21.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.21.5", "@esbuild/android-arm": "0.21.5", "@esbuild/android-arm64": "0.21.5", "@esbuild/android-x64": "0.21.5", "@esbuild/darwin-arm64": "0.21.5", "@esbuild/darwin-x64": "0.21.5", "@esbuild/freebsd-arm64": "0.21.5", "@esbuild/freebsd-x64": "0.21.5", "@esbuild/linux-arm": "0.21.5", "@esbuild/linux-arm64": "0.21.5", "@esbuild/linux-ia32": "0.21.5", "@esbuild/linux-loong64": "0.21.5", "@esbuild/linux-mips64el": "0.21.5", "@esbuild/linux-ppc64": "0.21.5", "@esbuild/linux-riscv64": "0.21.5", "@esbuild/linux-s390x": "0.21.5", "@esbuild/linux-x64": "0.21.5", "@esbuild/netbsd-x64": "0.21.5", "@esbuild/openbsd-x64": "0.21.5", "@esbuild/sunos-x64": "0.21.5", "@esbuild/win32-arm64": "0.21.5", "@esbuild/win32-ia32": "0.21.5", "@esbuild/win32-x64": "0.21.5" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw=="], - "@moq/hang-ui/vite/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w=="], + "balanced-match/jackspeak/@isaacs/cliui": ["@isaacs/cliui@9.0.0", "", {}, "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg=="], - "@moq/hang-ui/vite/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg=="], + "cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - "@moq/hang-ui/vite/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw=="], + "cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], - "@moq/hang-ui/vite/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ=="], + "filelist/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], - "@moq/hang-ui/vite/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA=="], + "string-width-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - "@moq/hang-ui/vite/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w=="], + "string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - "@moq/hang-ui/vite/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.2", "", { "os": "linux", "cpu": "x64" }, "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA=="], + "unified-engine/@types/node/undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], - "@moq/hang-ui/vite/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.2", "", { "os": "none", "cpu": "arm64" }, "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw=="], + "unified-engine/glob/minimatch": ["minimatch@9.0.9", "", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="], - "@moq/hang-ui/vite/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.2", "", { "os": "none", "cpu": "x64" }, "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA=="], + "unified-engine/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], - "@moq/hang-ui/vite/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA=="], + "vfile-reporter/string-width/emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], - "@moq/hang-ui/vite/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg=="], + "vitepress/vite/esbuild": ["esbuild@0.21.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.21.5", "@esbuild/android-arm": "0.21.5", "@esbuild/android-arm64": "0.21.5", "@esbuild/android-x64": "0.21.5", "@esbuild/darwin-arm64": "0.21.5", "@esbuild/darwin-x64": "0.21.5", "@esbuild/freebsd-arm64": "0.21.5", "@esbuild/freebsd-x64": "0.21.5", "@esbuild/linux-arm": "0.21.5", "@esbuild/linux-arm64": "0.21.5", "@esbuild/linux-ia32": "0.21.5", "@esbuild/linux-loong64": "0.21.5", "@esbuild/linux-mips64el": "0.21.5", "@esbuild/linux-ppc64": "0.21.5", "@esbuild/linux-riscv64": "0.21.5", "@esbuild/linux-s390x": "0.21.5", "@esbuild/linux-x64": "0.21.5", "@esbuild/netbsd-x64": "0.21.5", "@esbuild/openbsd-x64": "0.21.5", "@esbuild/sunos-x64": "0.21.5", "@esbuild/win32-arm64": "0.21.5", "@esbuild/win32-ia32": "0.21.5", "@esbuild/win32-x64": "0.21.5" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw=="], - "@moq/hang-ui/vite/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.2", "", { "os": "none", "cpu": "arm64" }, "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag=="], + "wrap-ansi-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - "@moq/hang-ui/vite/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg=="], + "wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - "@moq/hang-ui/vite/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg=="], + "@npmcli/map-workspaces/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], - "@moq/hang-ui/vite/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ=="], + "@npmcli/map-workspaces/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], - "@moq/hang-ui/vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.2", "", { "os": "win32", "cpu": "x64" }, "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ=="], + "@npmcli/package-json/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], - "module-lookup-amd/glob/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], + "@npmcli/package-json/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], - "vite-node/vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw=="], + "@vitejs/plugin-vue/vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.21.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ=="], - "vite-node/vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.27.2", "", { "os": "android", "cpu": "arm" }, "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA=="], + "@vitejs/plugin-vue/vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.21.5", "", { "os": "android", "cpu": "arm" }, "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg=="], - "vite-node/vite/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.2", "", { "os": "android", "cpu": "arm64" }, "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA=="], + "@vitejs/plugin-vue/vite/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.21.5", "", { "os": "android", "cpu": "arm64" }, "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A=="], - "vite-node/vite/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.27.2", "", { "os": "android", "cpu": "x64" }, "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A=="], + "@vitejs/plugin-vue/vite/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.21.5", "", { "os": "android", "cpu": "x64" }, "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA=="], - "vite-node/vite/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg=="], + "@vitejs/plugin-vue/vite/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.21.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ=="], - "vite-node/vite/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA=="], + "@vitejs/plugin-vue/vite/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.21.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw=="], - "vite-node/vite/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g=="], + "@vitejs/plugin-vue/vite/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.21.5", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g=="], - "vite-node/vite/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA=="], + "@vitejs/plugin-vue/vite/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.21.5", "", { "os": "freebsd", "cpu": "x64" }, "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ=="], - "vite-node/vite/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.2", "", { "os": "linux", "cpu": "arm" }, "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw=="], + "@vitejs/plugin-vue/vite/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.21.5", "", { "os": "linux", "cpu": "arm" }, "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA=="], - "vite-node/vite/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw=="], + "@vitejs/plugin-vue/vite/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.21.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q=="], - "vite-node/vite/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w=="], + "@vitejs/plugin-vue/vite/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.21.5", "", { "os": "linux", "cpu": "ia32" }, "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg=="], - "vite-node/vite/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg=="], + "@vitejs/plugin-vue/vite/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg=="], - "vite-node/vite/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw=="], + "@vitejs/plugin-vue/vite/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg=="], - "vite-node/vite/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ=="], + "@vitejs/plugin-vue/vite/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.21.5", "", { "os": "linux", "cpu": "ppc64" }, "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w=="], - "vite-node/vite/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA=="], + "@vitejs/plugin-vue/vite/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA=="], - "vite-node/vite/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w=="], + "@vitejs/plugin-vue/vite/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.21.5", "", { "os": "linux", "cpu": "s390x" }, "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A=="], - "vite-node/vite/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.2", "", { "os": "linux", "cpu": "x64" }, "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA=="], + "@vitejs/plugin-vue/vite/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.21.5", "", { "os": "linux", "cpu": "x64" }, "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ=="], - "vite-node/vite/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.2", "", { "os": "none", "cpu": "arm64" }, "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw=="], + "@vitejs/plugin-vue/vite/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.21.5", "", { "os": "none", "cpu": "x64" }, "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg=="], - "vite-node/vite/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.2", "", { "os": "none", "cpu": "x64" }, "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA=="], + "@vitejs/plugin-vue/vite/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.21.5", "", { "os": "openbsd", "cpu": "x64" }, "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow=="], - "vite-node/vite/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA=="], + "@vitejs/plugin-vue/vite/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.21.5", "", { "os": "sunos", "cpu": "x64" }, "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg=="], - "vite-node/vite/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg=="], + "@vitejs/plugin-vue/vite/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.21.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A=="], - "vite-node/vite/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.2", "", { "os": "none", "cpu": "arm64" }, "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag=="], + "@vitejs/plugin-vue/vite/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.21.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA=="], - "vite-node/vite/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg=="], + "@vitejs/plugin-vue/vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.21.5", "", { "os": "win32", "cpu": "x64" }, "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw=="], - "vite-node/vite/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg=="], + "filelist/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], - "vite-node/vite/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ=="], + "unified-engine/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], - "vite-node/vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.2", "", { "os": "win32", "cpu": "x64" }, "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ=="], + "unified-engine/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], "vitepress/vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.21.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ=="], @@ -1673,56 +1851,8 @@ "vitepress/vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.21.5", "", { "os": "win32", "cpu": "x64" }, "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw=="], - "vitest/vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw=="], - - "vitest/vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.27.2", "", { "os": "android", "cpu": "arm" }, "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA=="], - - "vitest/vite/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.2", "", { "os": "android", "cpu": "arm64" }, "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA=="], - - "vitest/vite/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.27.2", "", { "os": "android", "cpu": "x64" }, "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A=="], - - "vitest/vite/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg=="], - - "vitest/vite/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA=="], - - "vitest/vite/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g=="], - - "vitest/vite/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA=="], - - "vitest/vite/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.2", "", { "os": "linux", "cpu": "arm" }, "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw=="], - - "vitest/vite/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw=="], - - "vitest/vite/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w=="], - - "vitest/vite/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg=="], - - "vitest/vite/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw=="], - - "vitest/vite/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ=="], - - "vitest/vite/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA=="], - - "vitest/vite/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w=="], - - "vitest/vite/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.2", "", { "os": "linux", "cpu": "x64" }, "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA=="], - - "vitest/vite/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.2", "", { "os": "none", "cpu": "arm64" }, "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw=="], - - "vitest/vite/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.2", "", { "os": "none", "cpu": "x64" }, "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA=="], - - "vitest/vite/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA=="], - - "vitest/vite/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg=="], - - "vitest/vite/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.2", "", { "os": "none", "cpu": "arm64" }, "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag=="], - - "vitest/vite/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg=="], - - "vitest/vite/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg=="], - - "vitest/vite/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ=="], + "@npmcli/package-json/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], - "vitest/vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.2", "", { "os": "win32", "cpu": "x64" }, "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ=="], + "unified-engine/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], } } diff --git a/cdn/.gitignore b/cdn/.gitignore deleted file mode 100644 index a3749935f9..0000000000 --- a/cdn/.gitignore +++ /dev/null @@ -1,23 +0,0 @@ -# Terraform/OpenTofu -.terraform/ -.tofu/ -.terraform.lock.hcl -.tofu.lock.hcl -terraform.tfstate -terraform.tfstate.backup -tofu.tfstate -tofu.tfstate.backup -*.tfvars -!*.tfvars.example - -# Nix -result -result-* - -# Credentials -secrets/* -*.jwk -*.jwt -*.key -*.crt -*.pem diff --git a/cdn/README.md b/cdn/README.md deleted file mode 100644 index 8c39c67861..0000000000 --- a/cdn/README.md +++ /dev/null @@ -1,52 +0,0 @@ -# Infrastructure - -OpenTofu/Terraform configuration for deploying clustered MoQ relays to Linode. -There's nothing special about Linode, other cloud providers will work provided they support UDP and public IPs. - -However, we do use GCP for GeoDNS because most providers don't support it or too expensive (Cloudflare). - -## Setup - -1. Copy `terraform.tfvars.example` to `terraform.tfvars` and fill in values -2. Run `tofu init`. -3. Run `tofu apply`. -4. Create a `secrets/` directory with JWT/JWK credentials: - - ```bash - mkdir -p secrets - - # generate the root key private key - cargo run --bin moq-token -- --key secrets/root.jwk generate > secrets/root.jwk - - # to allow relay servers to connect to each other - cargo run --bin moq-token -- --key secrets/root.jwk sign --publish "" --subscribe "" --cluster > secrets/cluster.jwt - - # to allow publishing to `demo/` - cargo run --bin moq-token -- --key secrets/root.jwk sign --root "demo" --publish "" > secrets/demo-pub.jwt - ``` - -## Deploy - -1. `nix flake update` to update the `moq-relay` and `hang-cli` binaries. - - **NOTE**: This pulls from `main` on github, not a local path or the latest release. -2. `just deploy-all` to deploy to all nodes in parallel. - - This will take a while as the builds *currently* occur on the remote nodes. - - Somebody should set up remote builders or cross-compilation. - -## Monitor -Use `just` to see all of the available commands. - -1. `just ssh ` to SSH into a specific node. -2. `just logs ` to view the logs of a specific node. -3. etc - -## Costs -Change the number of nodes in [input.tf](input.tf). - -- $25/month for `g6-standard-2` nodes. -- $5/month for `g6-nanode-1` nodes. - -The default configuration is 3 `g6-standard-2` relay nodes and 1 `g6-nanode-1` publisher node. So $80/month. - -**NOTE**: `moq-relay` does not scale particularly well right now. -- The current design is a mesh network, so more nodes means more unnecessary backbone traffic. -- Quinn currently uses a single UDP receive thread, so scaling to multiple cores won't help. diff --git a/cdn/bootstrap.sh b/cdn/bootstrap.sh deleted file mode 100644 index 3e6c4540e1..0000000000 --- a/cdn/bootstrap.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash -# -# - -set -euo pipefail - -echo "Starting bootstrap for moq-relay on Debian..." - -# Set hostname -hostnamectl set-hostname "$HOSTNAME" - -# Install base packages -echo "Installing base packages..." -apt-get update -apt-get install -y rsync curl - -# Create directories -mkdir -p /var/lib/moq -chmod 755 /var/lib/moq - -# Write GCP credentials -echo "$GCP_ACCOUNT" | base64 -d > /var/lib/moq/gcp.json -chmod 600 /var/lib/moq/gcp.json - -# Install Nix (multi-user installation) -echo "Installing Nix package manager..." -sh <(curl -L https://nixos.org/nix/install) --daemon --yes - -# Enable flakes and configure Cachix -mkdir -p /etc/nix -cat > /etc/nix/nix.conf <' to install services and credentials." diff --git a/cdn/bootstrap.tf b/cdn/bootstrap.tf deleted file mode 100644 index 129d1cffaf..0000000000 --- a/cdn/bootstrap.tf +++ /dev/null @@ -1,19 +0,0 @@ -# Service account for relay instances -resource "google_service_account" "relay" { - account_id = "moq-relay" - display_name = "MoQ Relay" - description = "Service account for MoQ relay instances" -} - -# Generate service account key -resource "google_service_account_key" "relay" { - service_account_id = google_service_account.relay.name -} - -# Bootstrap script to install Nix on first boot -resource "linode_stackscript" "bootstrap" { - label = "moq-bootstrap" - description = "Bootstrap Debian with Nix" - script = file("${path.module}/bootstrap.sh") - images = ["linode/debian12"] -} diff --git a/cdn/dns.tf b/cdn/dns.tf deleted file mode 100644 index 506f4a7267..0000000000 --- a/cdn/dns.tf +++ /dev/null @@ -1,64 +0,0 @@ -# DNS zone for relay servers -resource "google_dns_managed_zone" "relay" { - name = "relay-cdn" - dns_name = "${var.domain}." - dnssec_config { - state = "on" - } -} - -# Individual DNS records for each relay node (for direct access) -resource "google_dns_record_set" "relay_node" { - for_each = local.relays - - name = "${each.key}.${google_dns_managed_zone.relay.dns_name}" - managed_zone = google_dns_managed_zone.relay.name - type = "A" - ttl = 300 - rrdatas = linode_instance.relay[each.key].ipv4 -} - -# Global Geo DNS, routing to the closest region -resource "google_dns_record_set" "relay_global" { - name = google_dns_managed_zone.relay.dns_name - managed_zone = google_dns_managed_zone.relay.name - type = "A" - ttl = 300 - - routing_policy { - dynamic "geo" { - for_each = local.relay_gcp_regions - - content { - location = geo.value - rrdatas = linode_instance.relay[geo.key].ipv4 - } - } - } -} - -# Region mapping for GCP geo routing -# GCP uses region codes like "us-east1", "us-west1", "europe-west3", "asia-southeast1" -locals { - relay_gcp_regions = { - usc = "us-central1" # Dallas, TX -> closest GCP region - euc = "europe-west3" # Frankfurt -> closest GCP region - sea = "asia-southeast1" # Singapore -> closest GCP region - } -} - -# DNS record for publisher node -resource "google_dns_record_set" "publisher" { - name = "pub.${google_dns_managed_zone.relay.dns_name}" - managed_zone = google_dns_managed_zone.relay.name - type = "A" - ttl = 300 - rrdatas = linode_instance.publisher.ipv4 -} - -# Grant DNS admin permissions to the service account -resource "google_project_iam_member" "dns_admin" { - project = var.gcp_project - role = "roles/dns.admin" - member = "serviceAccount:${google_service_account.relay.email}" -} diff --git a/cdn/flake.lock b/cdn/flake.lock deleted file mode 100644 index 80e369392a..0000000000 --- a/cdn/flake.lock +++ /dev/null @@ -1,368 +0,0 @@ -{ - "nodes": { - "cdn": { - "inputs": { - "flake-utils": [ - "moq", - "flake-utils" - ], - "moq": "moq_2", - "nixpkgs": [ - "moq", - "nixpkgs" - ] - }, - "locked": { - "path": "./cdn", - "type": "path" - }, - "original": { - "path": "./cdn", - "type": "path" - }, - "parent": [ - "moq" - ] - }, - "crane": { - "locked": { - "lastModified": 1763938834, - "narHash": "sha256-j8iB0Yr4zAvQLueCZ5abxfk6fnG/SJ5JnGUziETjwfg=", - "owner": "ipetkov", - "repo": "crane", - "rev": "d9e753122e51cee64eb8d2dddfe11148f339f5a2", - "type": "github" - }, - "original": { - "owner": "ipetkov", - "repo": "crane", - "type": "github" - } - }, - "crane_2": { - "locked": { - "lastModified": 1760924934, - "narHash": "sha256-tuuqY5aU7cUkR71sO2TraVKK2boYrdW3gCSXUkF4i44=", - "owner": "ipetkov", - "repo": "crane", - "rev": "c6b4d5308293d0d04fcfeee92705017537cad02f", - "type": "github" - }, - "original": { - "owner": "ipetkov", - "repo": "crane", - "type": "github" - } - }, - "flake-utils": { - "inputs": { - "systems": "systems" - }, - "locked": { - "lastModified": 1731533236, - "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "flake-utils_2": { - "inputs": { - "systems": "systems_2" - }, - "locked": { - "lastModified": 1731533236, - "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "flake-utils_3": { - "inputs": { - "systems": "systems_3" - }, - "locked": { - "lastModified": 1731533236, - "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "js": { - "inputs": { - "flake-utils": "flake-utils_3", - "nixpkgs": "nixpkgs_2" - }, - "locked": { - "path": "./js", - "type": "path" - }, - "original": { - "path": "./js", - "type": "path" - }, - "parent": [ - "moq" - ] - }, - "moq": { - "inputs": { - "cdn": "cdn", - "crane": "crane_2", - "flake-utils": "flake-utils_2", - "js": "js", - "nixpkgs": "nixpkgs_3", - "rs": "rs", - "rust-overlay": "rust-overlay_2" - }, - "locked": { - "lastModified": 1765242341, - "narHash": "sha256-xctkx17D5+xKyWsqrgwbO20/c3QwVT+ITglHpcKBAK4=", - "owner": "kixelated", - "repo": "moq", - "rev": "252c160fe07f907433b0c55bc64cb19d663bdeb6", - "type": "github" - }, - "original": { - "owner": "kixelated", - "repo": "moq", - "type": "github" - } - }, - "moq_2": { - "inputs": { - "crane": "crane", - "flake-utils": "flake-utils", - "nixpkgs": "nixpkgs", - "rust-overlay": "rust-overlay" - }, - "locked": { - "dir": "rs", - "lastModified": 1765236058, - "narHash": "sha256-v+dXxh4ZsWrtoCUUoTG3nzzXnZ+V5Bqugu5fqaev+30=", - "owner": "kixelated", - "repo": "moq", - "rev": "07be135ae654c9bf806b450941bf42e3e05704e1", - "type": "github" - }, - "original": { - "dir": "rs", - "owner": "kixelated", - "repo": "moq", - "type": "github" - } - }, - "nixpkgs": { - "locked": { - "lastModified": 1763966396, - "narHash": "sha256-6eeL1YPcY1MV3DDStIDIdy/zZCDKgHdkCmsrLJFiZf0=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "5ae3b07d8d6527c42f17c876e404993199144b6a", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_2": { - "locked": { - "lastModified": 1748792178, - "narHash": "sha256-BHmgfHlCJVNisJShVaEmfDIr/Ip58i/4oFGlD1iK6lk=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "5929de975bcf4c7c8d8b5ca65c8cd9ef9e44523e", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_3": { - "locked": { - "lastModified": 1761880412, - "narHash": "sha256-QoJjGd4NstnyOG4mm4KXF+weBzA2AH/7gn1Pmpfcb0A=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "a7fc11be66bdfb5cdde611ee5ce381c183da8386", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_4": { - "locked": { - "lastModified": 1764950072, - "narHash": "sha256-BmPWzogsG2GsXZtlT+MTcAWeDK5hkbGRZTeZNW42fwA=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "f61125a668a320878494449750330ca58b78c557", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "root": { - "inputs": { - "moq": "moq", - "nixpkgs": "nixpkgs_4" - } - }, - "rs": { - "inputs": { - "crane": [ - "moq", - "crane" - ], - "flake-utils": [ - "moq", - "flake-utils" - ], - "nixpkgs": [ - "moq", - "nixpkgs" - ], - "rust-overlay": [ - "moq", - "rust-overlay" - ] - }, - "locked": { - "path": "./rs", - "type": "path" - }, - "original": { - "path": "./rs", - "type": "path" - }, - "parent": [ - "moq" - ] - }, - "rust-overlay": { - "inputs": { - "nixpkgs": [ - "moq", - "cdn", - "moq", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1764124769, - "narHash": "sha256-vcoOEy3i8AGJi3Y2C48hrf6CuL2h8W1gLe1gNt72Kxg=", - "owner": "oxalica", - "repo": "rust-overlay", - "rev": "5da8c00313b4434f00aed6b4c94cd3b207bafdc5", - "type": "github" - }, - "original": { - "owner": "oxalica", - "repo": "rust-overlay", - "type": "github" - } - }, - "rust-overlay_2": { - "inputs": { - "nixpkgs": [ - "moq", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1761964689, - "narHash": "sha256-Zo3LQQDz+64EQ9zor/WmeNTFLoZkjmhp0UY3G0D3seE=", - "owner": "oxalica", - "repo": "rust-overlay", - "rev": "63d22578600f70d293aede6bc737efef60ebd97f", - "type": "github" - }, - "original": { - "owner": "oxalica", - "repo": "rust-overlay", - "type": "github" - } - }, - "systems": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - }, - "systems_2": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - }, - "systems_3": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - } - }, - "root": "root", - "version": 7 -} diff --git a/cdn/flake.nix b/cdn/flake.nix deleted file mode 100644 index 6fa54845b8..0000000000 --- a/cdn/flake.nix +++ /dev/null @@ -1,35 +0,0 @@ -{ - description = "MoQ relay server dependencies"; - - inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - moq = { - # Unfortunately, we can't use a relative path here because it executes on the remote. - # TODO cross-compile locally and upload the binary to the remote. - url = "github:moq-dev/moq"; - }; - }; - - outputs = - { - nixpkgs, - moq, - ... - }: - { - # Linux-only packages for deployment - packages.x86_64-linux = - let - system = "x86_64-linux"; - pkgs = nixpkgs.legacyPackages.${system}; - in - { - default = pkgs.certbot.withPlugins (ps: [ ps.certbot-dns-google ]); - certbot = pkgs.certbot.withPlugins (ps: [ ps.certbot-dns-google ]); - moq-relay = moq.packages.${system}.moq-relay; - cachix = pkgs.cachix; - ffmpeg = pkgs.ffmpeg; - hang-cli = moq.packages.${system}.hang; - }; - }; -} diff --git a/cdn/input.tf b/cdn/input.tf deleted file mode 100644 index 6a5a40f582..0000000000 --- a/cdn/input.tf +++ /dev/null @@ -1,45 +0,0 @@ -variable "linode_token" { - description = "Linode API token" - type = string - sensitive = true -} - -variable "gcp_project" { - description = "GCP project ID for DNS management" - type = string -} - -variable "domain" { - description = "Relay domain name" - type = string -} - -variable "email" { - description = "Email address for LetsEncrypt notifications" - type = string -} - -variable "ssh_keys" { - description = "SSH public keys for root access" - type = list(string) -} - -# Relay node definitions -# regions: https://api.linode.com/v4/regions -# instance types: https://api.linode.com/v4/linode/types -locals { - relays = { - usc = { - region = "us-central" # Dallas, TX - type = "g6-standard-2" # 4GB RAM, 2 vCPU, $24/mo, 4TB out - } - euc = { - region = "eu-central" # Frankfurt, Germany - type = "g6-standard-2" - } - sea = { - region = "ap-south" # Singapore - type = "g6-standard-2" - } - } -} diff --git a/cdn/justfile b/cdn/justfile deleted file mode 100644 index 81c38c73d8..0000000000 --- a/cdn/justfile +++ /dev/null @@ -1,126 +0,0 @@ -# List all of the available commands. -default: - just --list - -# Get the hostname for a node -host node: - #!/usr/bin/env bash - DOMAIN=$(tofu output -raw domain) - echo "{{node}}.$DOMAIN" - -# Deploy moq-relay and moq-cert to all nodes -[parallel] -deploy-all: (deploy "usc") (deploy "euc") (deploy "sea") - -# List the available nodes. -nodes: - @echo "usc: Dallas, TX" - @echo "euc: Frankfurt, Germany" - @echo "sea: Singapore" - -# Deploy moq-relay and moq-cert to a specific node -deploy node: - #!/usr/bin/env bash - set -euo pipefail - HOST=$(just host {{node}}) - echo "Deploying to $HOST..." - - echo " Copying flake files to /var/lib/moq" - rsync -az flake.nix flake.lock root@$HOST:/var/lib/moq/ - - echo " Copying secrets to /var/lib/moq" - rsync -az secrets/ root@$HOST:/var/lib/moq/ - ssh root@$HOST "chmod -R 755 /var/lib/moq && chmod 600 /var/lib/moq/*.jwk /var/lib/moq/*.jwt" - - echo " Copying systemd units to /etc/systemd/system/..." - rsync -az relay/ root@$HOST:/etc/systemd/system/ - - echo " Building and caching packages..." - ssh root@$HOST "cd /var/lib/moq && nix build .#moq-relay -o relay && nix build .#certbot -o cert" - - echo " Enabling and starting services..." - ssh root@$HOST "\ - systemctl daemon-reload && \ - systemctl enable moq-cert.service && \ - systemctl enable certbot-renew.timer && \ - systemctl enable vacuum.timer && \ - systemctl enable moq-relay.service && \ - systemctl start certbot-renew.timer && \ - systemctl start vacuum.timer && \ - systemctl start moq-cert.service && \ - systemctl restart moq-relay.service" - -# Check status of a node -status node: - #!/usr/bin/env bash - HOST=$(just host {{node}}) - echo "=== $HOST ===" - ssh root@$HOST "systemctl status moq-relay --no-pager" - -status-all: (status "usc") (status "euc") (status "sea") - -ssh node: - #!/usr/bin/env bash - ssh root@$(just host {{node}}) - -# View logs from a specific node -logs node: - #!/usr/bin/env bash - ssh root@$(just host {{node}}) "journalctl -u moq-relay -f" - -# Deploy publisher -deploy-pub: - #!/usr/bin/env bash - set -euo pipefail - HOST=$(just host pub) - echo "Deploying to $HOST..." - - echo " Copying flake files to /var/lib/moq" - rsync -az flake.nix flake.lock root@$HOST:/var/lib/moq/ - - echo " Copying secrets to /var/lib/moq" - rsync -az secrets/ root@$HOST:/var/lib/moq/ - ssh root@$HOST "chmod -R 755 /var/lib/moq && chmod 600 /var/lib/moq/*.jwt" - - echo " Copying systemd units to /etc/systemd/system/..." - rsync -az pub/ root@$HOST:/etc/systemd/system/ - - echo " Building and caching packages..." - ssh root@$HOST "cd /var/lib/moq && nix build .#ffmpeg -o result && nix build .#hang-cli -o result-hang" - - echo " Enabling and starting services..." - ssh root@$HOST "\ - systemctl daemon-reload && \ - systemctl enable hang-bbb-prepare.service && \ - systemctl enable hang-bbb.service && \ - systemctl enable vacuum.timer && \ - systemctl start hang-bbb-prepare.service && \ - systemctl start vacuum.timer && \ - systemctl restart hang-bbb.service" - -# Check status of publisher -status-pub: - #!/usr/bin/env bash - HOST=$(just host pub) - echo "=== $HOST ===" - ssh root@$HOST "systemctl status hang-bbb --no-pager" - -# SSH into publisher -ssh-pub: - #!/usr/bin/env bash - HOST=$(just host pub) - ssh root@$HOST - -# View logs from publisher -logs-pub: - #!/usr/bin/env bash - HOST=$(just host pub) - ssh root@$HOST "journalctl -u hang-bbb -f" - -# Check tofu formatting -check: - tofu fmt -check -recursive - -# Fix tofu formatting -fix: - tofu fmt -recursive diff --git a/cdn/main.tf b/cdn/main.tf deleted file mode 100644 index 612fb2c311..0000000000 --- a/cdn/main.tf +++ /dev/null @@ -1,42 +0,0 @@ -terraform { - required_providers { - linode = { - source = "linode/linode" - version = "~> 3.4" - } - - google = { - source = "hashicorp/google" - version = "~> 5.0" - } - } - - backend "local" { - path = "tofu.tfstate" - } - - required_version = ">= 1.6" -} - -provider "linode" { - token = var.linode_token -} - -provider "google" { - project = var.gcp_project -} - -variable "gcp_service_list" { - description = "The list of apis necessary for the project" - type = list(string) - default = [ - "dns.googleapis.com", - ] -} - -resource "google_project_service" "all" { - for_each = toset(var.gcp_service_list) - service = each.key - disable_dependent_services = false - disable_on_destroy = false -} diff --git a/cdn/output.tf b/cdn/output.tf deleted file mode 100644 index 35f9de7079..0000000000 --- a/cdn/output.tf +++ /dev/null @@ -1,5 +0,0 @@ -# Domain configuration -output "domain" { - description = "Base domain for all nodes" - value = var.domain -} diff --git a/cdn/pub/hang-bbb-prepare.service b/cdn/pub/hang-bbb-prepare.service deleted file mode 100644 index a7bed17594..0000000000 --- a/cdn/pub/hang-bbb-prepare.service +++ /dev/null @@ -1,23 +0,0 @@ -[Unit] -Description=Prepare video for hang-bbb publisher -Before=hang-bbb.service - -[Service] -Type=oneshot -RemainAfterExit=yes -User=root -WorkingDirectory=/var/lib/moq - -ExecStart=/bin/bash -c '\ - # Download the video \ - /nix/var/nix/profiles/default/bin/nix shell nixpkgs#wget -c wget -nv http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4 -O /var/lib/moq/tmp.mp4 && \ - # Fragment the video using ffmpeg from flake \ - /var/lib/moq/result-bin/bin/ffmpeg \ - -y -loglevel error -i /var/lib/moq/tmp.mp4 \ - -c copy \ - -f mp4 -movflags cmaf+separate_moof+delay_moov+skip_trailer+frag_every_frame \ - /var/lib/moq/fragmented.mp4 && \ - rm -f /var/lib/moq/tmp.mp4' - -[Install] -WantedBy=multi-user.target diff --git a/cdn/pub/hang-bbb.service b/cdn/pub/hang-bbb.service deleted file mode 100644 index 922f8789b7..0000000000 --- a/cdn/pub/hang-bbb.service +++ /dev/null @@ -1,37 +0,0 @@ -[Unit] -Description=MoQ Publisher - Big Buck Bunny -After=network-online.target hang-bbb-prepare.service -Wants=network-online.target -Requires=hang-bbb-prepare.service - -[Service] -Type=simple -User=root -WorkingDirectory=/var/lib/moq -Environment="RUST_LOG=debug" - -# Stream fragmented video in a loop and pipe to hang publish -ExecStart=/bin/bash -c '\ - /var/lib/moq/result-bin/bin/ffmpeg \ - -stream_loop -1 \ - -hide_banner \ - -v quiet \ - -re \ - -i /var/lib/moq/fragmented.mp4 \ - -c copy \ - -f mp4 \ - -movflags cmaf+separate_moof+delay_moov+skip_trailer+frag_every_frame \ - - | \ - /var/lib/moq/result-hang/bin/hang publish \ - --url "https://cdn.moq.dev/demo?jwt=$(cat /var/lib/moq/demo-pub.jwt)" \ - --name bbb' - -# Restart with exponential backoff -Restart=always -RestartSec=10s - -StandardOutput=journal -StandardError=journal - -[Install] -WantedBy=multi-user.target diff --git a/cdn/pub/vacuum.service b/cdn/pub/vacuum.service deleted file mode 100644 index 4f8a493942..0000000000 --- a/cdn/pub/vacuum.service +++ /dev/null @@ -1,10 +0,0 @@ -[Unit] -Description=Vacuum systemd journal logs -Documentation=man:journalctl(1) - -[Service] -Type=oneshot -ExecStart=/usr/bin/journalctl --vacuum-time=7d --vacuum-size=500M - -StandardOutput=journal -StandardError=journal diff --git a/cdn/pub/vacuum.timer b/cdn/pub/vacuum.timer deleted file mode 100644 index 8bb7ec9e75..0000000000 --- a/cdn/pub/vacuum.timer +++ /dev/null @@ -1,12 +0,0 @@ -[Unit] -Description=Vacuum systemd journal logs daily -After=multi-user.target - -[Timer] -# Run daily at 2am -OnCalendar=02:00 -# Run on boot if we missed a scheduled run -Persistent=true - -[Install] -WantedBy=timers.target diff --git a/cdn/publisher.tf b/cdn/publisher.tf deleted file mode 100644 index 76a6b3069d..0000000000 --- a/cdn/publisher.tf +++ /dev/null @@ -1,48 +0,0 @@ -# Publisher instance -resource "linode_instance" "publisher" { - label = "publisher-moq" - region = "us-central" # Dallas, TX - type = "g6-nanode-1" - - # Use Debian 12 as base, will be converted to NixOS via bootstrap - image = "linode/debian12" - root_pass = random_password.publisher_root.result - authorized_keys = var.ssh_keys - - # Publisher only needs outbound, no special inbound - firewall_id = linode_firewall.publisher.id - - # Bootstrap script - only installs Nix and creates directories - stackscript_id = linode_stackscript.bootstrap.id - stackscript_data = { - hostname = "pub.${var.domain}" - gcp_account = google_service_account_key.relay.private_key - } - - tags = ["publisher", "moq"] -} - -# Generate random root password for publisher -resource "random_password" "publisher_root" { - length = 32 - special = true -} - -# Firewall rules for publisher (SSH only) -resource "linode_firewall" "publisher" { - label = "publisher-firewall" - - inbound { - label = "allow-ssh" - action = "ACCEPT" - protocol = "TCP" - ports = "22" - ipv4 = ["0.0.0.0/0"] - ipv6 = ["::/0"] - } - - inbound_policy = "DROP" - outbound_policy = "ACCEPT" - - tags = ["publisher"] -} diff --git a/cdn/relay.tf b/cdn/relay.tf deleted file mode 100644 index d41b95542b..0000000000 --- a/cdn/relay.tf +++ /dev/null @@ -1,86 +0,0 @@ -# Generate systemd service files from templates -resource "local_file" "moq_relay_service" { - content = templatefile("${path.module}/relay/moq-relay.service.tftpl", { - domain = var.domain - }) - filename = "${path.module}/relay/moq-relay.service" -} - -resource "local_file" "moq_cert_service" { - content = templatefile("${path.module}/relay/moq-cert.service.tftpl", { - domain = var.domain - email = var.email - }) - filename = "${path.module}/relay/moq-cert.service" -} - -# Create Linode instances -resource "linode_instance" "relay" { - for_each = local.relays - - label = "relay-${each.key}" - region = each.value.region - type = each.value.type - - # Use Debian 12 as base, will be converted to NixOS via bootstrap - image = "linode/debian12" - root_pass = random_password.relay_root[each.key].result - authorized_keys = var.ssh_keys - - # Open firewall for QUIC/WebTransport - firewall_id = linode_firewall.relay.id - - # Bootstrap script - only installs Nix and creates directories - stackscript_id = linode_stackscript.bootstrap.id - stackscript_data = { - hostname = "${each.key}.${var.domain}" - gcp_account = google_service_account_key.relay.private_key - } - - tags = ["relay", "moq"] -} - -# Generate random root passwords (store these securely!) -resource "random_password" "relay_root" { - for_each = local.relays - - length = 32 - special = true -} - -# Firewall rules for relay servers -resource "linode_firewall" "relay" { - label = "relay-firewall" - - inbound { - label = "allow-ssh" - action = "ACCEPT" - protocol = "TCP" - ports = "22" - ipv4 = ["0.0.0.0/0"] - ipv6 = ["::/0"] - } - - inbound { - label = "allow-quic-udp" - action = "ACCEPT" - protocol = "UDP" - ports = "443" - ipv4 = ["0.0.0.0/0"] - ipv6 = ["::/0"] - } - - inbound { - label = "allow-quic-tcp" - action = "ACCEPT" - protocol = "TCP" - ports = "443" - ipv4 = ["0.0.0.0/0"] - ipv6 = ["::/0"] - } - - inbound_policy = "DROP" - outbound_policy = "ACCEPT" - - tags = ["relay"] -} diff --git a/cdn/relay/certbot-renew.service b/cdn/relay/certbot-renew.service deleted file mode 100644 index cdf30e44cd..0000000000 --- a/cdn/relay/certbot-renew.service +++ /dev/null @@ -1,12 +0,0 @@ -[Unit] -Description=Certbot Certificate Renewal -After=network-online.target -Wants=network-online.target - -[Service] -Type=oneshot -# Renew certificates if they're close to expiration -ExecStart=/var/lib/moq/cert/bin/certbot renew - -StandardOutput=journal -StandardError=journal diff --git a/cdn/relay/certbot-renew.timer b/cdn/relay/certbot-renew.timer deleted file mode 100644 index aa1b7856dc..0000000000 --- a/cdn/relay/certbot-renew.timer +++ /dev/null @@ -1,14 +0,0 @@ -[Unit] -Description=Certbot Certificate Renewal Timer -After=network-online.target - -[Timer] -# Run daily at 3am -OnCalendar=03:00 -# Run on boot if we missed a scheduled run -Persistent=true -# Add some randomness to avoid all nodes hitting Let's Encrypt at once -RandomizedDelaySec=3600 - -[Install] -WantedBy=timers.target diff --git a/cdn/relay/moq-cert.service b/cdn/relay/moq-cert.service deleted file mode 100644 index b634b070f1..0000000000 --- a/cdn/relay/moq-cert.service +++ /dev/null @@ -1,23 +0,0 @@ -[Unit] -Description=MoQ Initial Certificate -After=network-online.target -Wants=network-online.target - -[Service] -Type=oneshot -RemainAfterExit=yes -# Obtain initial certificate -ExecStart=/bin/sh -c '/var/lib/moq/cert/bin/certbot certonly \ - --dns-google \ - --dns-google-credentials /var/lib/moq/gcp.json \ - --non-interactive \ - --agree-tos \ - --email admin@moq.dev \ - -d cdn.moq.dev \ - -d $(hostname)' - -StandardOutput=journal -StandardError=journal - -[Install] -WantedBy=multi-user.target diff --git a/cdn/relay/moq-cert.service.tftpl b/cdn/relay/moq-cert.service.tftpl deleted file mode 100644 index 86ab44d49a..0000000000 --- a/cdn/relay/moq-cert.service.tftpl +++ /dev/null @@ -1,23 +0,0 @@ -[Unit] -Description=MoQ Initial Certificate -After=network-online.target -Wants=network-online.target - -[Service] -Type=oneshot -RemainAfterExit=yes -# Obtain initial certificate -ExecStart=/bin/sh -c '/var/lib/moq/cert/bin/certbot certonly \ - --dns-google \ - --dns-google-credentials /var/lib/moq/gcp.json \ - --non-interactive \ - --agree-tos \ - --email ${email} \ - -d ${domain} \ - -d $(hostname)' - -StandardOutput=journal -StandardError=journal - -[Install] -WantedBy=multi-user.target diff --git a/cdn/relay/moq-relay.service b/cdn/relay/moq-relay.service deleted file mode 100644 index 9ae964eca7..0000000000 --- a/cdn/relay/moq-relay.service +++ /dev/null @@ -1,37 +0,0 @@ -[Unit] -Description=MoQ Relay Server -After=network-online.target moq-cert.service -Wants=network-online.target -Requires=moq-cert.service - -[Service] -Type=notify -User=root -WorkingDirectory=/var/lib/moq -Environment="RUST_LOG=trace" -Environment="RUST_BACKTRACE=1" - -ExecStart=/var/lib/moq/relay/bin/moq-relay \ - --listen [::]:443 \ - --tls-cert /etc/letsencrypt/live/cdn.moq.dev/fullchain.pem \ - --tls-key /etc/letsencrypt/live/cdn.moq.dev/privkey.pem \ - --auth-key /var/lib/moq/root.jwk \ - --auth-public anon \ - --web-https-listen [::]:443 \ - --web-https-cert /etc/letsencrypt/live/cdn.moq.dev/fullchain.pem \ - --web-https-key /etc/letsencrypt/live/cdn.moq.dev/privkey.pem \ - --cluster-root usc.cdn.moq.dev \ - --cluster-node %H \ - --cluster-token /var/lib/moq/cluster.jwt - -Restart=always -RestartSec=10 -StandardOutput=journal -StandardError=journal - -# Security hardening - relaxed to allow Nix to work -NoNewPrivileges=true -AmbientCapabilities=CAP_NET_BIND_SERVICE - -[Install] -WantedBy=multi-user.target diff --git a/cdn/relay/moq-relay.service.tftpl b/cdn/relay/moq-relay.service.tftpl deleted file mode 100644 index 0a62715f6b..0000000000 --- a/cdn/relay/moq-relay.service.tftpl +++ /dev/null @@ -1,37 +0,0 @@ -[Unit] -Description=MoQ Relay Server -After=network-online.target moq-cert.service -Wants=network-online.target -Requires=moq-cert.service - -[Service] -Type=notify -User=root -WorkingDirectory=/var/lib/moq -Environment="RUST_LOG=trace" -Environment="RUST_BACKTRACE=1" - -ExecStart=/var/lib/moq/relay/bin/moq-relay \ - --listen [::]:443 \ - --tls-cert /etc/letsencrypt/live/${domain}/fullchain.pem \ - --tls-key /etc/letsencrypt/live/${domain}/privkey.pem \ - --auth-key /var/lib/moq/root.jwk \ - --auth-public anon \ - --web-https-listen [::]:443 \ - --web-https-cert /etc/letsencrypt/live/${domain}/fullchain.pem \ - --web-https-key /etc/letsencrypt/live/${domain}/privkey.pem \ - --cluster-root usc.${domain} \ - --cluster-node %H \ - --cluster-token /var/lib/moq/cluster.jwt - -Restart=always -RestartSec=10 -StandardOutput=journal -StandardError=journal - -# Security hardening - relaxed to allow Nix to work -NoNewPrivileges=true -AmbientCapabilities=CAP_NET_BIND_SERVICE - -[Install] -WantedBy=multi-user.target diff --git a/cdn/relay/vacuum.service b/cdn/relay/vacuum.service deleted file mode 100644 index 81f19ac24c..0000000000 --- a/cdn/relay/vacuum.service +++ /dev/null @@ -1,11 +0,0 @@ -[Unit] -Description=Vacuum systemd journal logs and Nix store -Documentation=man:journalctl(1) man:nix-collect-garbage(1) - -[Service] -Type=oneshot -ExecStart=/usr/bin/journalctl --vacuum-time=7d --vacuum-size=500M -ExecStart=/usr/bin/nix-collect-garbage --delete-older-than 7d - -StandardOutput=journal -StandardError=journal diff --git a/cdn/relay/vacuum.timer b/cdn/relay/vacuum.timer deleted file mode 100644 index 8bb7ec9e75..0000000000 --- a/cdn/relay/vacuum.timer +++ /dev/null @@ -1,12 +0,0 @@ -[Unit] -Description=Vacuum systemd journal logs daily -After=multi-user.target - -[Timer] -# Run daily at 2am -OnCalendar=02:00 -# Run on boot if we missed a scheduled run -Persistent=true - -[Install] -WantedBy=timers.target diff --git a/cdn/terraform.tfvars.example b/cdn/terraform.tfvars.example deleted file mode 100644 index 2a8c239d5b..0000000000 --- a/cdn/terraform.tfvars.example +++ /dev/null @@ -1,20 +0,0 @@ -# Copy this file to terraform.tfvars and fill in your values - -# The domain to use for the GeoDNS entry. -# Each node will register its own subdomain. -domain = "cdn.moq.dev" - -# Linode API token (create at: https://cloud.linode.com/profile/tokens) -linode_token = "your-linode-api-token" - -# GCP project ID for DNS management -# Note: GCP credentials will be read from ~/.config/gcloud or GOOGLE_APPLICATION_CREDENTIALS -gcp_project = "your-gcp-project-id" - -# Email for LetsEncrypt notifications -email = "admin@moq.dev" - -# Your SSH public key for root access -ssh_keys = [ - "ssh-ed25519 AAAA... your-key-comment", -] diff --git a/demo/boy/.gitignore b/demo/boy/.gitignore new file mode 100644 index 0000000000..2a82664306 --- /dev/null +++ b/demo/boy/.gitignore @@ -0,0 +1,2 @@ +rom/ +.wrangler/ diff --git a/demo/boy/CHANGELOG.md b/demo/boy/CHANGELOG.md new file mode 100644 index 0000000000..2e9d8af00f --- /dev/null +++ b/demo/boy/CHANGELOG.md @@ -0,0 +1,14 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.1.0](https://github.com/moq-dev/moq/releases/tag/moq-boy-v0.1.0) - 2026-04-03 + +### Other + +- Replace drone demo with MoQ Boy ([#1197](https://github.com/moq-dev/moq/pull/1197)) diff --git a/demo/boy/justfile b/demo/boy/justfile new file mode 100644 index 0000000000..b5387236ae --- /dev/null +++ b/demo/boy/justfile @@ -0,0 +1,86 @@ +set fallback + +# Run the GB demo: relay + emulator publisher + web viewer. +default: + bun install + + bun run concurrently --kill-others --prefix-colors auto \ + "just relay" \ + "just wait && just b2s" \ + "just wait && just dangan" \ + "just wait && just web" + +# Download the given ROM from our R2 bucket. +download rom: + #!/usr/bin/env bash + if [ ! -f "rom/{{ rom }}" ]; then + mkdir -p rom + curl -fSL -o "rom/{{ rom }}.tmp" "https://rom.moq.dev/{{ rom }}" + mv "rom/{{ rom }}.tmp" "rom/{{ rom }}" + fi + +# Big2Small (puzzle): https://mdsteele.itch.io/big2small +b2s: + just download big2small.gb + just start rom/big2small.gb + +# Dangan GB2 (bullet hell): https://snorpung.itch.io/dangan-gb2 +dangan: + just download DanganGB2.gbc + just start rom/DanganGB2.gbc + +# Opossum Country (horror): https://benjelter.itch.io/opossum-country +opossum: + just download OpossumCountry.gbc + just start rom/OpossumCountry.gbc + +# Swordbird Song - Iron Owl Tower +songbird: + just download Swordbird.gb + just start rom/Swordbird.gb + +# RunieStory +runiestory: + just download RunieStory.gb + just start rom/RunieStory.gb + +# GB Run (racing): https://biscuitlocker.itch.io/gb-run +gb-run: + just download gb-run.gbc + just start rom/gb-run.gbc + +# Start a Game Boy emulator publisher. +start rom url='http://localhost:4443/anon': + cargo run --bin moq-boy -- --url "{{ url }}" --rom "{{ rom }}" --location localhost + +# Host the web server +web url='http://localhost:4443/anon': + VITE_RELAY_URL="{{ url }}" bun --bun vite --open + +# --- rom.moq.dev (R2 hosting) --- + +# Deploy the rom.moq.dev worker +deploy: + bun install + bun wrangler deploy + +# Upload a single ROM to R2 +upload file: + bun install + bun wrangler r2 object put "rom-moq-dev/{{ file }}" --file "rom/{{ file }}" --remote + +# Sync all ROMs to R2 +sync dir="rom": + #!/usr/bin/env bash + set -euo pipefail + for file in "{{ dir }}"/*; do + [ -e "$file" ] || continue + key=$(basename "$file") + echo "Uploading $key..." + bun wrangler r2 object put "rom-moq-dev/$key" --file "$file" --remote + done + +# List files in the R2 bucket +list: + bun install + bun wrangler r2 object list "rom-moq-dev" diff --git a/demo/boy/package.json b/demo/boy/package.json new file mode 100644 index 0000000000..029c40fe7c --- /dev/null +++ b/demo/boy/package.json @@ -0,0 +1,20 @@ +{ + "name": "@moq/demo-boy", + "private": true, + "type": "module", + "version": "0.2.0", + "description": "MoQ Boy Demo - Crowd-controlled Game Boy streaming", + "license": "(MIT OR Apache-2.0)", + "scripts": { + "dev": "vite --open" + }, + "dependencies": { + "@moq/boy": "workspace:^" + }, + "devDependencies": { + "esbuild": "^0.27.0", + "typescript": "^6.0.0", + "vite": "^7.3.1", + "vite-plugin-solid": "^2.11.10" + } +} diff --git a/demo/boy/src/index.html b/demo/boy/src/index.html new file mode 100644 index 0000000000..b78d0461f0 --- /dev/null +++ b/demo/boy/src/index.html @@ -0,0 +1,81 @@ + + + + + + MoQ Boy + + + +
+

MoQ Boy

+
+ + + +
+

Click a game to play. Multiple players can control it. (anarchy!)

+

+ A generic MoQ relay is used for everything: +

+
    +
  • Discovering online games and players.
  • +
  • Transmitting audio/video tracks, metadata, and player controls.
  • +
  • Pausing emulation/encoding when there are no subscribers.
  • +
+
+ +
try: just boy opossum
+ + + + diff --git a/demo/boy/src/index.ts b/demo/boy/src/index.ts new file mode 100644 index 0000000000..6258d1d7b7 --- /dev/null +++ b/demo/boy/src/index.ts @@ -0,0 +1,15 @@ +import "@moq/boy/element"; +import { Effect } from "@moq/signals"; + +const url = import.meta.env.VITE_RELAY_URL || "http://localhost:4443/anon"; + +const boy = document.querySelector("moq-boy"); +if (boy) boy.url = url; + +const about = document.getElementById("about"); +if (boy && about) { + const effect = new Effect(); + effect.run((inner) => { + about.hidden = inner.get(boy.expanded) !== undefined; + }); +} diff --git a/demo/boy/src/worker.ts b/demo/boy/src/worker.ts new file mode 100644 index 0000000000..3f7db4ec4b --- /dev/null +++ b/demo/boy/src/worker.ts @@ -0,0 +1,46 @@ +// Cloudflare Worker for rom.moq.dev — serves Game Boy ROMs from R2. + +interface Env { + ROM: R2Bucket; +} + +const CONTENT_TYPES: Record = { + ".gb": "application/octet-stream", + ".gbc": "application/octet-stream", +}; + +export default { + async fetch(request: Request, env: Env): Promise { + if (request.method !== "GET" && request.method !== "HEAD") { + return new Response("Method Not Allowed", { status: 405 }); + } + + const url = new URL(request.url); + const key = url.pathname.slice(1); + + if (!key) { + return new Response("Not Found", { status: 404 }); + } + + const object = await env.ROM.get(key); + if (!object) { + return new Response("Not Found", { status: 404 }); + } + + const dotIdx = key.lastIndexOf("."); + const ext = dotIdx >= 0 ? key.substring(dotIdx).toLowerCase() : ""; + const contentType = CONTENT_TYPES[ext] ?? "application/octet-stream"; + + const headers = { + "Content-Type": contentType, + "Cache-Control": "public, max-age=2592000", + "Content-Length": object.size.toString(), + }; + + if (request.method === "HEAD") { + return new Response(null, { headers }); + } + + return new Response(object.body, { headers }); + }, +}; diff --git a/demo/boy/vite.config.ts b/demo/boy/vite.config.ts new file mode 100644 index 0000000000..8b4b4d490a --- /dev/null +++ b/demo/boy/vite.config.ts @@ -0,0 +1,24 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; +import solidPlugin from "vite-plugin-solid"; +import { workletInline } from "../../js/common/vite-plugin-worklet"; + +export default defineConfig({ + root: "src", + envDir: resolve(__dirname), + plugins: [solidPlugin(), workletInline()], + build: { + target: "esnext", + rollupOptions: { + input: { + main: resolve(__dirname, "src/index.html"), + }, + }, + }, + server: { + hmr: false, + }, + optimizeDeps: { + exclude: ["@libav.js/variant-opus-af"], + }, +}); diff --git a/demo/boy/wrangler.jsonc b/demo/boy/wrangler.jsonc new file mode 100644 index 0000000000..1769469752 --- /dev/null +++ b/demo/boy/wrangler.jsonc @@ -0,0 +1,27 @@ +{ + // Cloudflare Wrangler configuration for ROM hosting (rom.moq.dev) + "$schema": "node_modules/wrangler/config-schema.json", + "name": "rom-moq-dev", + "main": "src/worker.ts", + "compatibility_date": "2025-07-09", + "account_id": "dd618f5dbd5da77b8296f1613c301f5c", + "workers_dev": false, + "route": { + "pattern": "rom.moq.dev", + "custom_domain": true + }, + // R2 bucket bindings + "r2_buckets": [ + { + "bucket_name": "rom-moq-dev", + "binding": "ROM", + "remote": true + } + ], + // Observability + "observability": { + "logs": { + "enabled": true + } + } +} diff --git a/demo/justfile b/demo/justfile new file mode 100644 index 0000000000..c94cd57e20 --- /dev/null +++ b/demo/justfile @@ -0,0 +1,30 @@ +set fallback + +mod boy +mod pub +mod relay +mod sub +mod web + +# Run the web demo (default). +default: + bun install + bun run concurrently --kill-others --names srv,bbb,web --prefix-colors auto \ + "just relay" \ + "just wait && just pub bbb" \ + "just wait && just web" + +# Wait for the localhost relay to be ready by repeatedly requesting the cert +[private] +wait url="http://localhost:4443/certificate.sha256": + #!/usr/bin/env bash + set -euo pipefail + for i in $(seq 1 600); do + curl -sf "{{ url }}" > /dev/null 2>&1 && exit 0 + sleep 1 + done + exit 1 + +# Throttle UDP traffic for testing (macOS only, requires sudo). +throttle: + throttle/enable diff --git a/demo/pub/bun.lock b/demo/pub/bun.lock new file mode 100644 index 0000000000..2842e269c2 --- /dev/null +++ b/demo/pub/bun.lock @@ -0,0 +1,194 @@ +{ + "lockfileVersion": 1, + "configVersion": 1, + "workspaces": { + "": { + "name": "video-moq-dev", + "devDependencies": { + "@cloudflare/workers-types": "^4", + "wrangler": "^4", + }, + }, + }, + "packages": { + "@cloudflare/kv-asset-handler": ["@cloudflare/kv-asset-handler@0.4.2", "", {}, "sha512-SIOD2DxrRRwQ+jgzlXCqoEFiKOFqaPjhnNTGKXSRLvp1HiOvapLaFG2kEr9dYQTYe8rKrd9uvDUzmAITeNyaHQ=="], + + "@cloudflare/unenv-preset": ["@cloudflare/unenv-preset@2.16.0", "", { "peerDependencies": { "unenv": "2.0.0-rc.24", "workerd": "1.20260301.1 || ~1.20260302.1 || ~1.20260303.1 || ~1.20260304.1 || >1.20260305.0 <2.0.0-0" }, "optionalPeers": ["workerd"] }, "sha512-8ovsRpwzPoEqPUzoErAYVv8l3FMZNeBVQfJTvtzP4AgLSRGZISRfuChFxHWUQd3n6cnrwkuTGxT+2cGo8EsyYg=="], + + "@cloudflare/workerd-darwin-64": ["@cloudflare/workerd-darwin-64@1.20260329.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-oyDXYlPBuGXKkZ85+M3jFz0/qYmvA4AEURN8USIGPDCR5q+HFSRwywSd9neTx3Wi7jhey2wuYaEpD3fEFWyWUA=="], + + "@cloudflare/workerd-darwin-arm64": ["@cloudflare/workerd-darwin-arm64@1.20260329.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-++ZxVa3ovzYeDLEG6zMqql9gzZAG8vak6ZSBQgprGKZp7akr+GKTpw9f3RrMP552NSi3gTisroLobrrkPBtYLQ=="], + + "@cloudflare/workerd-linux-64": ["@cloudflare/workerd-linux-64@1.20260329.1", "", { "os": "linux", "cpu": "x64" }, "sha512-kkeywAgIHwbqHkVILqbj/YkfbrA6ARbmutjiYzZA2MwMSfNXlw6/kedAKOY8YwcymZIgepx3YTIPnBP50pOotw=="], + + "@cloudflare/workerd-linux-arm64": ["@cloudflare/workerd-linux-arm64@1.20260329.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-eYBN20+B7XOUSWEe0mlqkMUbfLoIKjKZnpqQiSxnLbL72JKY0D/KlfN/b7RVGLpewB7i8rTrwTNr0szCKnZzSQ=="], + + "@cloudflare/workerd-windows-64": ["@cloudflare/workerd-windows-64@1.20260329.1", "", { "os": "win32", "cpu": "x64" }, "sha512-5R+/oxrDhS9nL3oA3ZWtD6ndMOqm7RfKknDNxLcmYW5DkUu7UH3J/s1t/Dz66iFePzr5BJmE7/8gbmve6TjtZQ=="], + + "@cloudflare/workers-types": ["@cloudflare/workers-types@4.20260401.1", "", {}, "sha512-tKBeV/ySfJjbO0qMKkFrstHDdWzZHAcW4vCpO5QaqjB/667y9lhZt9gZyTKeJ0gluIBwpeQ/efBjqRLqpkgw9g=="], + + "@cspotcode/source-map-support": ["@cspotcode/source-map-support@0.8.1", "", { "dependencies": { "@jridgewell/trace-mapping": "0.3.9" } }, "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw=="], + + "@emnapi/runtime": ["@emnapi/runtime@1.9.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA=="], + + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.3", "", { "os": "aix", "cpu": "ppc64" }, "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg=="], + + "@esbuild/android-arm": ["@esbuild/android-arm@0.27.3", "", { "os": "android", "cpu": "arm" }, "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA=="], + + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.3", "", { "os": "android", "cpu": "arm64" }, "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg=="], + + "@esbuild/android-x64": ["@esbuild/android-x64@0.27.3", "", { "os": "android", "cpu": "x64" }, "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ=="], + + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg=="], + + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg=="], + + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.3", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w=="], + + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA=="], + + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.3", "", { "os": "linux", "cpu": "arm" }, "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw=="], + + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg=="], + + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.3", "", { "os": "linux", "cpu": "ia32" }, "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg=="], + + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA=="], + + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw=="], + + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA=="], + + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ=="], + + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw=="], + + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.3", "", { "os": "linux", "cpu": "x64" }, "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA=="], + + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA=="], + + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.3", "", { "os": "none", "cpu": "x64" }, "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA=="], + + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.3", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw=="], + + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.3", "", { "os": "openbsd", "cpu": "x64" }, "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ=="], + + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g=="], + + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.3", "", { "os": "sunos", "cpu": "x64" }, "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA=="], + + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA=="], + + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q=="], + + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.3", "", { "os": "win32", "cpu": "x64" }, "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA=="], + + "@img/colour": ["@img/colour@1.1.0", "", {}, "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ=="], + + "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.2.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w=="], + + "@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.2.4" }, "os": "darwin", "cpu": "x64" }, "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw=="], + + "@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.2.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g=="], + + "@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.2.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg=="], + + "@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.2.4", "", { "os": "linux", "cpu": "arm" }, "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A=="], + + "@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw=="], + + "@img/sharp-libvips-linux-ppc64": ["@img/sharp-libvips-linux-ppc64@1.2.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA=="], + + "@img/sharp-libvips-linux-riscv64": ["@img/sharp-libvips-linux-riscv64@1.2.4", "", { "os": "linux", "cpu": "none" }, "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA=="], + + "@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.2.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ=="], + + "@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw=="], + + "@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw=="], + + "@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg=="], + + "@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.2.4" }, "os": "linux", "cpu": "arm" }, "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw=="], + + "@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg=="], + + "@img/sharp-linux-ppc64": ["@img/sharp-linux-ppc64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-ppc64": "1.2.4" }, "os": "linux", "cpu": "ppc64" }, "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA=="], + + "@img/sharp-linux-riscv64": ["@img/sharp-linux-riscv64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-riscv64": "1.2.4" }, "os": "linux", "cpu": "none" }, "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw=="], + + "@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.2.4" }, "os": "linux", "cpu": "s390x" }, "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg=="], + + "@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ=="], + + "@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg=="], + + "@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q=="], + + "@img/sharp-wasm32": ["@img/sharp-wasm32@0.34.5", "", { "dependencies": { "@emnapi/runtime": "^1.7.0" }, "cpu": "none" }, "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw=="], + + "@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.34.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g=="], + + "@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.34.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg=="], + + "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.5", "", { "os": "win32", "cpu": "x64" }, "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw=="], + + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], + + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], + + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.9", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="], + + "@poppinss/colors": ["@poppinss/colors@4.1.6", "", { "dependencies": { "kleur": "^4.1.5" } }, "sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg=="], + + "@poppinss/dumper": ["@poppinss/dumper@0.6.5", "", { "dependencies": { "@poppinss/colors": "^4.1.5", "@sindresorhus/is": "^7.0.2", "supports-color": "^10.0.0" } }, "sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw=="], + + "@poppinss/exception": ["@poppinss/exception@1.2.3", "", {}, "sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw=="], + + "@sindresorhus/is": ["@sindresorhus/is@7.2.0", "", {}, "sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw=="], + + "@speed-highlight/core": ["@speed-highlight/core@1.2.15", "", {}, "sha512-BMq1K3DsElxDWawkX6eLg9+CKJrTVGCBAWVuHXVUV2u0s2711qiChLSId6ikYPfxhdYocLNt3wWwSvDiTvFabw=="], + + "blake3-wasm": ["blake3-wasm@2.1.5", "", {}, "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g=="], + + "cookie": ["cookie@1.1.1", "", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="], + + "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], + + "error-stack-parser-es": ["error-stack-parser-es@1.0.5", "", {}, "sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA=="], + + "esbuild": ["esbuild@0.27.3", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.3", "@esbuild/android-arm": "0.27.3", "@esbuild/android-arm64": "0.27.3", "@esbuild/android-x64": "0.27.3", "@esbuild/darwin-arm64": "0.27.3", "@esbuild/darwin-x64": "0.27.3", "@esbuild/freebsd-arm64": "0.27.3", "@esbuild/freebsd-x64": "0.27.3", "@esbuild/linux-arm": "0.27.3", "@esbuild/linux-arm64": "0.27.3", "@esbuild/linux-ia32": "0.27.3", "@esbuild/linux-loong64": "0.27.3", "@esbuild/linux-mips64el": "0.27.3", "@esbuild/linux-ppc64": "0.27.3", "@esbuild/linux-riscv64": "0.27.3", "@esbuild/linux-s390x": "0.27.3", "@esbuild/linux-x64": "0.27.3", "@esbuild/netbsd-arm64": "0.27.3", "@esbuild/netbsd-x64": "0.27.3", "@esbuild/openbsd-arm64": "0.27.3", "@esbuild/openbsd-x64": "0.27.3", "@esbuild/openharmony-arm64": "0.27.3", "@esbuild/sunos-x64": "0.27.3", "@esbuild/win32-arm64": "0.27.3", "@esbuild/win32-ia32": "0.27.3", "@esbuild/win32-x64": "0.27.3" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg=="], + + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + + "kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="], + + "miniflare": ["miniflare@4.20260329.0", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "sharp": "^0.34.5", "undici": "7.24.4", "workerd": "1.20260329.1", "ws": "8.18.0", "youch": "4.1.0-beta.10" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-+G+1YFVeuEpw/gZZmUHQR7IfzJV+DDGvnSl0yXzhgvHh8Nbr8Go5uiWIwl17EyZ1Uors3FKUMDUyU6+ejeKZOw=="], + + "path-to-regexp": ["path-to-regexp@6.3.0", "", {}, "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ=="], + + "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + + "semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], + + "sharp": ["sharp@0.34.5", "", { "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", "semver": "^7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.5", "@img/sharp-darwin-x64": "0.34.5", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", "@img/sharp-libvips-linux-arm64": "1.2.4", "@img/sharp-libvips-linux-ppc64": "1.2.4", "@img/sharp-libvips-linux-riscv64": "1.2.4", "@img/sharp-libvips-linux-s390x": "1.2.4", "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", "@img/sharp-linux-arm": "0.34.5", "@img/sharp-linux-arm64": "0.34.5", "@img/sharp-linux-ppc64": "0.34.5", "@img/sharp-linux-riscv64": "0.34.5", "@img/sharp-linux-s390x": "0.34.5", "@img/sharp-linux-x64": "0.34.5", "@img/sharp-linuxmusl-arm64": "0.34.5", "@img/sharp-linuxmusl-x64": "0.34.5", "@img/sharp-wasm32": "0.34.5", "@img/sharp-win32-arm64": "0.34.5", "@img/sharp-win32-ia32": "0.34.5", "@img/sharp-win32-x64": "0.34.5" } }, "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg=="], + + "supports-color": ["supports-color@10.2.2", "", {}, "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g=="], + + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "undici": ["undici@7.24.4", "", {}, "sha512-BM/JzwwaRXxrLdElV2Uo6cTLEjhSb3WXboncJamZ15NgUURmvlXvxa6xkwIOILIjPNo9i8ku136ZvWV0Uly8+w=="], + + "unenv": ["unenv@2.0.0-rc.24", "", { "dependencies": { "pathe": "^2.0.3" } }, "sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw=="], + + "workerd": ["workerd@1.20260329.1", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20260329.1", "@cloudflare/workerd-darwin-arm64": "1.20260329.1", "@cloudflare/workerd-linux-64": "1.20260329.1", "@cloudflare/workerd-linux-arm64": "1.20260329.1", "@cloudflare/workerd-windows-64": "1.20260329.1" }, "bin": { "workerd": "bin/workerd" } }, "sha512-+ifMv3uBuD33ee7pan5n8+sgVxm2u5HnbgfXzHKwMNTKw86znqBJSnJoBqtP88+2T5U2Lu11xXUt+khPYioXwQ=="], + + "wrangler": ["wrangler@4.79.0", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.4.2", "@cloudflare/unenv-preset": "2.16.0", "blake3-wasm": "2.1.5", "esbuild": "0.27.3", "miniflare": "4.20260329.0", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.24", "workerd": "1.20260329.1" }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20260329.1" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-NMinIdB1pXIqdk+NLw4+RjzB7K5z4+lWMxhTxFTfZomwJu3Pm6N+kZ+a66D3nI7w0oCjsdv/umrZVmSHCBp2cg=="], + + "ws": ["ws@8.18.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw=="], + + "youch": ["youch@4.1.0-beta.10", "", { "dependencies": { "@poppinss/colors": "^4.1.5", "@poppinss/dumper": "^0.6.4", "@speed-highlight/core": "^1.2.7", "cookie": "^1.0.2", "youch-core": "^0.3.3" } }, "sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ=="], + + "youch-core": ["youch-core@0.3.3", "", { "dependencies": { "@poppinss/exception": "^1.2.2", "error-stack-parser-es": "^1.0.5" } }, "sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA=="], + } +} diff --git a/demo/pub/justfile b/demo/pub/justfile new file mode 100644 index 0000000000..ccf74cac0e --- /dev/null +++ b/demo/pub/justfile @@ -0,0 +1,251 @@ +set fallback + +# --- R2 bucket management (vid.moq.dev) --- + +# Initialize the bucket (this is mine; make your own) +init: + bun install + bun wrangler r2 bucket create video-moq-dev + +# Deploy the worker +deploy: + bun install + bun wrangler deploy + +# Upload a single file to R2. +# NOTE: Videos should be fragmented to minimize latency when streaming. +# Use ffmpeg to fragment before uploading: +# ffmpeg -i input.mp4 -c copy -f mp4 \ +# -movflags cmaf+separate_moof+delay_moov+skip_trailer+frag_every_frame \ +# output.mp4 +upload file: + bun install + bun wrangler r2 object put "video-moq-dev/{{ file }}" --file "media/{{ file }}" --remote + +# Sync all files in a local directory to R2 +sync dir="media": + #!/usr/bin/env bash + set -euo pipefail + for file in "{{ dir }}"/*; do + [ -e "$file" ] || continue + key=$(basename "$file") + echo "Uploading $key..." + bun wrangler r2 object put "video-moq-dev/$key" --file "$file" --remote + done + +# List files in the bucket +list: + bun install + bun wrangler r2 object list "video-moq-dev" + +# --- Publishing --- + +# Publish Big Buck Bunny to a relay server. +bbb url='http://localhost:4443/anon' *args: + just download bbb + just cmaf bbb "{{ url }}" {{ args }} + +# Publish Tears of Steel to a relay server. +tos url='http://localhost:4443/anon' *args: + just download tos + just cmaf tos "{{ url }}" {{ args }} + +# Publish a video using ffmpeg to a relay server. +cmaf name url='http://localhost:4443/anon' *args: + cargo build --bin moq-cli + just ffmpeg-cmaf "media/{{ name }}.mp4" |\ + cargo run --bin moq-cli -- \ + {{ args }} publish --url "{{ url }}" --name "{{ name }}.hang" fmp4 + +# Publish a video via iroh. +iroh name url prefix="": + just download "{{ name }}" + cargo build --bin moq-cli + just ffmpeg-cmaf "media/{{ name }}.mp4" |\ + cargo run --bin moq-cli -- \ + --iroh-enabled publish --url "{{ url }}" --name "{{ prefix }}{{ name }}.hang" fmp4 + +# Generate and ingest an HLS stream from a video file. +hls name relay="http://localhost:4443/anon": + #!/usr/bin/env bash + set -euo pipefail + + just download "{{ name }}" + + INPUT="media/{{ name }}.mp4" + OUT_DIR="media/{{ name }}" + + rm -rf "$OUT_DIR" + mkdir -p "$OUT_DIR" + + echo ">>> Generating HLS stream to disk (1280x720 + 256x144)..." + + ffmpeg -hide_banner -loglevel warning -re -stream_loop -1 -i "$INPUT" \ + -filter_complex "\ + [0:v]split=2[v0][v1]; \ + [v0]scale=-2:720[v720]; \ + [v1]scale=-2:144[v144]" \ + -map "[v720]" -map "[v144]" -map 0:a:0 \ + -r 25 -preset veryfast -g 50 -keyint_min 50 -sc_threshold 0 \ + -c:v:0 libx264 -profile:v:0 high -level:v:0 4.1 -pix_fmt:v:0 yuv420p -tag:v:0 avc1 \ + -b:v:0 4M -maxrate:v:0 4.4M -bufsize:v:0 8M \ + -c:v:1 libx264 -profile:v:1 high -level:v:1 4.1 -pix_fmt:v:1 yuv420p -tag:v:1 avc1 \ + -b:v:1 300k -maxrate:v:1 330k -bufsize:v:1 600k \ + -c:a aac -b:a 128k \ + -f hls -hls_time 2 -hls_list_size 6 \ + -hls_flags independent_segments+delete_segments \ + -hls_segment_type fmp4 \ + -master_pl_name master.m3u8 \ + -var_stream_map "v:0,agroup:audio,name:720 v:1,agroup:audio,name:144 a:0,agroup:audio,name:audio" \ + -hls_segment_filename "$OUT_DIR/v%v/segment_%09d.m4s" \ + "$OUT_DIR/v%v/stream.m3u8" & + + FFMPEG_PID=$! + + echo ">>> Waiting for HLS playlist generation..." + for i in {1..30}; do + if [ -f "$OUT_DIR/master.m3u8" ]; then break; fi + sleep 0.5 + done + + if [ ! -f "$OUT_DIR/master.m3u8" ]; then + kill $FFMPEG_PID 2>/dev/null || true + echo "Error: master.m3u8 not generated in time" + exit 1 + fi + + echo ">>> Waiting for variant playlists..." + sleep 2 + for i in {1..20}; do + if [ -f "$OUT_DIR/v0/stream.m3u8" ] || [ -f "$OUT_DIR/v720/stream.m3u8" ] || [ -f "$OUT_DIR/v144/stream.m3u8" ] || [ -f "$OUT_DIR/vaudio/stream.m3u8" ]; then + break + fi + sleep 0.5 + done + + CLEANUP_CALLED=false + cleanup() { + if [ "$CLEANUP_CALLED" = "true" ]; then return; fi + CLEANUP_CALLED=true + echo "Shutting down..." + kill $FFMPEG_PID 2>/dev/null || true + sleep 0.5 + kill -9 $FFMPEG_PID 2>/dev/null || true + } + trap cleanup SIGINT SIGTERM EXIT + + echo ">>> Running with --passthrough flag" + cargo run --bin moq-cli -- publish --url "{{ relay }}" --name "{{ name }}.hang" hls --playlist "$OUT_DIR/master.m3u8" --passthrough + EXIT_CODE=$? + + cleanup + exit $EXIT_CODE + +# Publish a video using H.264 Annex B format. +h264 name url="http://localhost:4443/anon" *args: + just download "{{ name }}" + cargo build --bin moq-cli + + ffmpeg -hide_banner -v quiet \ + -stream_loop -1 -re \ + -i "media/{{ name }}.mp4" \ + -c:v copy -an \ + -bsf:v h264_mp4toannexb \ + -f h264 \ + - | cargo run --bin moq-cli -- publish --url "{{ url }}" --name "{{ name }}.hang" avc3 {{ args }} + +# Publish a video using ffmpeg directly from moq to the localhost. +serve name *args: + just download "{{ name }}" + cargo build --bin moq-cli + just ffmpeg-cmaf "media/{{ name }}.mp4" |\ + cargo run --bin moq-cli -- \ + {{ args }} serve --listen "[::]:4443" --tls-generate "localhost" \ + --name "{{ name }}.hang" fmp4 + +# Generate and serve an HLS stream from a video for testing. +serve-hls name port="8000": + #!/usr/bin/env bash + set -euo pipefail + + just download "{{ name }}" + + INPUT="media/{{ name }}.mp4" + OUT_DIR="media/{{ name }}" + + rm -rf "$OUT_DIR" + mkdir -p "$OUT_DIR" + + echo ">>> Starting HLS stream generation..." + echo ">>> Master playlist: http://localhost:{{ port }}/master.m3u8" + + cleanup() { + echo "Shutting down..." + kill $(jobs -p) 2>/dev/null || true + exit 0 + } + trap cleanup SIGINT SIGTERM + + ffmpeg -loglevel warning -re -stream_loop -1 -i "$INPUT" \ + -map 0:v:0 -map 0:v:0 -map 0:a:0 \ + -r 25 -preset veryfast -g 50 -keyint_min 50 -sc_threshold 0 \ + -c:v:0 libx264 -profile:v:0 high -level:v:0 4.1 -pix_fmt:v:0 yuv420p -tag:v:0 avc1 -bsf:v:0 dump_extra -b:v:0 4M -vf:0 "scale=1920:-2" \ + -c:v:1 libx264 -profile:v:1 high -level:v:1 4.1 -pix_fmt:v:1 yuv420p -tag:v:1 avc1 -bsf:v:1 dump_extra -b:v:1 300k -vf:1 "scale=256:-2" \ + -c:a aac -b:a 128k \ + -f hls \ + -hls_time 2 -hls_list_size 12 \ + -hls_flags independent_segments+delete_segments \ + -hls_segment_type fmp4 \ + -master_pl_name master.m3u8 \ + -var_stream_map "v:0,agroup:audio v:1,agroup:audio a:0,agroup:audio" \ + -hls_segment_filename "$OUT_DIR/v%v/segment_%09d.m4s" \ + "$OUT_DIR/v%v/stream.m3u8" & + + sleep 2 + echo ">>> HTTP server: http://localhost:{{ port }}/" + cd "$OUT_DIR" && python3 -m http.server {{ port }} + +# Publish the clock broadcast. +clock action url="http://localhost:4443/anon" *args: + @if [ "{{ action }}" != "publish" ] && [ "{{ action }}" != "subscribe" ]; then \ + echo "Error: action must be 'publish' or 'subscribe', got '{{ action }}'" >&2; \ + exit 1; \ + fi + + cargo run -p moq-native --example clock -- --url "{{ url }}" --broadcast "clock" {{ args }} {{ action }} + +# Connect tokio-console to the publisher (port 6681). +console: + tokio-console http://127.0.0.1:6681 + +# --- GStreamer --- + +# Publish a video using GStreamer to a relay server. +gst name url='http://localhost:4443/anon' *args: + just download "{{ name }}" + cargo build -p moq-gst + + GST_PLUGIN_PATH_1_0="${PWD}/../../target/debug${GST_PLUGIN_PATH_1_0:+:$GST_PLUGIN_PATH_1_0}" \ + gst-launch-1.0 -v -e multifilesrc location="media/{{ name }}.mp4" loop=true ! parsebin name=parse \ + parse. ! queue ! identity sync=true ! mux.sink_0 \ + parse. ! queue ! identity sync=true ! mux.sink_1 \ + moqsink name=mux url="{{ url }}" broadcast="{{ name }}.hang" {{ args }} + +# --- Private helpers --- + +# Download a test video (already fragmented on vid.moq.dev). +[private] +download name: + @if [ ! -f "media/{{ name }}.mp4" ]; then \ + mkdir -p media; \ + curl -fsSL "https://vid.moq.dev/{{ name }}.mp4" -o "media/{{ name }}.mp4"; \ + fi + +# Convert an h264 input file to CMAF (fmp4) format to stdout. +[private] +ffmpeg-cmaf input output='-' *args: + ffmpeg -hide_banner -v quiet \ + -stream_loop -1 -re \ + -i "{{ input }}" \ + -c copy \ + -f mp4 -movflags cmaf+separate_moof+delay_moov+skip_trailer+frag_every_frame {{ args }} {{ output }} diff --git a/demo/pub/media/.gitignore b/demo/pub/media/.gitignore new file mode 100644 index 0000000000..d6b7ef32c8 --- /dev/null +++ b/demo/pub/media/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/demo/pub/package.json b/demo/pub/package.json new file mode 100644 index 0000000000..310bfa78bb --- /dev/null +++ b/demo/pub/package.json @@ -0,0 +1,11 @@ +{ + "name": "video-moq-dev", + "private": true, + "scripts": { + "deploy": "wrangler deploy" + }, + "devDependencies": { + "@cloudflare/workers-types": "^4", + "wrangler": "^4" + } +} diff --git a/demo/pub/tsconfig.json b/demo/pub/tsconfig.json new file mode 100644 index 0000000000..8a6de976fc --- /dev/null +++ b/demo/pub/tsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": true, + "types": ["@cloudflare/workers-types"] + } +} diff --git a/demo/pub/worker.ts b/demo/pub/worker.ts new file mode 100644 index 0000000000..1752e8a986 --- /dev/null +++ b/demo/pub/worker.ts @@ -0,0 +1,47 @@ +interface Env { + VIDEO: R2Bucket; +} + +const CONTENT_TYPES: Record = { + ".mp4": "video/mp4", + ".webm": "video/webm", + ".mkv": "video/x-matroska", + ".mov": "video/quicktime", + ".ts": "video/mp2t", +}; + +export default { + async fetch(request: Request, env: Env): Promise { + if (request.method !== "GET" && request.method !== "HEAD") { + return new Response("Method Not Allowed", { status: 405 }); + } + + const url = new URL(request.url); + const key = url.pathname.slice(1); // Remove leading slash + + if (!key) { + return new Response("Not Found", { status: 404 }); + } + + const object = await env.VIDEO.get(key); + if (!object) { + return new Response("Not Found", { status: 404 }); + } + + const dotIdx = key.lastIndexOf("."); + const ext = dotIdx >= 0 ? key.substring(dotIdx).toLowerCase() : ""; + const contentType = CONTENT_TYPES[ext] ?? "application/octet-stream"; + + const headers = { + "Content-Type": contentType, + "Cache-Control": "public, max-age=2592000", + "Content-Length": object.size.toString(), + }; + + if (request.method === "HEAD") { + return new Response(null, { headers }); + } + + return new Response(object.body, { headers }); + }, +}; diff --git a/demo/pub/wrangler.jsonc b/demo/pub/wrangler.jsonc new file mode 100644 index 0000000000..bc34bf3207 --- /dev/null +++ b/demo/pub/wrangler.jsonc @@ -0,0 +1,27 @@ +{ + // Cloudflare Wrangler configuration for the video hosting Worker + "$schema": "node_modules/wrangler/config-schema.json", + "name": "video-moq-dev", + "main": "worker.ts", + "compatibility_date": "2025-07-09", + "account_id": "dd618f5dbd5da77b8296f1613c301f5c", + "workers_dev": false, + "route": { + "pattern": "vid.moq.dev", + "custom_domain": true + }, + // R2 bucket bindings + "r2_buckets": [ + { + "binding": "VIDEO", + "bucket_name": "video-moq-dev", + "remote": true + } + ], + // Observability + "observability": { + "logs": { + "enabled": true + } + } +} diff --git a/demo/relay/.gitignore b/demo/relay/.gitignore new file mode 100644 index 0000000000..45d7060dc0 --- /dev/null +++ b/demo/relay/.gitignore @@ -0,0 +1,8 @@ +*.jwk +*.jwt +*.key +*.pem +*.crt +*.csr +*.cnf +*.srl diff --git a/demo/relay/justfile b/demo/relay/justfile new file mode 100644 index 0000000000..53a8783f43 --- /dev/null +++ b/demo/relay/justfile @@ -0,0 +1,93 @@ +set fallback + +# Run a localhost relay server without authentication. +default: + TOKIO_CONSOLE_BIND=127.0.0.1:6680 cargo run --bin moq-relay -- localhost.toml + +# Run a cluster of relay servers. +cluster: token + bun install + + bun run concurrently --kill-others --names root,leaf0,leaf1,bbb,tos,web --prefix-colors auto \ + "just root" \ + "just wait http://localhost:4443/certificate.sha256 && just leaf0" \ + "just wait http://localhost:4443/certificate.sha256 && just leaf1" \ + "just wait http://localhost:4444/certificate.sha256 && just pub bbb http://localhost:4444/demo?jwt=$(cat demo-cli.jwt)" \ + "just wait http://localhost:4443/certificate.sha256 && just pub tos http://localhost:4443/demo?jwt=$(cat demo-cli.jwt)" \ + "just wait http://localhost:4445/certificate.sha256 && VITE_RELAY_URL=http://localhost:4445/demo?jwt=$(cat demo-web.jwt) bun --cwd ../web --bun vite --open" + +# Run a localhost root server, accepting connections from leaf nodes. +root: (cert "root") + cargo run --bin moq-relay -- root.toml + +# Run a localhost leaf, connecting to the root server. +leaf0: (cert "leaf0") + cargo run --bin moq-relay -- leaf0.toml + +# Run a second localhost leaf, connecting to the root server. +leaf1: (cert "leaf1") + cargo run --bin moq-relay -- leaf1.toml + +# Generate a self-signed CA +ca: + #!/usr/bin/env bash + set -euo pipefail + umask 077 + + [ -f ca.pem ] && [ -f ca.key ] && exit 0 + rm -f ca.pem ca.key + printf '[req]\ndistinguished_name = req_dn\n[req_dn]\n' > ca.cnf + export OPENSSL_CONF="ca.cnf" + openssl req -x509 -sha256 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -nodes \ + -days 365 -subj "/CN=moq cluster CA" \ + -keyout ca.key -out ca.pem + +# Generate a self-signed certificate using the root CA. + +# Chrome requires a <=14 day validity for self-signed certs. +cert name: ca + #!/usr/bin/env bash + set -euo pipefail + umask 077 + + export OPENSSL_CONF="ca.cnf" + openssl req -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -nodes \ + -subj "/CN={{ name }}" \ + -keyout "{{ name }}.key" -out "{{ name }}.csr" + openssl x509 -req -sha256 -in "{{ name }}.csr" \ + -CA ca.pem -CAkey ca.key -CAcreateserial \ + -days 14 -extfile <(printf "subjectAltName=DNS:localhost\n") \ + -out "{{ name }}.crt" + rm "{{ name }}.csr" + +# Generate a random secret key for authentication. +key: + #!/usr/bin/env bash + set -euo pipefail + umask 077 + + [ -f root.jwk ] && exit 0 + rm -f *.jwt + cargo run --bin moq-token-cli -- generate --out root.jwk + +# Generate authentication tokens for local development. +token: key + #!/usr/bin/env bash + set -euo pipefail + umask 077 + + if [ ! -f demo-web.jwt ]; then + cargo run --quiet --bin moq-token-cli -- sign --key root.jwk \ + --root demo --subscribe "" --publish me \ + > demo-web.jwt + fi + + if [ ! -f demo-cli.jwt ]; then + cargo run --quiet --bin moq-token-cli -- sign --key root.jwk \ + --root demo --publish "" \ + > demo-cli.jwt + fi + +# Connect tokio-console to the relay server (port 6680). +console: + tokio-console http://127.0.0.1:6680 diff --git a/demo/relay/leaf0.toml b/demo/relay/leaf0.toml new file mode 100644 index 0000000000..809dd4dfa3 --- /dev/null +++ b/demo/relay/leaf0.toml @@ -0,0 +1,54 @@ +[log] +# Enable debug logging for development. +# The RUST_LOG environment variable will take precedence. +level = "debug" + +[server] +# Listen for QUIC connections on UDP:4444 +# Sometimes IPv6 causes issues; try 127.0.0.1:4444 instead. +listen = "[::]:4444" + +# Serve the same cluster-signed certificate that we present as a client, +# so other leaves can verify us against `ca.pem`. +tls.cert = ["leaf0.crt"] +tls.key = ["leaf0.key"] + +# Trust client certificates signed by this CA for mTLS peer auth, so +# other leaves dialing in as cluster peers can authenticate without a +# JWT. Without this, inbound leaf-to-leaf connections fall through to +# the JWT path and are rejected. +tls.root = ["ca.pem"] + +[client] +# Present this certificate and key on outbound cluster connections. +# The root maps a valid cert to full access. +tls.cert = "leaf0.crt" +tls.key = "leaf0.key" + +# Verify the remote's server cert against the cluster CA. All cluster +# nodes' server certs are signed by `ca.pem`, so no custom trust +# store is required beyond this one file. +tls.root = ["ca.pem"] + +[web.http] +# Listen for HTTP and WebSocket (TCP) connections on the given address. +listen = "[::]:4444" + +[cluster] +# Connect only to the root. leaf1 will dial us directly, forming a loop +# (leaf1 -> root, leaf1 -> leaf0, leaf0 -> root) to exercise cluster loop detection. +connect = ["localhost:4443"] + +[auth] +# Allow JWT tokens that are signed by this root key. +# `just key` will populate this file. +key = "root.jwk" + +[auth.public] +# Allow anonymous clients to subscribe and publish to the prefixes below. +subscribe = ["anon", "demo"] +publish = ["anon", "demo/viewer"] + +[stats] +enabled = true +node = "local/leaf0" diff --git a/demo/relay/leaf1.toml b/demo/relay/leaf1.toml new file mode 100644 index 0000000000..07639fc7a9 --- /dev/null +++ b/demo/relay/leaf1.toml @@ -0,0 +1,54 @@ +[log] +# Enable debug logging for development. +# The RUST_LOG environment variable will take precedence. +level = "debug" + +[server] +# Listen for QUIC connections on UDP:4445 +# Sometimes IPv6 causes issues; try 127.0.0.1:4445 instead. +listen = "[::]:4445" + +# Serve the same cluster-signed certificate that we present as a client, +# so other leaves can verify us against `ca.pem`. +tls.cert = ["leaf1.crt"] +tls.key = ["leaf1.key"] + +# Trust client certificates signed by this CA for mTLS peer auth, so +# other leaves dialing in as cluster peers can authenticate without a +# JWT. Without this, inbound leaf-to-leaf connections fall through to +# the JWT path and are rejected. +tls.root = ["ca.pem"] + +[client] +# Present this certificate and key on outbound cluster connections. +# The root maps a valid cert to full access. +tls.cert = "leaf1.crt" +tls.key = "leaf1.key" + +# Verify the remote's server cert against the cluster CA. All cluster +# nodes' server certs are signed by `ca.pem`, so no custom trust +# store is required beyond this one file. +tls.root = ["ca.pem"] + +[web.http] +# Listen for HTTP and WebSocket (TCP) connections on the given address. +listen = "[::]:4445" + +[cluster] +# Connect to both the root and leaf0, forming a loop to exercise cluster loop detection. +# ex. imagine us-east connects to us-central AND directly to us-west. +connect = ["localhost:4443", "localhost:4444"] + +[auth] +# Allow JWT tokens that are signed by this root key. +# `just key` will populate this file. +key = "root.jwk" + +[auth.public] +# Allow anonymous clients to subscribe and publish to the prefixes below. +subscribe = ["anon", "demo"] +publish = ["anon", "demo/viewer"] + +[stats] +enabled = true +node = "local/leaf1" diff --git a/demo/relay/localhost.toml b/demo/relay/localhost.toml new file mode 100644 index 0000000000..be6b25a4ca --- /dev/null +++ b/demo/relay/localhost.toml @@ -0,0 +1,54 @@ +# A simple configuration for a local relay server. +# This is used for local development and has authentication disabled. + +[log] +# Enable debug logging for development. +# The RUST_LOG environment variable will take precedence. +level = "debug" + +[server] +# Listen for QUIC connections on UDP:4443 +# Sometimes IPv6 causes issues; try 127.0.0.1:4443 instead. +listen = "[::]:4443" + +# Generate a self-signed certificate for the given hostnames. +# This is used for local development, in conjunction with a fingerprint, or with TLS verification disabled. +tls.generate = ["localhost"] + +[web.http] +# Listen for HTTP and WebSocket connections on the given TCP address. +# This is unfortunately required to serve certificate.sha256 for local development. +# However, as a bonus, we can serve tracks via both HTTP and WebSocket fallbacks. +listen = "[::]:4443" + +# See root.toml and leaf.toml for auth and clustering examples. +[auth] +# Allow anonymous access to everything. +public = "" + +# Publish a single per-node stats broadcast on the cluster origin: +# +# .stats/node/local/host +# +# carrying four JSON tracks (publisher.json, subscriber.json, +# internal/publisher.json, internal/subscriber.json) of {path: counters} +# for every broadcast that has changed within the last `retention` +# intervals. See doc/bin/relay/config.md for the field semantics. +[stats] +enabled = true + +# `node` is the suffix that disambiguates per-relay broadcasts in a cluster. +# It can be multi-segment (e.g. `sjc/1`, `sjc/2`) to nest multiple hosts under +# a shared region key. Single-node setups can leave it unset. +node = "local/host" + +[iroh] +# You can optionally enable iroh support for P2P connections. +# Clients can connect using --iroh-enabled and a `iroh://` URL. +enabled = false + +# Path to persist the iroh secret key. +# If the file does not exist, a random key will be generated and written to the path. +# This gives the relay a persistent iroh endpoint id. The secret key can alternatively be set +# via MOQ_IROH_SECRET environment variable. +secret = "./iroh-secret.key" diff --git a/demo/relay/prod.toml b/demo/relay/prod.toml new file mode 100644 index 0000000000..4726b28ff5 --- /dev/null +++ b/demo/relay/prod.toml @@ -0,0 +1,44 @@ +# An example of a production configuration. +# Here's a real one: https://github.com/moq-dev/moq.dev/blob/b4da7dd8f09879cefb593d5e35f99f064caa3943/infra/relay.yml.tpl#L56 + +[server] +# Listen for QUIC connections on UDP:443 +# This is the default port for WebTransport +listen = "[::]:443" + +[server.tls] +# You'll need to provide a real certificate and key in production. +# You can get this via a service like Let's Encrypt. +cert = "cert.pem" +key = "key.pem" + +#[web.http] +# Optionally listen for HTTP and WebSocket connections on port 80. +# listen = "[::]:80" + +[web.https] +# Optionally listen for TCP/HTTPS/WSS connections on port 443. +listen = "[::]:443" + +# You'll need to provide a real certificate and key in production. +# This can be the exact same certificate and key as the QUIC endpoint. +cert = "cert.pem" +key = "key.pem" + +# See docs/auth.md for more information. +[auth] +# A single JWK key file for authentication. No kid required in JWTs. +key = "root.jwk" + +# Allow anonymous subscribing for anon/** and demo/** +# Allow anonymous publishing for anon/** only +[auth.public] +subscribe = ["anon", "demo"] +publish = ["anon", "demo/viewer"] + +# For multiple keys with rotation, use a directory instead: +# key_dir = "/path/to/keys/" +# Keys are named {kid}.jwk and resolved by the kid in the JWT header. + +# Or use a URL for remote key management: +# key_dir = "https://api.example.com/keys" diff --git a/demo/relay/root.toml b/demo/relay/root.toml new file mode 100644 index 0000000000..187fe0102b --- /dev/null +++ b/demo/relay/root.toml @@ -0,0 +1,35 @@ +[log] +# Enable debug logging for development. +# The RUST_LOG environment variable will take precedence. +level = "debug" + +[server] +# Listen for QUIC connections on UDP:4443 +# Sometimes IPv6 causes issues; try 127.0.0.1:4443 instead. +listen = "[::]:4443" + +# Server certificate and key signed by the cluster CA so leaves can +# verify via `tls.root`. `just cert root` generates these files. +# For a standalone dev setup, use `tls.generate = ["localhost"]` instead. +tls.cert = ["root.crt"] +tls.key = ["root.key"] + +# Trust client certificates signed by this CA for mTLS peer auth. +# Any connection presenting such a cert is granted full access (publish/ +# subscribe/cluster), which is how leaves join without a `cluster.token` +# JWT. `just ca` generates the CA. +tls.root = ["ca.pem"] + +[web.http] +# Listen for HTTP and WebSocket (TCP) connections on the given address. +# Defaults to disabled if not provided. +listen = "[::]:4443" + +[auth] +# Allow JWT tokens that are signed by this root key. +key = "root.jwk" + +[auth.public] +# Allow anonymous clients to subscribe and publish to the prefixes below. +subscribe = ["anon", "demo"] +publish = ["anon", "demo/viewer"] diff --git a/demo/sub/justfile b/demo/sub/justfile new file mode 100644 index 0000000000..411e09ad4a --- /dev/null +++ b/demo/sub/justfile @@ -0,0 +1,9 @@ +set fallback + +# Subscribe to a broadcast using GStreamer and render to the screen. +gst name url='http://localhost:4443/anon' *args: + cargo build -p moq-gst + + GST_PLUGIN_PATH_1_0="${PWD}/../../target/debug${GST_PLUGIN_PATH_1_0:+:$GST_PLUGIN_PATH_1_0}" \ + gst-launch-1.0 -v -e moqsrc url="{{ url }}" broadcast="{{ name }}" {{ args }} \ + ! decodebin3 ! videoconvert ! autovideosink diff --git a/demo/throttle/enable b/demo/throttle/enable new file mode 100755 index 0000000000..aa62d703b8 --- /dev/null +++ b/demo/throttle/enable @@ -0,0 +1,104 @@ +#!/bin/bash +# +# Network throttle for local development (macOS) +# Simulates a constrained network for QUIC testing. +# Runs until Ctrl+C, then restores original settings. + +set -e + +# Hard-coded profile: 2Mbps, 50ms delay, 100 packet queue +BANDWIDTH="2Mbit" +DELAY="50ms" +QUEUE="100" + +PIPE_NUM=1 +PF_ANCHOR="moq-throttle" +PF_CONF="/etc/pf.conf" +PF_BACKUP="/tmp/pf.conf.backup" + +# State tracking +PF_WAS_ENABLED="" +CLEANUP_DONE="" + +capture_pf_state() { + if sudo pfctl -s info 2>/dev/null | grep -q "Status: Enabled"; then + PF_WAS_ENABLED="yes" + else + PF_WAS_ENABLED="no" + fi +} + +cleanup() { + local exit_code=$? + + # Guard against running cleanup multiple times + [ -n "$CLEANUP_DONE" ] && return + CLEANUP_DONE="yes" + + echo "" + echo "Stopping network throttle..." + + # Flush anchor rules + sudo pfctl -a "$PF_ANCHOR" -F all 2>/dev/null || true + + # Delete dummynet pipe + sudo dnctl pipe $PIPE_NUM delete 2>/dev/null || true + + # Restore original PF config + if [ -f "$PF_BACKUP" ]; then + sudo cp "$PF_BACKUP" "$PF_CONF" + sudo pfctl -f "$PF_CONF" 2>/dev/null || true + sudo rm "$PF_BACKUP" + fi + + # Restore PF enabled/disabled state (only disable if we enabled it) + if [ "$PF_WAS_ENABLED" = "no" ]; then + sudo pfctl -d 2>/dev/null || true + fi + + echo "Throttling disabled." + exit "$exit_code" +} + +# Register cleanup for all exit paths +trap cleanup EXIT + +echo "Starting network throttle..." +echo " Bandwidth: $BANDWIDTH" +echo " Delay: $DELAY" +echo " Queue: $QUEUE packets" + +# Capture PF state before any changes +capture_pf_state + +# Back up pf.conf +sudo cp "$PF_CONF" "$PF_BACKUP" + +# Modify pf.conf: remove lo0 skip and add our anchor point +{ + grep -v "set skip on lo0" "$PF_BACKUP" + echo "dummynet-anchor \"$PF_ANCHOR\"" + echo "anchor \"$PF_ANCHOR\"" +} | sudo tee "$PF_CONF" >/dev/null + +# Configure dummynet pipe +sudo dnctl pipe $PIPE_NUM config bw "$BANDWIDTH" delay "$DELAY" queue "$QUEUE" + +# Load modified pf config +sudo pfctl -f "$PF_CONF" 2>/dev/null + +# Enable PF if it wasn't already enabled +if [ "$PF_WAS_ENABLED" = "no" ]; then + sudo pfctl -E 2>/dev/null || true +fi + +# Add throttling rules for outbound UDP only +echo "dummynet out proto udp all pipe $PIPE_NUM" | sudo pfctl -a "$PF_ANCHOR" -f - + +echo "Throttling enabled. Press Ctrl+C to stop." +echo "" + +# Wait forever until interrupted +while true; do + sleep 1 +done diff --git a/demo/web/.env b/demo/web/.env new file mode 100644 index 0000000000..a416e700f5 --- /dev/null +++ b/demo/web/.env @@ -0,0 +1 @@ +VITE_RELAY_URL=http://localhost:4443/anon diff --git a/demo/web/README.md b/demo/web/README.md new file mode 100644 index 0000000000..7ce9e1ac8e --- /dev/null +++ b/demo/web/README.md @@ -0,0 +1,23 @@ +

+ Media over QUIC +

+ +Media over QUIC (MoQ) is a live (media) delivery protocol utilizing QUIC. +It utilizes new browser technologies such as [WebTransport](https://developer.mozilla.org/en-US/docs/Web/API/WebTransport_API) and [WebCodecs](https://developer.mozilla.org/en-US/docs/Web/API/WebCodecs_API) to provide WebRTC-like functionality. +Despite the focus on media, the transport is generic and designed to scale to enormous viewership via clustered relay servers (aka a CDN). +See [moq.dev](https://moq.dev) for more information. + +**Note:** this project is a [fork](https://moq.dev/blog/transfork) of the [IETF specification](https://datatracker.ietf.org/group/moq/documents/). +The principles are the same but the implementation is exponentially simpler given a narrower focus (and no politics). + +# Usage + +These are demos, duh. +We're using Vite but other bundlers should work too. + +# License + +Licensed under either: + +- Apache License, Version 2.0, ([LICENSE-APACHE](../../LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) +- MIT license ([LICENSE-MIT](../../LICENSE-MIT) or http://opensource.org/licenses/MIT) diff --git a/demo/web/justfile b/demo/web/justfile new file mode 100644 index 0000000000..9f279a42a8 --- /dev/null +++ b/demo/web/justfile @@ -0,0 +1,9 @@ +set shell := ["bash", "-euo", "pipefail", "-c"] + +# Run the web server targeting the default relay. +default: + just serve + +# Run the web server targeting the specified relay. +serve url='http://localhost:4443/anon': + VITE_RELAY_URL="{{ url }}" bun --bun vite --open diff --git a/demo/web/package.json b/demo/web/package.json new file mode 100644 index 0000000000..0373bb5a54 --- /dev/null +++ b/demo/web/package.json @@ -0,0 +1,32 @@ +{ + "name": "@moq/demo", + "private": true, + "type": "module", + "version": "0.1.1", + "description": "Media over QUIC - Demo", + "license": "(MIT OR Apache-2.0)", + "repository": "github:moq-dev/moq", + "scripts": { + "dev": "vite --open", + "build": "vite build", + "check": "tsc --noEmit" + }, + "dependencies": { + "@moq/hang": "workspace:^", + "@moq/watch": "workspace:^", + "@moq/publish": "workspace:^" + }, + "//devDependencies": "These are only needed for local development with workspace packages. They are NOT needed when using the published npm packages.", + "devDependencies": { + "@tailwindcss/typography": "^0.5.16", + "@tailwindcss/vite": "^4.1.13", + "esbuild": "^0.27.0", + "highlight.js": "^11.11.1", + "solid-element": "^1.9.1", + "solid-js": "^1.9.10", + "tailwindcss": "^4.1.13", + "typescript": "^6.0.0", + "vite": "^7.3.1", + "vite-plugin-solid": "^2.11.10" + } +} diff --git a/demo/web/src/discover.ts b/demo/web/src/discover.ts new file mode 100644 index 0000000000..0c2b8f50f0 --- /dev/null +++ b/demo/web/src/discover.ts @@ -0,0 +1,90 @@ +import { Moq, Signals } from "@moq/hang"; +import type MoqWatch from "@moq/watch/element"; + +/** + * Wraps a element and live discovers new broadcasts available at the given URL. + * Displays clickable broadcast names above the player. + */ +export default class MoqDiscover extends HTMLElement { + #suggestions: HTMLDivElement; + #signals = new Signals.Effect(); + + constructor() { + super(); + + // Create suggestions container + this.#suggestions = document.createElement("div"); + this.#suggestions.style.cssText = "margin-bottom: 0.5rem; font-size: 0.85rem;"; + } + + async connectedCallback() { + this.style.cssText = "display: block; margin: 1rem 0;"; + + // Discover the inner moq-watch element. + await customElements.whenDefined("moq-watch"); + const watch = this.querySelector("moq-watch") as MoqWatch | null; + if (!watch) return; + + // Insert the suggestions above the existing children. + this.prepend(this.#suggestions); + + // Reactively render suggestions when broadcasts or selected name changes. + this.#signals.run((effect) => { + const broadcasts = effect.get(watch.connection.announced); + const selected = effect.get(watch.broadcast.name).toString(); + + this.#clearSuggestions(); + + if (broadcasts.size === 0) return; + + const label = document.createElement("span"); + label.textContent = "Available: "; + label.style.color = "#666"; + this.#suggestions.appendChild(label); + + for (const name of broadcasts) { + const isSelected = name === selected; + const tag = document.createElement("button"); + tag.type = "button"; + tag.textContent = name; + + const defaultBg = isSelected ? "#2d4a2d" : "#1a2e1a"; + const defaultBorder = isSelected ? "#4ade80" : "#2d4a2d"; + + tag.style.cssText = ` + background: ${defaultBg}; color: #4ade80; border: 1px solid ${defaultBorder}; + padding: 0.2rem 0.5rem; margin: 0 0.25rem; border-radius: 4px; + font-size: 0.8rem; font-family: monospace; cursor: pointer; + font-weight: ${isSelected ? "bold" : "normal"}; + transition: background 0.15s, border-color 0.15s; + `; + if (!isSelected) { + tag.addEventListener("mouseenter", () => { + tag.style.background = "#2d4a2d"; + tag.style.borderColor = "#4ade80"; + }); + tag.addEventListener("mouseleave", () => { + tag.style.background = defaultBg; + tag.style.borderColor = defaultBorder; + }); + } + tag.addEventListener("click", () => { + watch.broadcast.name.set(Moq.Path.from(name)); + }); + this.#suggestions.appendChild(tag); + } + }); + } + + disconnectedCallback() { + this.#signals.close(); + } + + #clearSuggestions() { + while (this.#suggestions.firstChild) { + this.#suggestions.removeChild(this.#suggestions.firstChild); + } + } +} + +customElements.define("moq-discover", MoqDiscover); diff --git a/js/hang-demo/src/favicon.svg b/demo/web/src/favicon.svg similarity index 100% rename from js/hang-demo/src/favicon.svg rename to demo/web/src/favicon.svg diff --git a/js/hang-demo/src/highlight.ts b/demo/web/src/highlight.ts similarity index 100% rename from js/hang-demo/src/highlight.ts rename to demo/web/src/highlight.ts diff --git a/js/hang-demo/src/index.css b/demo/web/src/index.css similarity index 100% rename from js/hang-demo/src/index.css rename to demo/web/src/index.css diff --git a/demo/web/src/index.html b/demo/web/src/index.html new file mode 100644 index 0000000000..2c5c876366 --- /dev/null +++ b/demo/web/src/index.html @@ -0,0 +1,167 @@ + + + + + + + MoQ Demo + + + + + + + + + + + + + + + + + + + + + + + +

Other demos:

+ + +

Tips:

+

+ You can find the source code for this demo in dev/web/src/index.html. + Yes I know it's confusing when a command automatically opens a browser window. +

+

+ This demo uses + http so it's extra not secure. + It works by insecurely fetching the certificate hash and telling WebTransport to trust it. + If you're going to run this code in production, you'll need a valid certificate (ex. LetsEncrypt) and use + https. +

+
+

+ You can instanciate the player via the provided <moq-watch> Web Component. + Either modify HTML attributes like <moq-watch paused> or use the + Javascript API. + The Javascript API is still evolving, so I recommend the Web Component for now. +

+

+ You can provide your own canvas element and use CSS to modify it. + Unfortunately, you can't use the HTML width/height attributes because of how OffscreenCanvas + works. + For example: +

<moq-watch url="http://localhost:4443/" name="bbb.hang">
+	<!-- Optionally provide a custom canvas element that we can style as needed -->
+	<canvas style="max-width: 100%; height: auto; border-radius: 4px;"></canvas>
+</moq-watch>
+

+

+ Don't want video? Don't provide a canvas! + It won't be downloaded, decoded, or rendered. + This includes when the video is paused, minimized, not in the DOM, or scrolled out of view. + wowee the bandwidth savings! +

+

+ Audio may start muted because the browser can require user interaction before autoplaying. + You can unmute it by removing the muted property or calling watch.audio.muted.set(false) via the Javascript API. + And of course, nothing is downloaded while it's muted. +

+
+

+ The Javascript API is far more powerful and you can access properties directly: + +

const watch = document.getElementById("watch");
+watch.audio.muted.set(true);
+
+

+ +

+ All of the properties are reactive using a hand-rolled signals library: `@moq/signals`. + You could use it... or you can use the provided `react` and `solid` helpers: + +


+import { Watch } from "@moq/hang";
+import solid from "@moq/signals/solid";
+
+function Volume(hang: Watch) {
+	// Switch to `react` if you're using React, duh.
+	const volume = solid(hang.volume);
+
+	// Return a div that displays the volume.
+	return <div>
+		Volume: {volume()}
+	</div>
+}
+		
+

+

+ Using something more niche? There's also a subscribe() method to + trigger a callback on change. + +


+const cleanup = hang.volume.subscribe((volume) => {
+	document.getElementById("volume-value").textContent = `${volume * 100}%`;
+});
+
+// Cleanup the subscription when no longer needed.
+cleanup();
+		
+

+
+

+ The connection and broadcast are automatically reloaded. + Try running multiple terminals and kill the broadcast to see what happens. + +

# Run the relay and web server in another terminal or the background.
+just relay &
+just web &
+
+just pub bbb
+# Kill it with ctrl+C
+
+# Republish the same broadcast, the player will reconnect.
+just pub bbb
+		
+

+

+ If the Big Bunny is making you sick, you can use other inferior test videos or the publish demo. + For example, + Try running just pub tos in a new terminal and then watch robots bang. + This command uses ffmpeg to produce a fragmented MP4 file piped over stdout and then sent over the network. + Yeah it's pretty gross. +

+

+ If you want to do things more efficiently, you can use the + GStreamer plugin. + It's pretty crude and doesn't handle all pipeline events; contributions welcome! +

+ + + + + diff --git a/demo/web/src/index.ts b/demo/web/src/index.ts new file mode 100644 index 0000000000..a90f3eabfc --- /dev/null +++ b/demo/web/src/index.ts @@ -0,0 +1,18 @@ +import "./highlight"; +import "@moq/watch/ui"; +import MoqWatch from "@moq/watch/element"; +import MoqWatchSupport from "@moq/watch/support/element"; +import MoqDiscover from "./discover"; + +export { MoqDiscover, MoqWatch, MoqWatchSupport }; + +const watch = document.querySelector("moq-watch") as MoqWatch | undefined; +if (!watch) throw new Error("unable to find element"); + +// If query params are provided, use them. +const urlParams = new URLSearchParams(window.location.search); +const name = urlParams.get("broadcast") ?? urlParams.get("name"); +const url = urlParams.get("url"); + +if (url) watch.url = url; +if (name) watch.name = name; diff --git a/demo/web/src/manual.html b/demo/web/src/manual.html new file mode 100644 index 0000000000..fa29995637 --- /dev/null +++ b/demo/web/src/manual.html @@ -0,0 +1,65 @@ + + + + + + + MoQ Demo (Manual Catalog) + + + + + + + + + + + + + + + +
+

Catalog JSON

+

+ Paste a Catalog.Root blob and click Apply. + The element won't fetch a catalog track in manual mode — media tracks are + subscribed off whatever you provide here. +

+

+ To grab a real one, open the WebCodecs demo, + let it play, then run JSON.stringify(document.getElementById("watch").catalog) + in the dev console and paste the result here. +

+ + + +
+ + +
+
+ +

Other demos:

+ + + + + + diff --git a/demo/web/src/manual.ts b/demo/web/src/manual.ts new file mode 100644 index 0000000000..1d2624d96b --- /dev/null +++ b/demo/web/src/manual.ts @@ -0,0 +1,51 @@ +import "./highlight"; +import "@moq/watch/ui"; +import * as Catalog from "@moq/hang/catalog"; +import MoqWatch from "@moq/watch/element"; +import MoqWatchSupport from "@moq/watch/support/element"; + +export { MoqWatch, MoqWatchSupport }; + +const watch = document.querySelector("moq-watch") as MoqWatch | null; +if (!watch) throw new Error("missing element"); + +const input = document.getElementById("catalog-input") as HTMLTextAreaElement; +const apply = document.getElementById("apply") as HTMLButtonElement; +const status = document.getElementById("status") as HTMLSpanElement; + +const urlParams = new URLSearchParams(window.location.search); +const name = urlParams.get("broadcast") ?? urlParams.get("name"); +const url = urlParams.get("url"); +if (url) watch.url = url; +if (name) watch.name = name; + +function setStatus(msg: string, ok = true) { + status.textContent = msg; + status.style.color = ok ? "" : "tomato"; +} + +apply.addEventListener("click", () => { + const text = input.value.trim(); + if (!text) { + watch.catalog = undefined; + setStatus("cleared"); + return; + } + let parsed: unknown; + try { + parsed = JSON.parse(text); + } catch (err) { + setStatus(`parse error: ${(err as Error).message}`, false); + return; + } + + const result = Catalog.RootSchema.safeParse(parsed); + if (!result.success) { + setStatus(`invalid catalog: ${result.error.message}`, false); + return; + } + + watch.catalogFormat = "manual"; + watch.catalog = result.data; + setStatus("applied"); +}); diff --git a/demo/web/src/mse.html b/demo/web/src/mse.html new file mode 100644 index 0000000000..ed723fb1c0 --- /dev/null +++ b/demo/web/src/mse.html @@ -0,0 +1,54 @@ + + + + + + + MoQ Demo (MSE) + + + + + + + + + + + + + + + + + +

Other demos:

+ + +

Tips:

+

+ This demo uses MSE (Media + Source Extensions) + via a <video> element instead of WebCodecs via <canvas>. + MSE has broader device support but higher latency. +

+

+ To use MSE, provide a <video> element instead of a <canvas> element: +

<moq-watch url="https://cdn.moq.dev/anon" name="bbb.hang">
+	<video style="max-width: 100%; height: auto;" autoplay muted></video>
+</moq-watch>
+

+ + + + + diff --git a/demo/web/src/publish.html b/demo/web/src/publish.html new file mode 100644 index 0000000000..610940cf1e --- /dev/null +++ b/demo/web/src/publish.html @@ -0,0 +1,91 @@ + + + + + + + MoQ Demo + + + + + + + + + + + + + + + + +

Other demos:

+ + +

Tips:

+

+ This page creates a broadcast called `me.hang` by default. + You can use query parameters to use a different broadcast name and create + multiple broadcasts. +

+

+ Reusing the same broadcast path means viewers will automatically reconnect to the new session. + Try reloading the page and broadcasting again; viewers will automatically reconnect. +

+
+

+ Media only flows over the network when requested! + Connecting to a relay means the broadcast is advertised as available, but nothing is transferred until there's + at least one viewer per track. + If there's multiple viewers, the relay will fan out the media to all of them. +

+

+ You can create a broadcaster via the provided <moq-publish> Web Component. + Either modify HTML attributes like <moq-publish source="camera" audio /> + or access the element's Javascript API: +

const publish = document.getElementById("publish");
+publish.broadcast.audio.enabled.set(true);
+ + And of course you can use the Javascript API directly instead of the Web Component. + It's a bit more complicated and subject to change, but it gives you more control. +

+
+

+ You're not limited to web publishing either. + Try running just pub tos in a new terminal and then watch robots bang. + This uses ffmpeg to produce a fragmented MP4 file piped over stdout then sent over the network. + Yeah it's pretty gross. +

+

+ If you want to do things more efficiently, you can use the + GStreamer plugin. + It's pretty crude and doesn't handle all pipeline events; contributions welcome! +

+
+

+ This demo uses `http://` so it's not secure. + It works by fetching the certificate hash (via HTTP) and providing that to WebTransport, which requires HTTPS. + To run this in production, you'll need a valid certificate (ex. letsencrypt) and to use `https://`. +

+ + + + + diff --git a/demo/web/src/publish.ts b/demo/web/src/publish.ts new file mode 100644 index 0000000000..68622af530 --- /dev/null +++ b/demo/web/src/publish.ts @@ -0,0 +1,20 @@ +import "./highlight"; +import "@moq/publish/ui"; + +// We need to import Web Components with fully-qualified paths because of tree-shaking. +import MoqPublish from "@moq/publish/element"; +import MoqPublishSupport from "@moq/publish/support/element"; + +export { MoqPublish, MoqPublishSupport }; + +const publish = document.querySelector("moq-publish") as MoqPublish; +const watch = document.getElementById("watch") as HTMLAnchorElement; +const watchName = document.getElementById("watch-name") as HTMLSpanElement; + +const urlParams = new URLSearchParams(window.location.search); +const name = urlParams.get("broadcast") ?? urlParams.get("name"); +if (name) { + publish.setAttribute("name", name); + watch.href = `index.html?broadcast=${name}`; + watchName.textContent = name; +} diff --git a/js/hang-demo/src/vite-env.d.ts b/demo/web/src/vite-env.d.ts similarity index 100% rename from js/hang-demo/src/vite-env.d.ts rename to demo/web/src/vite-env.d.ts diff --git a/js/hang-demo/tailwind.config.js b/demo/web/tailwind.config.js similarity index 100% rename from js/hang-demo/tailwind.config.js rename to demo/web/tailwind.config.js diff --git a/demo/web/tsconfig.json b/demo/web/tsconfig.json new file mode 100644 index 0000000000..a8f92e3998 --- /dev/null +++ b/demo/web/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../js/tsconfig.json", + "compilerOptions": { + "module": "esnext", + "moduleResolution": "bundler", + "jsx": "preserve", + "jsxImportSource": "solid-js", + "outDir": "dist" + }, + "include": ["src", "../../js/common/worklet.d.ts"] +} diff --git a/demo/web/vite.config.ts b/demo/web/vite.config.ts new file mode 100644 index 0000000000..5cd3ce3572 --- /dev/null +++ b/demo/web/vite.config.ts @@ -0,0 +1,31 @@ +import tailwindcss from "@tailwindcss/vite"; +import { resolve } from "path"; +import { defineConfig } from "vite"; +import solidPlugin from "vite-plugin-solid"; +import { workletInline } from "../../js/common/vite-plugin-worklet"; + +export default defineConfig({ + root: "src", + envDir: resolve(__dirname), + plugins: [tailwindcss(), solidPlugin(), workletInline()], + build: { + target: "esnext", + sourcemap: process.env.NODE_ENV === "production" ? false : "inline", + rollupOptions: { + input: { + watch: resolve(__dirname, "src/index.html"), + publish: resolve(__dirname, "src/publish.html"), + mse: resolve(__dirname, "src/mse.html"), + manual: resolve(__dirname, "src/manual.html"), + }, + }, + }, + server: { + // TODO: properly support HMR + hmr: false, + }, + optimizeDeps: { + // No idea why this needs to be done, but I don't want to figure it out. + exclude: ["@libav.js/variant-opus-af"], + }, +}); diff --git a/deno.json b/deno.json deleted file mode 100644 index 83640dbd92..0000000000 --- a/deno.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "unstable": ["sloppy-imports", "net"] -} diff --git a/deno.lock b/deno.lock deleted file mode 100644 index 8e95c842cf..0000000000 --- a/deno.lock +++ /dev/null @@ -1,123 +0,0 @@ -{ - "version": "5", - "specifiers": { - "jsr:@std/cli@*": "1.0.21" - }, - "jsr": { - "@std/cli@1.0.21": { - "integrity": "cd25b050bdf6282e321854e3822bee624f07aca7636a3a76d95f77a3a919ca2a" - } - }, - "workspace": { - "packageJson": { - "dependencies": [ - "npm:@biomejs/biome@^2.3.11", - "npm:concurrently@^9.2.1" - ] - }, - "members": { - "doc": { - "packageJson": { - "dependencies": [ - "npm:vitepress@^1.6.4", - "npm:wrangler@^4.56.0" - ] - } - }, - "js/clock": { - "packageJson": { - "dependencies": [ - "npm:@types/deno@^2.3.0", - "npm:typescript@^5.9.2" - ] - } - }, - "js/hang": { - "packageJson": { - "dependencies": [ - "npm:@kixelated/libavjs-webcodecs-polyfill@~0.5.5", - "npm:@libav.js/variant-opus-af@^6.8.8", - "npm:@types/audioworklet@^0.0.77", - "npm:@types/web@^0.0.241", - "npm:async-mutex@0.5", - "npm:comlink@^4.4.2", - "npm:fast-glob@^3.3.3", - "npm:rimraf@^6.0.1", - "npm:typescript@^5.9.2", - "npm:vitest@^3.2.4", - "npm:zod@^4.1.5" - ] - } - }, - "js/hang-demo": { - "packageJson": { - "dependencies": [ - "npm:@tailwindcss/typography@~0.5.16", - "npm:@tailwindcss/vite@^4.1.13", - "npm:highlight.js@^11.11.1", - "npm:tailwindcss@^4.1.13", - "npm:typescript@^5.9.2", - "npm:vite-plugin-solid@^2.11.10", - "npm:vite@^6.3.6" - ] - } - }, - "js/hang-ui": { - "packageJson": { - "dependencies": [ - "npm:@solidjs/testing-library@~0.8.10", - "npm:@testing-library/jest-dom@^6.9.1", - "npm:happy-dom@^20.0.11", - "npm:rimraf@^6.0.1", - "npm:solid-element@^1.9.1", - "npm:solid-js@^1.9.10", - "npm:typescript@^5.9.2", - "npm:unplugin-solid@1", - "npm:vite-plugin-solid@^2.11.10", - "npm:vite@^7.3.1", - "npm:vitest@^3.2.4" - ] - } - }, - "js/lite": { - "packageJson": { - "dependencies": [ - "npm:@moq/web-transport-ws@~0.1.2", - "npm:@types/deno@^2.3.0", - "npm:@types/node@^24.3.1", - "npm:@types/web@^0.0.241", - "npm:async-mutex@0.5", - "npm:madge@8", - "npm:rimraf@^6.0.1", - "npm:typescript@^5.9.2", - "npm:vite-plugin-html@^3.2.2", - "npm:vite@^6.3.6" - ] - } - }, - "js/signals": { - "packageJson": { - "dependencies": [ - "npm:@types/react@^19.1.8", - "npm:dequal@^2.0.3", - "npm:rimraf@^6.0.1", - "npm:solid-js@^1.9.7", - "npm:typescript@^5.9.2" - ] - } - }, - "js/token": { - "packageJson": { - "dependencies": [ - "npm:@hexagon/base64@^2.0.4", - "npm:@types/node@^24.3.1", - "npm:commander@^14.0.2", - "npm:jose@^6.1.0", - "npm:typescript@^5.9.2", - "npm:zod@^4.1.5" - ] - } - } - } - } -} diff --git a/deny.toml b/deny.toml new file mode 100644 index 0000000000..b3548456fe --- /dev/null +++ b/deny.toml @@ -0,0 +1,63 @@ +# cargo-deny configuration. See https://embarkstudios.github.io/cargo-deny/ +# +# Run `cargo deny check` to validate; runs in `just rs check` and `just rs ci`. + +[graph] +all-features = true + +[advisories] +version = 2 +yanked = "deny" +ignore = [ + # rsa 0.9.x Marvin Attack (RSA private-key timing sidechannel). The + # `rsa` crate is a direct dep of moq-token but is only used for keygen + # and PEM serialization of JWK components. JWT signing/verification + # itself runs through `jsonwebtoken` backed by `aws-lc-rs` (constant + # time), so the vulnerable code path is not exercised. Drop the ignore + # when rustcrypto/RSA publishes a constant-time fix. + "RUSTSEC-2023-0071", + + # foundations (Cloudflare) pins serde_yaml 0.8 which uses yaml-rust 0.4. + # Reachable via tokio-quiche -> web-transport-quiche -> moq-native + # (quiche feature). Awaits upstream migration to serde_yaml 0.9+. + "RUSTSEC-2024-0320", + + # gstreamer 0.23 pulls paste (proc-macro). gstreamer 0.25 drops it but + # requires Rust 1.92; workspace MSRV is 1.85. Build-time only. + "RUSTSEC-2024-0436", + + # http-cache (via http-cache-reqwest in moq-relay) still depends on + # bincode 1.x. Awaits upstream bump to bincode 2.x. + "RUSTSEC-2025-0141", +] + +[licenses] +version = 2 +confidence-threshold = 0.9 +allow = [ + "0BSD", + "Apache-2.0", + "Apache-2.0 WITH LLVM-exception", + "BSD-2-Clause", + "BSD-3-Clause", + "CC0-1.0", + "CDLA-Permissive-2.0", # webpki-roots cert bundle + "ISC", + "MIT", + "MPL-2.0", + "Unicode-3.0", + "Unlicense", + "WTFPL", # ffmpeg-next, ffmpeg-sys-next + "Zlib", +] + +[bans] +multiple-versions = "warn" +wildcards = "deny" +# Path/workspace deps don't carry versions; that's fine for intra-workspace use. +allow-wildcard-paths = true + +[sources] +unknown-registry = "deny" +unknown-git = "deny" +allow-registry = ["https://github.com/rust-lang/crates.io-index"] diff --git a/dev/leaf.toml b/dev/leaf.toml deleted file mode 100644 index f623d71c1c..0000000000 --- a/dev/leaf.toml +++ /dev/null @@ -1,69 +0,0 @@ -[log] -# Enable debug logging for development. -# The RUST_LOG environment variable will take precedence. -level = "debug" - -[server] -# Listen for QUIC connections on UDP:4444 -# Sometimes IPv6 causes issues; try 127.0.0.1:4444 instead. -listen = "[::]:4444" - -# Generate a self-signed certificate for the server. -# You should use a real certificate in production. -tls.generate = ["localhost"] - -[web.http] -# Listen for HTTP and WebSocket (TCP) connections on the given address. -listen = "[::]:4444" - -# This clustering scheme is very very simple for now. -# -# There is a root node that is used to connect leaf nodes together. -# Announcements flow from leaf -> root -> leaf, but any subscriptions are leaf -> leaf. -# The root node can serve (user) subscriptions too. -# -# The root node is either missing the "root" field below or it's identifical to the "node" field. -# This node acts a server only, accepting incoming connections from leaf nodes and users alike. -# -# There can be any number of leaf nodes. -# These nodes will connect to the specified root address and announce themselves via MoQ as a "broadcast". -# All nodes will discover these broadcasts and connect to other nodes. -# -# This forms an NxN mesh of nodes. -# Broadcasts are announced between all nodes with no collision detection, so duplicates are possible. -# Subscriptions will be relayed from leaf to leaf, so at most you can have: -# user -> leaf -> leaf -> user -[cluster] -# Connect to this hostname in order to discover other nodes. -connect = "localhost:4443" - -# Use the token in this file when connecting to other nodes. -# `just auth-token` will populate this file. -token = "dev/root.jwt" - -# My hostname, which must be accessible from other nodes. -node = "localhost:4444" - -# Each leaf node will connect to the root node and other nodes, using this configuration. -[client] -# QUIC uses TLS to have the client verify the server's identity. -# However if you're not worried about man-in-the-middle attacks, you can disable verification: -tls.disable_verify = true - -# A better approach is to generate a server certificate and configure the client to accept it. -# -# If the server has a certificate generated by a public root CA (ex. Let's Encrypt), then that will work if the client connects to the indiciated domain. -# ex. a cert for *.moq.dev will only be allowed if the root/node configuration below matches. -# -# Alternatively, you can generate a self-signed root CA and configure the client to accept it. -# tls.root = ["/path/to/root.pem"] -# -# This can be much more secure because the server doesn't need to be publically accessible. -# ex. You could host the root at a private `.internal` domain and generate a matching certificate. - -[auth] -# `just auth-key` will populate this file. -key = "dev/root.jwk" - -# Allow anonymous publishing and subscribing for this prefix. -public = "anon" diff --git a/dev/prod.toml b/dev/prod.toml deleted file mode 100644 index 40805ca639..0000000000 --- a/dev/prod.toml +++ /dev/null @@ -1,33 +0,0 @@ -# An example of a production configuration. -# Here's a real one: https://github.com/moq-dev/moq.dev/blob/b4da7dd8f09879cefb593d5e35f99f064caa3943/infra/relay.yml.tpl#L56 - -[server] -# Listen for QUIC connections on UDP:443 -# This is the default port for WebTransport -listen = "[::]:443" - -[server.tls] -# You'll need to provide a real certificate and key in production. -# You can get this via a service like Let's Encrypt. -cert = "cert.pem" -key = "key.pem" - -#[web.http] -# Optionally listen for HTTP and WebSocket connections on port 80. -# listen = "[::]:80" - -[web.https] -# Optionally listen for TCP/HTTPS/WSS connections on port 443. -listen = "[::]:443" - -# You'll need to provide a real certificate and key in production. -# This can be the exact same certificate and key as the QUIC endpoint. -cert = "cert.pem" -key = "key.pem" - -# See docs/auth.md for more information. -[auth] -# Path to the authentication key file: -# - For asymmetric keys (RS256, ES256, etc.): use the public key (e.g., "public.jwk") -# - For symmetric keys (HS256, HS384, HS512): use the shared secret key (e.g., "secret.jwk") -key = "public.jwk" diff --git a/dev/relay.toml b/dev/relay.toml deleted file mode 100644 index c954f9ee16..0000000000 --- a/dev/relay.toml +++ /dev/null @@ -1,38 +0,0 @@ -# A simple configuration for a local relay server. -# This is used for local development and has authentication disabled. - -[log] -# Enable debug logging for development. -# The RUST_LOG environment variable will take precedence. -level = "debug" - -[server] -# Listen for QUIC connections on UDP:4443 -# Sometimes IPv6 causes issues; try 127.0.0.1:4443 instead. -listen = "[::]:4443" - -# Generate a self-signed certificate for the given hostnames. -# This is used for local development, in conjunction with a fingerprint, or with TLS verification disabled. -tls.generate = ["localhost"] - -[web.http] -# Listen for HTTP and WebSocket connections on the given TCP address. -# This is unfortunately required to serve certificate.sha256 for local development. -# However, as a bonus, we can serve tracks via both HTTP and WebSocket fallbacks. -listen = "[::]:4443" - -# See root.toml and leaf.toml for auth and clustering examples. -[auth] -# Allow anonymous access to everything. -public = "" - -[iroh] -# You can optionally enable iroh support for P2P connections. -# Clients can connect using --iroh-enabled and a `iroh://` URL. -enabled = false - -# Path to persist the iroh secret key. -# If the file does not exist, a random key will be generated and written to the path. -# This gives the relay a persistent iroh endpoint id. The secret key can alternatively be set -# via MOQ_IROH_SECRET environment variable. -secret = "./dev/relay-iroh-secret.key" diff --git a/dev/root.toml b/dev/root.toml deleted file mode 100644 index 8b8140de17..0000000000 --- a/dev/root.toml +++ /dev/null @@ -1,34 +0,0 @@ -[log] -# Enable debug logging for development. -# The RUST_LOG environment variable will take precedence. -level = "debug" - -[server] -# Listen for QUIC connections on UDP:4443 -# Sometimes IPv6 causes issues; try 127.0.0.1:4443 instead. -listen = "[::]:4443" - -# Generate a self-signed certificate for the given hostnames. -# This is used for local development, in conjunction with a fingerprint, or with TLS verification disabled. -tls.generate = ["localhost"] - -[web.http] -# Listen for HTTP and WebSocket (TCP) connections on the given address. -# Defaults to disabled if not provided. -listen = "[::]:4443" - -# In production, we would use a real certificate from something like Let's Encrypt. -# Multiple certificates are supported; the first one that matches the SNI will be used. -# [[server.tls.cert]] -# chain = "dev/moq.dev.pem" -# key = "dev/moq.dev.key" - -# Authentication is rather crude because it's GOOD ENOUGH for now. -# see docs/auth.md for more information. -[auth] -# `just auth-key` will generate a root key. -# If you want to disable authentication, don't specify a key. -key = "dev/root.jwk" - -# Allow anonymous publishing and subscribing for anon/** -public = "anon" diff --git a/dev/throttle b/dev/throttle deleted file mode 100755 index 844ceabbd1..0000000000 --- a/dev/throttle +++ /dev/null @@ -1,104 +0,0 @@ -#!/bin/bash -# -# Network throttle for local development (macOS) -# Simulates a constrained network for QUIC testing. -# Runs until Ctrl+C, then restores original settings. - -set -e - -# Hard-coded profile: 2Mbps, 50ms delay, 100 packet queue -BANDWIDTH="2Mbit" -DELAY="50ms" -QUEUE="100" - -PIPE_NUM=1 -PF_ANCHOR="moq-throttle" -PF_CONF="/etc/pf.conf" -PF_BACKUP="/tmp/pf.conf.backup" - -# State tracking -PF_WAS_ENABLED="" -CLEANUP_DONE="" - -capture_pf_state() { - if sudo pfctl -s info 2>/dev/null | grep -q "Status: Enabled"; then - PF_WAS_ENABLED="yes" - else - PF_WAS_ENABLED="no" - fi -} - -cleanup() { - local exit_code=$? - - # Guard against running cleanup multiple times - [ -n "$CLEANUP_DONE" ] && return - CLEANUP_DONE="yes" - - echo "" - echo "Stopping network throttle..." - - # Flush anchor rules - sudo pfctl -a "$PF_ANCHOR" -F all 2>/dev/null || true - - # Delete dummynet pipe - sudo dnctl pipe $PIPE_NUM delete 2>/dev/null || true - - # Restore original PF config - if [ -f "$PF_BACKUP" ]; then - sudo cp "$PF_BACKUP" "$PF_CONF" - sudo pfctl -f "$PF_CONF" 2>/dev/null || true - sudo rm "$PF_BACKUP" - fi - - # Restore PF enabled/disabled state (only disable if we enabled it) - if [ "$PF_WAS_ENABLED" = "no" ]; then - sudo pfctl -d 2>/dev/null || true - fi - - echo "Throttling disabled." - exit "$exit_code" -} - -# Register cleanup for all exit paths -trap cleanup EXIT - -echo "Starting network throttle..." -echo " Bandwidth: $BANDWIDTH" -echo " Delay: $DELAY" -echo " Queue: $QUEUE packets" - -# Capture PF state before any changes -capture_pf_state - -# Back up pf.conf -sudo cp "$PF_CONF" "$PF_BACKUP" - -# Modify pf.conf: remove lo0 skip and add our anchor point -{ - grep -v "set skip on lo0" "$PF_BACKUP" - echo "dummynet-anchor \"$PF_ANCHOR\"" - echo "anchor \"$PF_ANCHOR\"" -} | sudo tee "$PF_CONF" > /dev/null - -# Configure dummynet pipe -sudo dnctl pipe $PIPE_NUM config bw "$BANDWIDTH" delay "$DELAY" queue "$QUEUE" - -# Load modified pf config -sudo pfctl -f "$PF_CONF" 2>/dev/null - -# Enable PF if it wasn't already enabled -if [ "$PF_WAS_ENABLED" = "no" ]; then - sudo pfctl -E 2>/dev/null || true -fi - -# Add throttling rules for outbound UDP only -echo "dummynet out proto udp all pipe $PIPE_NUM" | sudo pfctl -a "$PF_ANCHOR" -f - - -echo "Throttling enabled. Press Ctrl+C to stop." -echo "" - -# Wait forever until interrupted -while true; do - sleep 1 -done diff --git a/doc/.vitepress/config.ts b/doc/.vitepress/config.ts index 194ccb4e6c..7679bcf50a 100644 --- a/doc/.vitepress/config.ts +++ b/doc/.vitepress/config.ts @@ -5,64 +5,233 @@ export default defineConfig({ description: "Real-time latency at massive scale", base: "/", - head: [["link", { rel: "icon", href: "/icon.svg", type: "image/svg+xml" }]], + head: [ + ["link", { rel: "icon", href: "/favicon.svg", type: "image/svg+xml" }], + ["meta", { property: "og:type", content: "website" }], + ["meta", { property: "og:title", content: "Media over QUIC" }], + [ + "meta", + { + property: "og:description", + content: "Real-time latency at massive scale", + }, + ], + ["meta", { property: "og:image", content: "https://doc.moq.dev/icon.png" }], + ["meta", { property: "og:image:width", content: "163" }], + ["meta", { property: "og:image:height", content: "150" }], + ["meta", { property: "og:url", content: "https://doc.moq.dev" }], + ["meta", { property: "og:site_name", content: "Media over QUIC" }], + ["meta", { name: "twitter:card", content: "summary_large_image" }], + ["meta", { name: "twitter:title", content: "Media over QUIC" }], + [ + "meta", + { + name: "twitter:description", + content: "Real-time latency at massive scale", + }, + ], + ["meta", { name: "twitter:image", content: "https://doc.moq.dev/icon.png" }], + ["meta", { name: "theme-color", content: "#0f172a" }], + ], appearance: "force-dark", themeConfig: { - logo: "/icon.svg", + logo: "/favicon.svg", nav: [ { text: "Setup", link: "/setup/" }, - { text: "Concepts", link: "/concepts/" }, - { text: "API", link: "/api/" }, + { text: "Concepts", link: "/concept/" }, + { text: "Apps", link: "/bin/" }, + { + text: "Libraries", + link: "/lib/", + items: [ + { text: "Rust", link: "/lib/rs/" }, + { text: "TypeScript", link: "/lib/js/" }, + { text: "C", link: "/lib/c/" }, + { text: "Python", link: "/lib/py/" }, + { text: "Kotlin", link: "/lib/kt/" }, + { text: "Swift", link: "/lib/swift/" }, + { text: "Go", link: "/lib/go/" }, + ], + }, ], sidebar: { "/setup/": [ { text: "Setup", + link: "/setup/", + items: [ + { text: "Development", link: "/setup/dev" }, + { text: "Production", link: "/setup/prod" }, + { text: "Linux Packages", link: "/setup/linux" }, + ], + }, + { + text: "Demos", items: [ - { text: "Quick Start", link: "/setup/" }, - { text: "Development", link: "/setup/development" }, - { text: "Production", link: "/setup/production" }, + { text: "Web", link: "/setup/demo/web" }, + { text: "MoQ Boy", link: "/setup/demo/boy" }, ], }, ], - "/concepts/": [ + "/concept/": [ { text: "Concepts", + link: "/concept/", items: [ - { text: "Layers", link: "/concepts/" }, - { text: "Latency", link: "/concepts/latency" }, - { text: "Standards", link: "/concepts/standards" }, + { + text: "Layers", + link: "/concept/layer/", + items: [ + { text: "quic", link: "/concept/layer/quic" }, + { text: "web-transport", link: "/concept/layer/web-transport" }, + { text: "web-socket", link: "/concept/layer/web-socket" }, + { text: "moq-lite", link: "/concept/layer/moq-lite" }, + { text: "hang", link: "/concept/layer/hang" }, + ], + }, + { + text: "Standards", + link: "/concept/standard/", + items: [ + { text: "MoqTransport", link: "/concept/standard/moq-transport" }, + { text: "MSF", link: "/concept/standard/msf" }, + { text: "LOC", link: "/concept/standard/loc" }, + { text: "Interop", link: "/concept/standard/interop" }, + ], + }, + { + text: "Use Cases", + link: "/concept/use-case/", + items: [ + { text: "Contribution", link: "/concept/use-case/contribution" }, + { text: "Distribution", link: "/concept/use-case/distribution" }, + { text: "Conferencing", link: "/concept/use-case/conferencing" }, + { text: "AI", link: "/concept/use-case/ai" }, + { text: "Other", link: "/concept/use-case/other" }, + ], + }, ], }, ], - "/rust/": [ + "/bin/": [ { - text: "Rust Libraries", + text: "Applications", + link: "/bin/", items: [ - { text: "Overview", link: "/rust/" }, - { text: "moq-lite", link: "/rust/moq-lite" }, - { text: "hang", link: "/rust/hang" }, - { text: "moq-relay", link: "/rust/moq-relay" }, - { text: "Examples", link: "/rust/examples" }, + { + text: "Relay", + link: "/bin/relay/", + items: [ + { text: "Configuration", link: "/bin/relay/config" }, + { text: "Authentication", link: "/bin/relay/auth" }, + { text: "Clustering", link: "/bin/relay/cluster" }, + { text: "HTTP", link: "/bin/relay/http" }, + { text: "Production", link: "/bin/relay/prod" }, + ], + }, + { text: "CLI", link: "/bin/cli" }, + { text: "OBS", link: "/bin/obs" }, + { text: "GStreamer", link: "/bin/gstreamer" }, + { text: "Web", link: "/bin/web" }, ], }, ], - "/typescript/": [ + "/lib/": [ { - text: "TypeScript Libraries", + text: "Libraries", + link: "/lib/", items: [ - { text: "Overview", link: "/typescript/" }, - { text: "@moq/lite", link: "/typescript/lite" }, - { text: "@moq/hang", link: "/typescript/hang" }, - { text: "Web Components", link: "/typescript/web-components" }, - { text: "Examples", link: "/typescript/examples" }, + { + text: "Rust", + link: "/lib/rs/", + items: [ + { + text: "Environments", + link: "/lib/rs/env/", + items: [ + { text: "Native", link: "/lib/rs/env/native" }, + { text: "WASM", link: "/lib/rs/env/wasm" }, + ], + }, + { + text: "Crates", + link: "/lib/rs/crate", + items: [ + { text: "moq-net", link: "/lib/rs/crate/moq-net" }, + { text: "moq-native", link: "/lib/rs/crate/moq-native" }, + { text: "moq-token", link: "/lib/rs/crate/moq-token" }, + { text: "hang", link: "/lib/rs/crate/hang" }, + { text: "web-transport", link: "/lib/rs/crate/web-transport" }, + { text: "libmoq", link: "/lib/rs/crate/libmoq" }, + ], + }, + ], + }, + { + text: "TypeScript", + link: "/lib/js/", + items: [ + { + text: "Environments", + link: "/lib/js/env/", + items: [ + { text: "Web", link: "/lib/js/env/web" }, + { text: "Native", link: "/lib/js/env/native" }, + ], + }, + { + text: "Packages", + link: "/lib/js/@moq", + items: [ + { text: "@moq/net", link: "/lib/js/@moq/net" }, + { + text: "@moq/hang", + link: "/lib/js/@moq/hang/", + items: [ + { text: "Watch", link: "/lib/js/@moq/hang/watch" }, + { text: "Publish", link: "/lib/js/@moq/hang/publish" }, + ], + }, + { text: "@moq/watch", link: "/lib/js/@moq/watch" }, + { text: "@moq/publish", link: "/lib/js/@moq/publish" }, + { text: "@moq/token", link: "/lib/js/@moq/token" }, + { text: "@moq/signals", link: "/lib/js/@moq/signals" }, + ], + }, + ], + }, + { + text: "C", + link: "/lib/c/", + items: [{ text: "libmoq", link: "/lib/rs/crate/libmoq" }], + }, + { + text: "Python", + link: "/lib/py/", + items: [{ text: "moq-rs", link: "/lib/py/moq-rs" }], + }, + { + text: "Kotlin", + link: "/lib/kt/", + items: [{ text: "dev.moq:moq", link: "/lib/kt/moq" }], + }, + { + text: "Swift", + link: "/lib/swift/", + items: [{ text: "Moq", link: "/lib/swift/moq" }], + }, + { + text: "Go", + link: "/lib/go/", + items: [{ text: "moq", link: "/lib/go/moq" }], + }, ], }, ], @@ -74,7 +243,7 @@ export default defineConfig({ ], editLink: { - pattern: "https://github.com/moq-dev/moq/edit/main/docs/:path", + pattern: "https://github.com/moq-dev/moq/edit/main/doc/:path", text: "Edit this page on GitHub", }, @@ -88,7 +257,7 @@ export default defineConfig({ footer: { message: "Licensed under MIT or Apache-2.0", - copyright: "Copyright © 2025-present MoQ Contributors", + copyright: "Copyright © 2026-present moq.dev", }, }, @@ -97,6 +266,8 @@ export default defineConfig({ lineNumbers: true, }, - // TODO: Remove this - ignoreDeadLinks: true, + ignoreDeadLinks: [ + // Localhost URLs are intentional for development + "http://localhost:5173", + ], }); diff --git a/doc/.vitepress/theme/custom.css b/doc/.vitepress/theme/custom.css index 72e86976c6..04bab82fb4 100644 --- a/doc/.vitepress/theme/custom.css +++ b/doc/.vitepress/theme/custom.css @@ -108,6 +108,22 @@ margin: 0 auto; } +/* Tables */ +.vp-doc table { + margin: 2.5rem 0; +} + +.vp-doc th { + font-weight: 700; + color: #ffffff; + background-color: #1e293b; + border-bottom: 2px solid #22c55e; +} + +.vp-doc tr:nth-child(even) { + background-color: rgba(30, 41, 59, 0.5); +} + /* Navbar background */ .VPNav { background-color: #0f172a; diff --git a/doc/bin/cli.md b/doc/bin/cli.md new file mode 100644 index 0000000000..4bb280699a --- /dev/null +++ b/doc/bin/cli.md @@ -0,0 +1,187 @@ +--- +title: FFmpeg / moq-cli +description: Command-line tools for MoQ media +--- + +# FFmpeg / moq-cli + +`moq-cli` is a command-line tool for publishing media to MoQ relays. It works with FFmpeg for encoding. + +## Installation + +### Using Cargo + +```bash +cargo install moq-cli +``` + +### Using Nix + +```bash +# Run directly +nix run github:moq-dev/moq#moq-cli + +# Or build and find the binary in ./result/bin/ +nix build github:moq-dev/moq#moq-cli +``` + +### Using Docker + +```bash +docker pull moqdev/moq-cli +docker run -v "$(pwd)/video.mp4:/app/video.mp4:ro" moqdev/moq-cli publish /app/video.mp4 https://relay.example.com/anon/stream +``` + +Multi-arch images (`linux/amd64` and `linux/arm64`) are published to [Docker Hub](https://hub.docker.com/r/moqdev/moq-cli). + +### From Source + +```bash +git clone https://github.com/moq-dev/moq +cd moq +cargo build --release --bin moq-cli +``` + +The binary will be in `target/release/moq-cli`. + +## Basic Usage + +### Publish a Video File + +```bash +moq-cli publish video.mp4 https://relay.example.com/anon/my-stream +``` + +### Publish from FFmpeg + +Pipe FFmpeg output directly to moq-cli: + +```bash +ffmpeg -i input.mp4 -f mpegts - | moq-cli publish - https://relay.example.com/anon/my-stream +``` + +### Publish a Webcam + +```bash +# macOS +ffmpeg -f avfoundation -i "0:0" -f mpegts - | moq-cli publish - https://relay.example.com/anon/webcam + +# Linux +ffmpeg -f v4l2 -i /dev/video0 -f mpegts - | moq-cli publish - https://relay.example.com/anon/webcam +``` + +### Publish Screen + +```bash +# macOS +ffmpeg -f avfoundation -i "1:" -f mpegts - | moq-cli publish - https://relay.example.com/anon/screen + +# Linux (X11) +ffmpeg -f x11grab -i :0.0 -f mpegts - | moq-cli publish - https://relay.example.com/anon/screen +``` + +## Encoding Options + +### Custom Video Settings + +```bash +ffmpeg -i input.mp4 \ + -c:v libx264 -preset ultrafast -tune zerolatency \ + -b:v 2500k -maxrate 2500k -bufsize 5000k \ + -c:a aac -b:a 128k \ + -f mpegts - | moq-cli publish - https://relay.example.com/anon/stream +``` + +### Low Latency Settings + +```bash +ffmpeg -i input.mp4 \ + -c:v libx264 -preset ultrafast -tune zerolatency \ + -g 30 -keyint_min 30 \ + -c:a aac \ + -f mpegts - | moq-cli publish - https://relay.example.com/anon/stream +``` + +### H.265/HEVC + +```bash +ffmpeg -i input.mp4 \ + -c:v libx265 -preset ultrafast \ + -c:a aac \ + -f mpegts - | moq-cli publish - https://relay.example.com/anon/stream +``` + +## Authentication + +Pass a JWT token via the URL: + +```bash +moq-cli publish video.mp4 "https://relay.example.com/room/123?jwt=" +``` + +See [Authentication](/bin/relay/auth) for token generation. + +## Test Videos + +The repository includes helper commands for test content: + +```bash +# Publish Big Buck Bunny +just pub bbb https://relay.example.com/anon + +# Publish Tears of Steel +just pub tos https://relay.example.com/anon +``` + +## Clock Synchronization + +Publish and subscribe to clock broadcasts for testing: + +```bash +# Publish a clock +just clock publish https://relay.example.com/anon + +# Subscribe to a clock +just clock subscribe https://relay.example.com/anon +``` + +## Debugging + +### Verbose Output + +```bash +RUST_LOG=debug moq-cli publish video.mp4 https://relay.example.com/anon/stream +``` + +### Check Connection + +```bash +# Verify you can connect to the relay +curl http://relay.example.com:4443/announced/ +``` + +## Common Issues + +### "Connection refused" + +- Ensure the relay is running +- Check firewall allows UDP traffic +- Verify the URL is correct + +### "Invalid certificate" + +- The relay needs a valid TLS certificate +- For development, use the fingerprint method +- See [TLS Setup](/bin/relay/#tls-setup) + +### "Permission denied" + +- Check your JWT token is valid +- Verify the token allows publishing to that path +- See [Authentication](/bin/relay/auth) + +## Next Steps + +- Deploy a [relay server](/bin/relay/) +- Use [Web Components](/lib/js/env/web) for playback +- Try the [Rust libraries](/lib/rs/) for custom apps diff --git a/doc/bin/gstreamer.md b/doc/bin/gstreamer.md new file mode 100644 index 0000000000..bfb6818b07 --- /dev/null +++ b/doc/bin/gstreamer.md @@ -0,0 +1,214 @@ +--- +title: GStreamer Plugin +description: GStreamer plugin for MoQ +--- + +# GStreamer Plugin + +A GStreamer plugin for publishing and consuming MoQ streams. + +::: warning Work in Progress +This plugin is currently under development, but it works okay. +::: + +## Overview + +The GStreamer plugin provides two elements: + +- **moqsink** - Publish media to a MoQ relay +- **moqsrc** - Subscribe to MoQ broadcasts + +Both elements support the following properties: + +| Property | Type | Description | +| -------------------- | ------ | ----------------------------------------------------------------- | +| `url` | string | The relay URL to connect to | +| `broadcast` | string | The broadcast name | +| `tls-disable-verify` | bool | Disable TLS certificate validation (rarely needed, default false) | + +::: info +For `http://` URLs, `moq-native` automatically fetches the server's certificate fingerprint from `/certificate.sha256` and verifies TLS against it. You don't need `tls-disable-verify` for local development. +::: + +## Prerequisites + +The plugin requires GStreamer development libraries. It is **not** built by default since most users don't have them installed. + +If you're using Nix, GStreamer is included in the dev shell automatically. Otherwise, install manually: + +- **macOS:** `brew install gstreamer` +- **Debian/Ubuntu:** `apt install libgstreamer1.0-dev gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad` +- **Arch:** `pacman -S gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad` + +## Quick start with Nix + +If you have Nix installed, you don't need to build anything or set any environment variables. The `moq-gst` flake output bundles the plugin with wrappers around `gst-inspect-1.0` / `gst-launch-1.0` that preload moq alongside `gst-plugins-{base,good,bad}`, so the standard tools find `moqsink` / `moqsrc` automatically. + +### Inspect the plugin + +```bash +nix shell github:moq-dev/moq#moq-gst --command gst-inspect-1.0 moq +``` + +Lists `moqsink` and `moqsrc`. As a one-liner: `nix run github:moq-dev/moq#moq-gst -- moq`. + +### Subscribe to the public test broadcast + +`cdn.moq.dev/demo` hosts an always-on `bbb.hang` broadcast (looping Big Buck Bunny). Render it to a window: + +```bash +nix shell github:moq-dev/moq#moq-gst --command gst-launch-1.0 -v -e \ + moqsrc url=https://cdn.moq.dev/demo broadcast=bbb.hang \ + ! decodebin3 ! videoconvert ! autovideosink +``` + +Audio-only variant: swap the tail for `! decodebin3 ! audioconvert ! autoaudiosink`. + +### Publish your own broadcast + +`cdn.moq.dev/anon` accepts publishers without auth. Pick a name, publish, then subscribe to that same name (in another terminal or from another machine). + +```bash +# Download a pre-fragmented CMAF test file (one time). +curl -fsSL https://vid.moq.dev/bbb.mp4 -o bbb.mp4 + +# Terminal 1: loop the file as a broadcast named `.hang`. +nix shell github:moq-dev/moq#moq-gst --command gst-launch-1.0 -v -e \ + multifilesrc location=bbb.mp4 loop=true ! parsebin name=parse \ + parse. ! queue ! identity sync=true ! mux.sink_0 \ + parse. ! queue ! identity sync=true ! mux.sink_1 \ + moqsink name=mux url=https://cdn.moq.dev/anon broadcast=.hang +``` + +```bash +# Terminal 2: render it. +nix shell github:moq-dev/moq#moq-gst --command gst-launch-1.0 -v -e \ + moqsrc url=https://cdn.moq.dev/anon broadcast=.hang \ + ! decodebin3 ! videoconvert ! autovideosink +``` + +### Local relay + +If you'd rather run a relay yourself, the [relay binary](/bin/relay/) is in the same flake: + +```bash +# Terminal 1: start a relay on localhost:4443. +nix run github:moq-dev/moq#moq-relay -- demo/relay/localhost.toml + +# Terminal 2: publish. +nix shell github:moq-dev/moq#moq-gst --command gst-launch-1.0 -v -e \ + multifilesrc location=bbb.mp4 loop=true ! parsebin name=parse \ + parse. ! queue ! identity sync=true ! mux.sink_0 \ + parse. ! queue ! identity sync=true ! mux.sink_1 \ + moqsink name=mux url=http://localhost:4443/anon broadcast=bbb.hang + +# Terminal 3: subscribe. +nix shell github:moq-dev/moq#moq-gst --command gst-launch-1.0 -v -e \ + moqsrc url=http://localhost:4443/anon broadcast=bbb.hang \ + ! decodebin3 ! videoconvert ! autovideosink +``` + +::: tip +`http://` URLs auto-verify TLS via `/certificate.sha256` fingerprint pinning, so localhost development needs no certificate setup. +::: + +## Building + +```bash +cargo build -p moq-gst +``` + +This produces a shared library (cdylib) in `target/debug/`. GStreamer needs to find this plugin via the `GST_PLUGIN_PATH_1_0` environment variable — the `just` commands below handle this automatically. + +## Running Locally + +Start a [relay server](/bin/relay/) first: + +```bash +just relay +``` + +### Publishing + +Use the `just` shortcut to publish a test video via GStreamer: + +```bash +# Publish Big Buck Bunny (downloads automatically) +just pub gst bbb + +# Publish to a remote relay +just pub gst bbb https://cdn.moq.dev/anon +``` + +Or run `gst-launch-1.0` directly: + +```bash +# Point GST_PLUGIN_PATH_1_0 at the build output +export GST_PLUGIN_PATH_1_0="$PWD/target/debug${GST_PLUGIN_PATH_1_0:+:$GST_PLUGIN_PATH_1_0}" + +# Publish a fragmented MP4 file +gst-launch-1.0 -v -e \ + multifilesrc location=demo/pub/media/bbb.mp4 loop=true ! parsebin name=parse \ + parse. ! queue ! identity sync=true ! mux.sink_0 \ + parse. ! queue ! identity sync=true ! mux.sink_1 \ + moqsink name=mux url="http://localhost:4443/anon" broadcast="bbb" +``` + +::: tip +The input video must be a fragmented MP4 (CMAF). The `just pub download` helper fetches pre-fragmented test videos from `vid.moq.dev`. To fragment your own video: + +```bash +ffmpeg -i input.mp4 -c copy \ + -f mp4 -movflags cmaf+separate_moof+delay_moov+skip_trailer+frag_every_frame \ + output.mp4 +``` + +::: + +### Subscribing + +```bash +# Subscribe and render to the screen +just sub gst bbb + +# Subscribe from a remote relay +just sub gst bbb https://cdn.moq.dev/anon +``` + +Or directly: + +```bash +export GST_PLUGIN_PATH_1_0="$PWD/target/debug${GST_PLUGIN_PATH_1_0:+:$GST_PLUGIN_PATH_1_0}" + +gst-launch-1.0 -v -e \ + moqsrc url="http://localhost:4443/anon" broadcast="bbb" \ + ! decodebin3 ! videoconvert ! autovideosink +``` + +## Supported Codecs + +### moqsink (publish) + +| Media | Codec | GStreamer caps | +| ----- | ----- | --------------------- | +| Video | H.264 | `video/x-h264` | +| Video | H.265 | `video/x-h265` | +| Video | AV1 | `video/x-av1` | +| Audio | AAC | `audio/mpeg` (v4) | +| Audio | Opus | `audio/x-opus` | + +### moqsrc (subscribe) + +Outputs the same caps based on the catalog, compatible with `decodebin3`. + +## Debugging + +Enable GStreamer debug output: + +```bash +# GStreamer debug (verbose) +GST_DEBUG=*:4 just pub gst bbb + +# Rust logging +RUST_LOG=debug just pub gst bbb +``` diff --git a/doc/bin/index.md b/doc/bin/index.md new file mode 100644 index 0000000000..90652c1cd3 --- /dev/null +++ b/doc/bin/index.md @@ -0,0 +1,45 @@ +--- +title: Applications +description: Ready-to-use tools built on MoQ +--- + +# Applications + +These are the applications you can run today. +Some are servers, some are command-line tools, and some are web apps. + +## [moq-relay](/bin/relay/) + +The relay server that routes broadcasts between publishers and subscribers. +This is the heart of any MoQ deployment that relies on fanout. +Run it yourself, or pay for an external service (ex. Cloudflare). + +- [Configuration](/bin/relay/config) - TOML reference and examples +- [Authentication](/bin/relay/auth) - JWT-based access control +- [HTTP Endpoints](/bin/relay/http) - Debugging and diagnostics +- [Clustering](/bin/relay/cluster) - Multi-region deployment + +## [moq-cli](/bin/cli) + +A CLI for publishing to media streams. +Another tool does the encoding (ex. ffmpeg), making it easy to pipe any media into MoQ. + +```bash +# Publish your webcam +ffmpeg -f avfoundation -i "0" -f mp4 - | moq-cli publish https://relay.example.com my-stream +``` + +## [OBS Plugin](/bin/obs) + +Real-time latency with the familiar OBS interface. +Supports both publishing and subscribing. + +## [GStreamer Plugin](/bin/gstreamer) + +Integrate MoQ into GStreamer pipelines for advanced media workflows. +Supports both publishing and subscribing. + +## [Web Demo](/bin/web) + +A demo web application showcasing MoQ in the browser. +Watch streams, publish from your camera, and explore the API. diff --git a/doc/bin/obs.md b/doc/bin/obs.md new file mode 100644 index 0000000000..3638a0284c --- /dev/null +++ b/doc/bin/obs.md @@ -0,0 +1,40 @@ +--- +title: OBS Plugin +description: OBS Studio plugin for MoQ +--- + +# OBS Plugin + +An OBS Studio plugin for publishing and consuming MoQ streams. + +::: warning Work in Progress +This plugin is currently under development, but works pretty gud. +::: + +## Overview + +The OBS plugin allows you to: + +- **Publish** directly from OBS to a MoQ relay +- **Subscribe** to MoQ broadcasts as an OBS source + +## Repository + +The plugin is maintained in a separate repository: [moq-dev/obs](https://github.com/moq-dev/obs) + +## Usage + +### Publishing + +1. Open OBS Studio +2. Go to Settings > Stream +3. Select "MoQ" as the service +4. Enter your relay URL and path +5. Click "Start Streaming" + +### Subscribing + +1. Add a new source +2. Select "MoQ Source" +3. Enter the relay URL and broadcast path +4. The stream will appear in your scene diff --git a/doc/bin/relay/auth.md b/doc/bin/relay/auth.md new file mode 100644 index 0000000000..3126c73dd1 --- /dev/null +++ b/doc/bin/relay/auth.md @@ -0,0 +1,239 @@ +--- +title: Authentication +description: JWT-based access control for moq-relay +--- + +# Authentication + +moq-relay uses JWT (JSON Web Tokens) for authentication and authorization. Tokens control who can publish or subscribe to which paths. + +## Overview + +There are two authentication modes: + +### Single Key (`--auth-key`) + +A single JWK file used to verify all tokens. No `kid` header is required in JWTs. Good for development and simple deployments. + +### Key Directory (`--auth-key-dir`) + +For production use with key rotation. Keys are resolved on demand by extracting the `kid` from the JWT header and fetching the corresponding key file. + +1. Generate signing keys (a random key ID is assigned automatically) +2. Store each key as `{kid}.jwk` in a directory or serve via HTTP +3. Configure the relay with the key directory or URL +4. Issue tokens to clients with their allowed paths +5. Clients connect with `?jwt=` query parameter + +## Quick Start + +### Generate a Key + +Using the Rust CLI: + +```bash +# Symmetric key (simpler, key must stay secret) +moq-token-cli generate --out my-key.jwk + +# Save to a directory as {kid}.jwk +moq-token-cli generate --out-dir ./keys/ + +# Asymmetric key (private signs, public verifies) +moq-token-cli generate --algorithm ES256 --out private.jwk --public public.jwk + +# Asymmetric key, both saved to directories as {kid}.jwk +moq-token-cli generate --algorithm ES256 --out-dir ./private/ --public-dir ./keys/ +``` + +A random key ID is generated if `--id` is not specified. + +### Configure the Relay + +Single key (simplest): + +```toml +[auth] +key = "my-key.jwk" +``` + +Key directory (for key rotation): + +```toml +[auth] +# Point to the public keys directory (from --public-dir). +# For asymmetric algorithms, the relay only needs public keys to verify tokens. +key_dir = "/etc/moq/keys/" +``` + +Remote key server: + +```toml +[auth] +key_dir = "https://api.example.com/keys" +``` + +### Issue a Token + +```bash +# Allow publishing to demo/my-stream and subscribing to anything under demo/ +moq-token-cli sign --key my-key.jwk --root demo --publish my-stream --subscribe "" +``` + +The client connects with the token. The connection path can be the root or any parent: + +```text +# Connect at the token's root +https://relay.example.com/demo?jwt=eyJhbGciOiJIUzI1NiIs... + +# Connect at the server root (permissions still scoped to demo/) +https://relay.example.com/?jwt=eyJhbGciOiJIUzI1NiIs... +``` + +## Key Resolution + +### Single Key Mode (`--auth-key`) + +The relay uses the specified key file to verify all incoming JWTs. No `kid` header is required in the token. + +### Key Directory Mode (`--auth-key-dir`) + +Key files are stored as JSON by default. Legacy base64url-encoded files are also supported for backwards compatibility. Use `--base64` when generating keys if you prefer the base64url format. + +When a client connects with a JWT, the relay: + +1. Decodes the JWT header to extract the `kid` (key ID) +2. Looks up the key from the configured source: `{dir}/{kid}.jwk` or `{url}/{kid}.jwk` +3. Verifies the JWT signature with the resolved key +4. Checks the token's permissions cover the connection path + +Key IDs must contain only alphanumeric characters, hyphens, and underscores. + +## Token Claims + +The JWT payload contains these claims: + +| Claim | Description | +|-------|-------------| +| `root` | Base path for publish/subscribe permissions | +| `pub` | Suffix appended to root for publish permission | +| `sub` | Suffix appended to root for subscribe permission | +| `exp` | Expiration time (Unix timestamp) | +| `iat` | Issued-at time (Unix timestamp) | + +### Path Matching + +The `root` claim sets a base path. The `pub` and `sub` claims are suffixes: + +```text +Full publish path = root + "/" + pub +Full subscribe path = root + "/" + sub +``` + +An empty suffix (`""`) allows access to anything under the root. + +**Examples:** + +| root | pub | sub | Can publish | Can subscribe | +|------|-----|-----|-------------|---------------| +| `demo` | `my-stream` | `""` | `demo/my-stream` | `demo/*` | +| `rooms/123` | `alice` | `""` | `rooms/123/alice` | `rooms/123/*` | +| `""` | `""` | `""` | Everything | Everything | + +### Connection Path + +The client's connection URL path does **not** need to match the token's `root` exactly. The connection path determines the scope of the session — all publish/subscribe operations are relative to it. + +- If the connection path **extends** the root (e.g., token root=`demo`, connect to `/demo/room`), permissions are narrowed to only paths under `/demo/room`. +- If the connection path is a **parent** of the root (e.g., token root=`demo`, connect to `/`), permissions still apply but are scoped to the token's root. You can only access paths under `demo/`. +- If the connection path is **unrelated** to the root (e.g., token root=`demo`, connect to `/other`), the connection is rejected. + +The connection is also rejected if the resulting permissions are empty (no publish or subscribe paths remain after scoping). + +## Supported Algorithms + +### Symmetric (HMAC) + +The same key signs and verifies. Simpler setup, but the key must be kept secret everywhere it's used. + +- `HS256` - HMAC with SHA-256 (default) +- `HS384` - HMAC with SHA-384 +- `HS512` - HMAC with SHA-512 + +### Asymmetric (RSA/ECDSA) + +Private key signs, public key verifies. The relay only needs the public key, so compromise of the relay doesn't leak signing capability. + +- `RS256`, `RS384`, `RS512` - RSA PKCS#1 v1.5 +- `PS256`, `PS384`, `PS512` - RSA PSS +- `ES256`, `ES384` - ECDSA +- `EdDSA` - Edwards-curve DSA + +## Anonymous Access + +The `public` setting allows unauthenticated access to a path prefix: + +```toml +[auth] +key = "my-key.jwk" +public = "anon" # Anyone can publish/subscribe to anon/* +``` + +Set `public = ""` to make everything public (development only). + +## mTLS Peer Authentication + +In addition to JWT auth, the relay can authenticate peers via mutual TLS. When +the server is configured with a trusted root CA, any client that presents a +certificate chaining to that CA is granted **full publish and subscribe access +within the connection URL path**. The URL path scopes the grant exactly like a +JWT's `root` claim, so a peer dialing `/demo` can only publish and subscribe +under `demo/`. A peer dialing `/` (as cluster nodes do) gets an empty root and +unscoped, cluster-wide access. The token is also flagged as internal, which only +selects the stats tier used for billing; it grants no extra permissions. + +This is primarily intended for relay-to-relay (clustering) authentication, as a +simpler alternative to distributing long-lived JWTs. + +Client certificate presentation is **optional**: connections without a +certificate fall through to the normal JWT path unchanged. + +```toml +[tls] +cert = ["/etc/moq/server.pem"] +key = ["/etc/moq/server.key"] +# One or more PEM files containing the CAs trusted to sign peer certificates. +root = ["/etc/moq/peer-ca.pem"] +``` + +The certificate is used only to authenticate the peer: the relay verifies the +chain against the configured CA and reads nothing else from it. A node +advertises its own identity by setting `--cluster-mesh` to its +externally-reachable URL, which it publishes on the cluster origin for other +peers to discover and dial. + +Only the `quinn` QUIC backend supports mTLS; configuring `tls.root` with any +other backend is a startup error. + +## Example Configurations + +See the [`demo/relay/`](https://github.com/moq-dev/moq/tree/main/demo/relay) directory for complete working configuration files, including authentication setup: + +- **Development** - [`demo/relay/root.toml`](https://github.com/moq-dev/moq/blob/main/demo/relay/root.toml) (single key with anonymous access) +- **Production** - [`demo/relay/prod.toml`](https://github.com/moq-dev/moq/blob/main/demo/relay/prod.toml) (key and key directory options) + +## Library Usage + +### Rust + +- [`rs/moq-token/examples/basic.rs`](https://github.com/moq-dev/moq/blob/main/rs/moq-token/examples/basic.rs) - Symmetric key generation, signing, and verification +- [`rs/moq-token/examples/asymmetric.rs`](https://github.com/moq-dev/moq/blob/main/rs/moq-token/examples/asymmetric.rs) - Asymmetric key pair with public key extraction + +### TypeScript + +See [`js/token/examples/sign-and-verify.ts`](https://github.com/moq-dev/moq/blob/main/js/token/examples/sign-and-verify.ts) for a complete working example of signing and verifying tokens. + +## See Also + +- [moq-token (Rust)](/lib/rs/crate/moq-token) - Rust library and CLI +- [@moq/token](/lib/js/@moq/token) - TypeScript library and CLI +- [Relay Configuration](/bin/relay/config) - Full config reference diff --git a/doc/bin/relay/cluster.md b/doc/bin/relay/cluster.md new file mode 100644 index 0000000000..ccaf53530a --- /dev/null +++ b/doc/bin/relay/cluster.md @@ -0,0 +1,99 @@ +--- +title: Clustering +description: Run multiple moq-relay instances across multiple hosts/regions +--- + +# Clustering + +Relays can be joined together to proxy announcements and subscriptions between each other. A viewer talks to whichever relay is closest; if their broadcast lives somewhere else in the cluster, the local relay fetches it from a neighbor and caches it. + +A broadcast carries a small hop list as it travels. Each relay it passes through adds itself to the list, which is how loops are caught and how the network picks the shortest path when there's more than one. When two paths are the same length, every relay breaks the tie the same way (a hash of the broadcast name and hop list), so the whole cluster converges on one route instead of flapping between equals. + +## Topology + +Each relay lists the peers it wants to dial in `cluster.connect`. That's it; the topology is whatever you draw with those links. + +A simple chain works well when one region is the source and others are caches: + +```text +eu-west <--- us-east <--- us-west +``` + +```toml +# us-east.toml +[cluster] +connect = ["eu-west.example.com:4443"] + +# us-west.toml +[cluster] +connect = ["us-east.example.com:4443"] +``` + +A publisher on `eu-west` reaches a viewer on `us-west` through `us-east`. If a second `us-west` viewer subscribes to the same broadcast, `us-east` already has it cached, so only one fetch crosses the Atlantic. A full mesh (every relay dialing every other) would skip the cache entirely and waste an outbound link per pair. + +Pick the shape that matches your traffic. Linear chains are great for fanout; small N-way meshes are fine when latency matters more than dedup; mixed shapes work too. + +## Auto-discovery + +Listing every peer by hand can get tedious in larger clusters. Tell the relay its own URL with `cluster.node`, then enable gossip with `cluster.mesh`; connected peers will discover and dial it back automatically: + +```toml +[cluster] +connect = ["us-east.example.com:4443"] +node = "us-west.example.com:4443" +mesh = true +``` + +`node` is this relay's identity (its externally-reachable URL); `mesh` is a boolean that turns gossip on. Each gossiping node creates a broadcast carrying its `node` address, which other nodes pick up. `connect` is optional once gossip is running, but you still need at least one connection somewhere (either you dial a peer or a peer dials you) for the advertisement to flow. Enabling `mesh` without `node` is an error, since there'd be no address to advertise. + +When two gossiping nodes discover each other, only one of them dials: the node with the lexicographically-smaller URL is the client, the larger is the server. The session is bidirectional, so a single connection carries announcements both ways and the pair avoids opening two redundant links. This tiebreaker applies only to gossip-discovered peers; an explicit `connect` entry always dials. + +A relay with `node` + `mesh` and no `connect` is a passive rendezvous: it sits and waits for inbound connections, then helps everyone else find each other. + +## Dynamic peer lists + +`cluster.connect` is fixed at startup, so adding or removing a node means editing every affected config and restarting. When you'd rather keep the topology somewhere external and change it without a redeploy, point `cluster.connect_api` at an HTTP(S) endpoint or a local file: + +```toml +[cluster] +connect_api = "https://api.example.com/cluster/connect" +node = "us-west.example.com:4443" +``` + +The source returns a bare JSON array of peer hostnames: + +```json +["eu-west.example.com:4443", "us-east.example.com:4443"] +``` + +The relay reconciles that list against its live dials: new entries are dialed, entries that disappear are dropped. It composes with `connect` (static seeds that are never reconciled away) and `mesh` (gossip). The relay's own `node` value, when set, is sent as a `?node=` query parameter so the endpoint can return the peers for that specific node; for mTLS-gated endpoints the cluster client certificate identifies the caller as well. + +- **HTTP(S) URL**: re-checked every 30s, but freshness is delegated to a standard HTTP cache (`http-cache`), so the response's `Cache-Control` controls how often a check turns into a real fetch. While the cached list is still fresh (`max-age`), the re-check is served from cache with no network round-trip; once it's stale the cache issues a conditional GET (`ETag` / `Last-Modified`) and falls back to the last cached body if revalidation fails (stale-if-error). Set a longer `max-age` to reduce load on your endpoint, or `no-cache` to force a conditional GET on every tick. Transient endpoint blips don't churn the dial set. +- **Local file** (a path or `file://` URL): watched via OS filesystem notifications (inotify / FSEvents / kqueue), with a periodic re-check as a safety net. + +If a fetch fails or returns garbage, the relay logs and keeps the last good list rather than tearing the cluster down. This keeps the moq-relay binary generic: all routing decisions (which node connects where) live in whatever service answers the endpoint. + +## Authentication + +Cluster peers must authenticate to each other: + +- **mTLS** (recommended). Set `tls.root` to the CA that signed the cluster certificates. Inbound connections presenting a valid client cert are granted full access; outbound dials use `client.tls.cert` / `client.tls.key`. +- **JWT**. Each relay reads a token from `cluster.token` and presents it on outbound dials. The token needs broad enough scope to cover whatever paths the cluster carries. + +See [Authentication](/bin/relay/auth) for the full setup. + +## Migration from older configs + +`cluster.root` was removed; setting it errors at startup with a message pointing at the replacement. `cluster.mesh` is now a boolean gossip toggle (it used to take this relay's URL); the URL moved to `cluster.node`. The old `mesh = ""` form still works for backwards compatibility: it enables gossip and is treated as `cluster.node`, with a deprecation warning (or an error if it conflicts with an explicit `cluster.node`). + +| Old | New | +|---|---| +| `root = "rendezvous:4443"` + `node = "us-east:4443"` | `connect = ["rendezvous:4443"]` + `node = "us-east:4443"` + `mesh = true` | +| `root = "rendezvous:4443"` only | `node = "rendezvous:4443"` + `mesh = true` (passive rendezvous) | +| `mesh = "us-east:4443"` | `node = "us-east:4443"` + `mesh = true` | + +## Next steps + +- Deploy to [Production](/bin/relay/prod) +- Set up [Authentication](/bin/relay/auth) +- Learn about [Protocol concepts](/concept/layer/) diff --git a/doc/bin/relay/config.md b/doc/bin/relay/config.md new file mode 100644 index 0000000000..e7ed813395 --- /dev/null +++ b/doc/bin/relay/config.md @@ -0,0 +1,304 @@ +--- +title: Configuration +description: TOML configuration reference for moq-relay +--- + +# Configuration + +moq-relay is configured via a TOML file. Pass the path as the only argument: + +```bash +moq-relay relay.toml +# or +moq-relay --config relay.toml +``` + +## Minimal Example + +```toml +[server] +listen = "0.0.0.0:4443" + +[server.tls] +cert = "cert.pem" +key = "key.pem" +``` + +## Full Reference + +### \[log] + +Logging configuration. + +```toml +[log] +# Log level: trace, debug, info, warn, error +# The RUST_LOG environment variable takes precedence +level = "info" +``` + +### \[server] + +QUIC/WebTransport server settings. + +```toml +[server] +# Listen address for QUIC (UDP) +listen = "0.0.0.0:4443" +``` + +### \[server.tls] + +TLS configuration for the QUIC endpoint. + +```toml +[server.tls] +# Option 1: Provide certificate files +cert = "/path/to/cert.pem" # Certificate chain +key = "/path/to/key.pem" # Private key + +# Option 2: Generate self-signed certificates (development only) +generate = ["localhost", "127.0.0.1"] + +# Optional: root CAs to accept for mTLS peer authentication. +# Clients that present a cert signed by one of these CAs are granted +# full access (publish/subscribe/cluster). Intended for relay clustering. +# Quinn backend only. +root = ["/path/to/peer-ca.pem"] +``` + +For production, use certificates from Let's Encrypt or another CA. + +### \[web.http] + +HTTP server for debugging endpoints. + +```toml +[web.http] +# Listen address for HTTP (TCP) +# Defaults to disabled if not specified +listen = "0.0.0.0:4443" +``` + +See [HTTP Endpoints](/bin/relay/http) for available endpoints. + +### \[web.https] + +HTTPS/WSS server for TCP fallback. + +```toml +[web.https] +# Listen address for HTTPS/WSS (TCP) +listen = "0.0.0.0:443" + +# TLS certificates (can be the same as server.tls) +cert = "cert.pem" +key = "key.pem" +``` + +### \[auth] + +Authentication configuration. + +```toml +[auth] +# Path to the JWT verification key +# - Symmetric: the shared secret key +# - Asymmetric: the public key +key = "root.jwk" + +# Path prefix for anonymous access +# Omit to require authentication everywhere +public = "anon" +``` + +See [Authentication](/bin/relay/auth) for details on token generation. + +### \[cluster] + +Clustering configuration for multi-relay deployments. + +```toml +[cluster] +# Peers this relay dials. The topology is whatever you draw with these links. +connect = ["us-east.example.com:4443"] + +# Optional. This relay's own externally-reachable URL (identity). Advertised to +# peers when gossip is on, and sent to connect_api as ?node=. +node = "us-west.example.com:4443" + +# Optional. Enable gossip discovery: advertise `node` so peers find you +# automatically. Boolean; requires `node` to be set. +mesh = true + +# Optional. Fetch the peer list from an HTTP(S) endpoint or local file (a JSON +# array of hostnames) and reconcile it at runtime, no restart needed. +connect_api = "https://api.example.com/cluster/connect" + +# JWT used for outbound cluster dials (alternative to mTLS). +token = "cluster.jwt" +``` + +See [Clustering](/bin/relay/cluster) for topology choices and the trade-off between hand-listed peers and gossip. + +### \[client] + +Client settings used when connecting to other relays (clustering). + +```toml +[client] +# Disable TLS verification (development only!) +tls.disable_verify = true + +# Or provide trusted root certificates +# tls.root = ["/path/to/root.pem"] +``` + +### \[stats] + +Per-node stats publishing. When enabled, the relay publishes a single +`/node/` broadcast (or `/node` when `node` is unset) +carrying JSON snapshots of the broadcasts it's currently serving and of the +sessions currently connected to it. + +```toml +[stats] +# Master switch (defaults to false) +enabled = true + +# Top-level path under which stats broadcasts are published (defaults to ".stats") +prefix = ".stats" + +# Seconds between snapshot publishes (defaults to 1) +interval = 1 + +# Node identifier appended to the advertised path to disambiguate broadcasts +# when multiple relays share a cluster origin. May be multi-segment, e.g. +# "sjc/1" / "sjc/2" for two hosts nested under a shared region key. +# Single-relay deployments can omit this. +node = "sjc/1" +``` + +Each stats broadcast carries four per-broadcast tracks, one per +`(tier, role)` pair, plus two session tracks (one per tier): + +| Track | What it covers | +|-----------------------------|---------------------------------------------| +| `publisher.json` | external (e.g. customer) egress | +| `subscriber.json` | external ingress | +| `internal/publisher.json` | internal (e.g. mTLS cluster peer) egress | +| `internal/subscriber.json` | internal ingress | +| `sessions.json` | external connected sessions, keyed by root | +| `internal/sessions.json` | internal connected sessions, keyed by root | + +Each per-broadcast frame is a JSON object mapping broadcast path to a +cumulative counter snapshot. An entry surfaces on any tick where the +broadcast is live (any open counter still exceeds its `*_closed` +counterpart, so a subscription could begin at any moment) or its snapshot +changed since the previous tick. Once every counter equals its `*_closed` +counterpart no traffic can flow, so the entry is dropped: + +```json +{ + "demo/bbb": { + "announced": 1, "announced_closed": 0, + "broadcasts": 1, "broadcasts_closed": 0, + "subscriptions": 5, "subscriptions_closed": 2, + "bytes": 12345, "frames": 678, "groups": 9 + }, + "anon/foo": { + "announced": 1, "announced_closed": 0, + "broadcasts": 1, "broadcasts_closed": 0, + "subscriptions": 2, "subscriptions_closed": 0, + "bytes": 234, "frames": 12, "groups": 1 + } +} +``` + +Field semantics: + +- `announced` / `announced_closed`: cumulative count of every broadcast + announce/unannounce event on this `(tier, role)` slot, regardless of + whether any subscription happened. Use this for "all known broadcasts". +- `broadcasts` / `broadcasts_closed`: per-(broadcast, session) + subscription sentinel. The first active subscription a peer session + opens for a broadcast bumps `broadcasts`; the last one it closes bumps + `broadcasts_closed`. Summed across sessions, `broadcasts - + broadcasts_closed` is the number of distinct sessions currently + subscribed to the broadcast (i.e. viewers on the egress side), which is + typically what billing and UI want. +- `subscriptions` / `subscriptions_closed`: cumulative count of + track-level subscription guards opened and dropped. +- `bytes` / `frames` / `groups`: cumulative payload counters from the + session loops (both the `moq-lite` and IETF `moq-transport` paths). + +The session tracks (`sessions.json`, `internal/sessions.json`) instead map +each auth root to a `{ sessions, sessions_closed }` snapshot. `sessions` +bumps when a session authenticated under that root connects and +`sessions_closed` when it disconnects, so `sessions - sessions_closed` is +the number of sessions currently connected under the root. This counts +presence regardless of whether any data flows, so a client connected to +e.g. `/acme` is billable even while idle. A root entry is emitted while live +or on the tick it changed, then dropped once no session under it remains: + +```json +{ + "acme": { "sessions": 3, "sessions_closed": 1 }, + "globex": { "sessions": 1, "sessions_closed": 0 } +} +``` + +Tier, role, and node are implied by the track and broadcast paths, so +they aren't repeated inside the frame. Counters are cumulative and +strictly monotonic; a counter going *backwards* across successive +snapshots means the underlying entry was garbage-collected and +re-created (relay restart or a long idle gap). Downstream consumers +should treat decreases as a fresh session segment and sum across resets +when computing lifetime totals. + +Each snapshot reads `*_closed` atomics before their open counterparts, +which guarantees the emitted snapshot never shows `closed > open` even +under concurrent bumps (it can momentarily show an inflated *open* count, +which is logically valid). + +Frames for any one `(tier, role)` are skipped when the JSON is +byte-identical to the last emitted frame; new subscribers still pick up +a baseline immediately via track-latest semantics. + +Every flag also accepts an equivalent CLI argument (`--stats-enabled`, +`--stats-prefix`, `--stats-interval`, `--stats-node`) and environment +variable (`MOQ_STATS_ENABLED`, `MOQ_STATS_PREFIX`, `MOQ_STATS_INTERVAL`, +`MOQ_STATS_NODE`). + +### \[iroh] + +Experimental P2P support via iroh. + +```toml +[iroh] +# Enable iroh for P2P connections +enabled = false + +# Path to persist the iroh secret key +secret = "./relay-iroh-secret.key" +``` + +## Example Configurations + +See the [`demo/relay/`](https://github.com/moq-dev/moq/tree/main/demo/relay) directory for working configuration files: + +- **Development** - [`demo/relay/root.toml`](https://github.com/moq-dev/moq/blob/main/demo/relay/root.toml) +- **Production** - [`demo/relay/prod.toml`](https://github.com/moq-dev/moq/blob/main/demo/relay/prod.toml) +- **Cluster Leaf Node** - [`demo/relay/leaf0.toml`](https://github.com/moq-dev/moq/blob/main/demo/relay/leaf0.toml) + +## Environment Variables + +- `RUST_LOG` - Override the log level (e.g., `RUST_LOG=debug`) +- `MOQ_IROH_SECRET` - Set the iroh secret key directly + +## See Also + +- [Authentication](/bin/relay/auth) - JWT setup +- [HTTP Endpoints](/bin/relay/http) - Debug endpoints +- [Clustering](/bin/relay/cluster) - Multi-relay deployments +- [Production Deployment](/setup/prod) - Production checklist diff --git a/doc/bin/relay/http.md b/doc/bin/relay/http.md new file mode 100644 index 0000000000..11cbdb6a85 --- /dev/null +++ b/doc/bin/relay/http.md @@ -0,0 +1,84 @@ +--- +title: HTTP +description: HTTP endpoints exposed by moq-relay +--- + +# HTTP Endpoints + +moq-relay exposes HTTP/HTTPS endpoints via TCP too. +These were initially added for debugging but are useful for many things, such as fetching old content. + +## Configuration + +The relay supports both HTTP and HTTPS, configured independently: + +```toml +[web.http] +# Listen for unencrypted HTTP connections on TCP +listen = "0.0.0.0:80" + +[web.https] +# Listen for encrypted HTTPS connections on TCP +listen = "0.0.0.0:443" +cert = "cert.pem" +key = "key.pem" +``` + +::: warning +HTTP is unencrypted, which means any [authentication tokens](/bin/relay/auth) will be sent in plaintext. +It's recommended to only use HTTPS in production. +::: + +## Notable Endpoints + +### GET /announced/\*prefix + +Lists all announced broadcasts matching the given prefix. + +```bash +# All broadcasts +curl http://localhost:4443/announced/ + +# Broadcasts under "demo/" +curl http://localhost:4443/announced/demo + +# Specific broadcast +curl http://localhost:4443/announced/demo/my-stream +``` + +### GET /fetch/\*path + +Fetches a specific group from a track, by default the latest group. +Useful for quick debugging without setting up a full subscriber, or for fetching old content. + +The path is `//`, where the last segment is the track name and everything before it is the broadcast path. + +```bash +# Get latest catalog from broadcast "demo/my-stream" +curl http://localhost:4443/fetch/demo/my-stream/catalog.json + +# Get a specific video group from broadcast "demo/my-stream" +curl http://localhost:4443/fetch/demo/my-stream/video?group=42 +``` + +::: tip +Use HTTP fetch for catch-up and historical data. +Use MoQ subscriptions for the live edge. +The two complement each other — HTTP is request/response, MoQ is pub/sub. +::: + +### GET /certificate.sha256 + +Returns the SHA-256 fingerprint of the TLS certificate. +This is only useful for local development with self-signed certificates. + +```bash +curl http://localhost:4443/certificate.sha256 +# f4:a3:b2:... (hex-encoded fingerprint) +``` + +## See Also + +- [Relay Configuration](/bin/relay/config) - Full config reference +- [Clustering](/bin/relay/cluster) - Multi-relay deployments +- [hang format](/concept/layer/hang) - Groups, keyframes, and container details diff --git a/doc/bin/relay/index.md b/doc/bin/relay/index.md new file mode 100644 index 0000000000..11ab4a6433 --- /dev/null +++ b/doc/bin/relay/index.md @@ -0,0 +1,193 @@ +--- +title: moq-relay +description: A server that connects MoQ publishers and subscribers. +--- + +# moq-relay + +A server that routes broadcasts between publishers and subscribers, performing caching, deduplication, and fan-out. + +## Overview + +`moq-relay` is designed to run in datacenters, relaying media across multiple hops to improve quality of service and enable massive scale. + +**Features:** + +- Fan-out to multiple subscribers +- Caching and deduplication +- Cross-region clustering +- JWT-based authentication +- HTTP debugging endpoints + +## Installation + +### From Source + +```bash +git clone https://github.com/moq-dev/moq +cd moq +cargo build --release --bin moq-relay +``` + +The binary will be in `target/release/moq-relay`. + +### Using Cargo + +```bash +cargo install moq-relay +``` + +### Using Nix + +```bash +# Run directly +nix run github:moq-dev/moq#moq-relay + +# Or build and find the binary in ./result/bin/ +nix build github:moq-dev/moq#moq-relay +``` + +### Using Docker + +```bash +docker pull moqdev/moq-relay +docker run -p 4443:4443/udp -v "$(pwd)/relay.toml:/app/relay.toml:ro" moqdev/moq-relay -- --config /app/relay.toml +``` + +Multi-arch images (`linux/amd64` and `linux/arm64`) are published to [Docker Hub](https://hub.docker.com/r/moqdev/moq-relay). + +## Configuration + +Create a `relay.toml` configuration file: + +```toml +[server] +bind = "[::]:4443" # Listen on all interfaces, port 4443 + +[tls] +cert = "/path/to/cert.pem" # TLS certificate +key = "/path/to/key.pem" # TLS private key + +[auth] +public = "anon" # Allow anonymous access to anon/** +key = "root.jwk" # JWT key for authenticated paths +``` + +See [localhost.toml](https://github.com/moq-dev/moq/blob/main/demo/relay/localhost.toml) for a complete example. + +## Running + +```bash +moq-relay --config relay.toml +``` + +Or with the config path as the only argument: + +```bash +moq-relay relay.toml +``` + +## HTTP Endpoints + +The relay exposes HTTP/HTTPS endpoints for debugging, health checks, and late-join. See [HTTP](/bin/relay/http) for details. + +## TLS Setup + +The relay requires TLS certificates. Use [Let's Encrypt](https://letsencrypt.org/): + +```bash +# Install certbot +sudo apt install certbot # Ubuntu/Debian +brew install certbot # macOS + +# Generate certificate +sudo certbot certonly --standalone -d relay.example.com +``` + +Update `relay.toml`: + +```toml +[tls] +cert = "/etc/letsencrypt/live/relay.example.com/fullchain.pem" +key = "/etc/letsencrypt/live/relay.example.com/privkey.pem" +``` + +## Monitoring + +### Logging + +Set log level via environment variable: + +```bash +RUST_LOG=info moq-relay relay.toml +RUST_LOG=debug moq-relay relay.toml +RUST_LOG=moq_relay=trace moq-relay relay.toml +``` + +### Metrics + +Metrics (Prometheus format) are planned but not yet implemented. + +Current visibility: + +- Check logs for connection count +- Use [HTTP endpoints](/bin/relay/http) for track inspection +- Monitor system resources (CPU, memory, bandwidth) + +## Performance + +### Current Status + +- **Single-threaded** - Quinn uses one UDP receive thread +- **In-memory caching** - Recent groups stored in RAM +- **Mesh clustering** - All relays connect to all others + +### Scaling + +- **Vertical** - Fast CPU matters more than core count +- **Horizontal** - Deploy multiple relays in different regions +- **Cluster size** - 3-5 nodes optimal with current implementation + +### Future Improvements + +- Multi-threaded UDP processing +- Tree-based clustering topology +- Improved memory management +- Metrics and observability + +## Troubleshooting + +### Port Already in Use + +```bash +# Check what's using port 4443 +lsof -i :4443 + +# Kill the process or use a different port +``` + +### Certificate Errors + +Ensure: + +- Certificate is valid and not expired +- Certificate matches domain name +- Private key has correct permissions +- Certificate includes full chain + +### Connection Timeouts + +Check: + +- UDP port is open in firewall +- Cloud provider allows UDP traffic +- TLS certificate is valid +- Relay is actually running + +## Next Steps + +- Set up [Authentication](/bin/relay/auth) +- Configure [Clustering](/bin/relay/cluster) +- Deploy to [Production](/bin/relay/prod) +- Use [moq-net](/lib/rs/crate/moq-net) client library +- Build media apps with [hang](/lib/rs/crate/hang) diff --git a/doc/bin/relay/prod.md b/doc/bin/relay/prod.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/doc/bin/web.md b/doc/bin/web.md new file mode 100644 index 0000000000..9e3093deaa --- /dev/null +++ b/doc/bin/web.md @@ -0,0 +1,32 @@ +--- +title: Web Demo +description: Browser-based demo application for MoQ +--- + +# Web Demo + +The web demo application showcases MoQ's browser capabilities, allowing you to publish and watch live streams directly from a web browser. + +## Overview + +Located at `demo/web/`, the web demo provides: + +- **Publishing** — Capture camera, microphone, or screen and publish via MoQ +- **Watching** — Subscribe to and render live broadcasts with low latency +- **Web Components** — Uses `` and `` custom elements + +## Running Locally + +```bash +cd demo/web +bun install +bun run dev +``` + +Then open in a browser with WebTransport support (Chrome 97+, Edge 97+). + +## Related + +- [@moq/watch](/lib/js/@moq/watch) — Watch/subscribe package +- [@moq/publish](/lib/js/@moq/publish) — Publish package +- [Relay setup](/bin/relay/) — Server to connect to diff --git a/doc/concept/index.md b/doc/concept/index.md new file mode 100644 index 0000000000..31243ef333 --- /dev/null +++ b/doc/concept/index.md @@ -0,0 +1,30 @@ +--- +title: Concepts +description: Understanding MoQ's fundamental concepts +--- + +# Concepts + +Welcome to my favorite section. +MoQ has been a multi-year journey to solve some very real problems in the industry and now it's time to flex the design. + +## Layers + +MoQ is carefully broken into layers to make it simple, composable, and customizable. +We don't want you to hit a brick wall if you deviate from the standard path (*ahem* WebRTC). + +See [Layers](/concept/layer/) for more information. + +## Standards + +MoQ is built on open standards and protocol specifications. +We're in this together, even if we disagree on some details. + +See [Standards](/concept/standard/) for more information. + +## Use Cases + +MoQ is designed to be used in a variety of use-cases. +Distribution, contribution, conferencing, and more. + +See [Use Cases](/concept/use-case/) for more information. diff --git a/doc/concept/layer/hang.md b/doc/concept/layer/hang.md new file mode 100644 index 0000000000..c193638e38 --- /dev/null +++ b/doc/concept/layer/hang.md @@ -0,0 +1,133 @@ +--- +title: Hang +description: A simple, WebCodecs-based media format utilizing MoQ. +--- + +# hang + +A simple, WebCodecs-based media format utilizing MoQ. See the [specification](https://datatracker.ietf.org/doc/draft-lcurley-moq-hang/) for wire-level details. + +## Catalog + +`catalog.json` is a special track that contains a JSON description of available tracks. +This is how the viewer decides what it can decode and wants to receive. +The catalog track is live updated as media tracks are added, removed, or changed. + +Each media track is described using the [WebCodecs specification](https://www.w3.org/TR/webcodecs/) and we plan to support every codec in the [WebCodecs registry](https://w3c.github.io/webcodecs/codec_registry.html). + +### Example + +Here is Big Buck Bunny's `catalog.json` as of 2026-02-02: + +```json +{ + "video": { + "renditions": { + "video0": { + "codec": "avc1.64001f", + "description": "0164001fffe100196764001fac2484014016ec0440000003004000000c23c60c9201000568ee32c8b0", + "codedWidth": 1280, + "codedHeight": 720, + "container": "legacy" + } + } + }, + "audio": { + "renditions": { + "audio1": { + "codec": "mp4a.40.2", + "sampleRate": 44100, + "numberOfChannels": 2, + "bitrate": 283637, + "container": "legacy" + } + } + } +} +``` + +### Audio + +[See the latest schema](https://github.com/moq-dev/moq/blob/main/js/hang/src/catalog/audio.ts). + +Audio is split into multiple renditions that should all be the same content, but different quality/codec/language options. + +Each rendition is an extension of [AudioDecoderConfig](https://www.w3.org/TR/webcodecs/#audio-decoder-config). +This is the minimum amount of information required to initialize an audio decoder. + +### Video + +[See the latest schema](https://github.com/moq-dev/moq/blob/main/js/hang/src/catalog/video.ts). + +Video is split into multiple renditions that should all be the same content, but different quality/codec/language options. +Any information shared between multiple renditions is stored in the root. +For example, it's not possible to have a different `flip` or `rotation` value for each rendition, + +Each rendition is an extension of [VideoDecoderConfig](https://www.w3.org/TR/webcodecs/#video-decoder-config). +This is the minimum amount of information required to initialize a video decoder. + +## Container + +The catalog also contains a `container` field for each rendition used to denote the encoding of each track. +Unfortunately, the raw codec bitstream lacks timestamp information so we need some sort of container. + +Containers can support additional features and configuration. +For example, `CMAF` specifies a timescale instead of hard-coding it to microseconds like `legacy`. + +### Legacy + +This is a lightweight container with no frills attached. +It's called "legacy" because it's not extensible nor optimized and will be deprecated in the future. + +Each frame consists of: + +- A 62-bit (varint-encoded) presentation timestamp in microseconds. +- The codec payload. + +### CMAF + +This is a more robust container used by HLS/DASH. + +Each frame consists of: + +- A `moof` box containing a `tfhd` box and a `tfdt` box. +- A `mdat` box containing the codec payload. + +Unfortunately, fMP4 is not quite designed for real-time streaming and incurs either a latency or size overhead: + +- Minimal latency: 1-frame fragments introduce ~100 bytes of overhead per frame. +- Minimal size (HLS): GoP sized fragments introduce a GoP's worth of latency. +- Mixed latency/size (LL-HLS): 500ms-sized fragments introduce a 500ms latency, with some additional overhead. + +## `description` + +The `description` field in audio/video renditions contains codec-specific initialization data based on the [WebCodecs codec registration](https://www.w3.org/TR/webcodecs-codec-registry/). + +For example, the `description` field for [H.264](https://www.w3.org/TR/webcodecs-avc-codec-registration/) can be: + +- **present**: the `description` is an `avcC` box, containing the SPS/PPS and other information. +- **absent**: the SPS/PPS NALUs are delivered **inline** before each keyframe. + +There's no "right format" and both exist in the wild. +Inlining the SPS/PPS marginally increases the overhead of each frame, but it means the decoder can be reinitialized (ex. resolution change). + +Unfortunately, your decoder should handle both. + +## Groups and Keyframes + +Each MoQ group aligns with a video Group of Pictures (GoP). +A new group starts with a keyframe (IDR frame) that can be decoded independently. + +This has important implications: + +- **Skipping a group means skipping an entire GoP.** The relay can drop old groups without corrupting the decoder state. +- **Late-join viewers** start at the beginning of a group (the keyframe), since it's not possible to join mid-group. +- **Audio groups** don't need to align with video groups and can contain any number of frames. + +The relay uses group boundaries for partial reliability: if congestion occurs, entire groups are dropped rather than individual frames, keeping the decoder in a consistent state. + +## Custom Media Formats + +You can make your own media format if you have full control over the publisher and all viewers. +You would be missing out on existing tools and libraries but it's really not that complicated; +QUIC and moq-lite do the heavy lifting. diff --git a/doc/concept/layer/index.md b/doc/concept/layer/index.md new file mode 100644 index 0000000000..2e823cc46b --- /dev/null +++ b/doc/concept/layer/index.md @@ -0,0 +1,83 @@ +--- +title: Layering +description: It's like a cake; you choose if you want frosting. +--- + +# Layers + +The design philosophy of MoQ is to make things simple, composable, and customizable. +We don't want you to hit a brick wall if you deviate from the standard path (*ahem* WebRTC). +We also want to benefit from economies of scale (like HTTP), utilizing generic libraries and tools whenever possible. + +To accomplish this, MoQ is broken into layers stacked on top of each other. +It's like a cake; you choose whether you want frosting or not. + +## QUIC + +[QUIC](/concept/layer/quic) is the core protocol that powers HTTP/3, designed to fix the head-of-line blocking that plagues TCP. + +Think of it like: + +- **TCP 2.0**: connections with congestion control, flow control, and retransmissions. But now with independent streams and prioritization to avoid head-of-line blocking. +- **UDP 2.0**: optional reliability and datagrams, allowing stuff to get dropped during congestion. + +It's a web standard, available in all major browsers, battle-tested by huge CDNs, and with great open-source implementations from every major tech company. + +## WebTransport (optional) + +[WebTransport](/concept/layer/web-transport) is a small layer that shares a QUIC connection with HTTP/3. + +Basically it's like WebSocket but for QUIC instead of TCP. +Browsers need it because not using HTTP would be some cardinal sin or something. +Everybody else can use QUIC directly instead. + +## WebSocket (optional) + +[WebSocket](/concept/layer/web-socket) is a TCP fallback for when QUIC is blocked (corporate firewalls) or unsupported (Safari). + +MoQ clients will automatically race the QUIC and WebSocket connections in parallel, using whatever wins the race. +It sucks but sometimes *media over QUIC* isn't actually an option. + +## MoQ Transport + +[moq-lite](/concept/layer/moq-lite) is a forwards-compatible subset of the [MoqTransport](/concept/standard/moq-transport) specification. +moq-lite clients work with any moq-transport CDN, so you're not locked in. + +The goal is a generic pub/sub protocol that can be scaled up via a CDN (see [moq-relay](/bin/relay/)). +The CDN doesn't know anything about media, it just knows track/group/frame boundaries and what it should do during congestion. +Think of it like HTTP but for live content. + +MoQ is bidirectional, so a **session** can be both a **publisher** and a **subscriber**: + +- A publisher produces **broadcasts**, split into one or more **tracks**. +- A subscriber discovers available broadcasts and can choose to subscribe to tracks. + +Each subscription is split into QUIC streams: + +- A **group** is a QUIC stream (independent, unordered) that can be closed or reset (congestion). +- A **frame** is a chunk of bytes with an upfront size, delivered reliably and in order *within a group*. + +## Media Format + +[hang](/concept/layer/hang) is a simple media format running on top of moq-lite. +The relay doesn't care about media details, but the end clients need to agree on something: a catalog of tracks, a container for each frame, and codec configuration. + +The IETF is working on a [suite of drafts](/concept/standard/msf) but the ideas are similar. + +## Application + +MoQ tracks are additive. +You can create new tracks for whatever purpose and it doesn't interfere with the function of a relay or media client. +Go ahead, create a `controller` track to stream button presses and it will be treated like any other opaque sequence of bytes. + +MoQ is implemented in application space, not built into the browser like WebRTC. +If you don't like something, fork it and ship your own web and native apps. + +## More Info + +I'd recommend starting with the minimal: + +- [moq-lite](/concept/layer/moq-lite) +- [hang](/concept/layer/hang) + +Then read more about the various [IETF standards](/concept/standard/). diff --git a/doc/concept/layer/moq-lite.md b/doc/concept/layer/moq-lite.md new file mode 100644 index 0000000000..38424d7260 --- /dev/null +++ b/doc/concept/layer/moq-lite.md @@ -0,0 +1,160 @@ +--- +title: MoQ Lite +description: A simple, forwards-compatible subset of MoQ Transport. Avoids some of the more complex (and dangerous) functionality. +--- + +# moq-lite + +This website uses [moq-lite](/concept/layer/moq-lite), a subset of the IETF [moq-transport](/concept/standard/moq-transport) draft. +moq-lite is forwards compatible with moq-transport so it works with any moq-transport CDN (ex. [Cloudflare](https://moq.dev/blog/first-cdn)). +The principles behind MoQ are fantastic, but standards are **SLOW** and involve too much arguing. +My goal is to build something simple that you can use *now*, even if it's not a standard *yet*. + +See the [specification](https://datatracker.ietf.org/doc/draft-lcurley-moq-lite/) for low-level details. + +## API + +### Terminology + +- **Session** - A bidirectional connection between a client and a server. +- **Origin** - A collection of **broadcasts**, used to scope what is available to a session. +- **Broadcast** - A named and discoverable collection of **tracks** from a single publisher. +- **Track** - A series of **groups**, potentially delivered out-of-order until closed/cancelled. +- **Group** - A series of **frames** delivered in order until closed/cancelled. +- **Frame** - A chunk of bytes with an upfront size. + +**NOTE:** The IETF draft uses some different names. +THE BIKE SHED MUST BE PAINTED RED. + +- `Origin` -> (doesn't exist in moq-transport) +- `Broadcast` -> `Namespace` +- `Frame` -> `Object` + +### Session Establishment + +When a client connects to a server, it sends a list of supported ALPNs. +The server selects the first supported one to negotiate the protocol/version. + +If `h3` is negotiated, then we do *another* ALPN negotiation as part of the WebTransport handshake. +It's gross but required for web browsers, so we suck it up. + +Here's a list of currently supported ALPNs: + +- `moql`: moq-lite, the version is negotiated via `SETUP`. +- `moq-lite-03`: moq-lite draft 3 +- `moq-00`: moq-transport draft 14, the version is negotiated via `SETUP`. +- `moqt-15`: moq-transport draft 15 +- `moqt-16`: moq-transport draft 16 +- `moqt-17`: moq-transport draft 17 +- etc... + +See the Compatibility section below for more details about `moq-transport` support. + +Once the QUIC or WebTransport connection is established, there is a minimal MoQ handshake. +The `SETUP` message is primarily used to negotiate extensions, then you're off to the races! + +### Announcements + +`moq-lite` optionally supports live discovery of broadcasts. + +Depending on the language, there's an `announced(prefix: Path)` method on the session. +This asks the peer to notify us of any existing broadcasts that match the prefix and any future updates. + +This is extremely useful for conference rooms, as you can live discover when participants join and leave. +It's also useful for individual broadcasts as you can get notifications it comes online or goes offline (no spamming F5). +The [moq-relay clustering](/bin/relay/cluster) feature actually uses this to discover other nodes in the cluster AND what broadcasts are available on each node. + +### Subscriptions + +All data transfers are initiated by subscriptions. + +The subscriber needs to send a `SUBSCRIBE` message indicating the **broadcast** and **track** they want (both strings). +There are additional options, such as `priority`, that primarily impact the behavior during congestion. +See the congestion section below for more details. + +If the peer doesn't have the broadcast/track, they will get an error. +Otherwise, the subscription is active and will stay open until closed by the publisher (possibly with an error). + +A track is broken into **groups**, each with an increasing ID. +Conceptually, these are join points, and new subscriptions will always start at the latest group. +Groups are delivered independently and potentially out of order, so you should have some logic to reorder or skip during congestion. +A group is closed when finished or aborted with an error (ex. during congestion). + +Each group consists of one or more **frames**. +Frames within a group are delivered reliably and in order. +You can and should take advantage of this, for example using delta encoding. +If frames within a group are actually independent, you should probably split them into individual groups! + +### Congestion + +If it's not obvious by now, a lot of MoQ's behavior is designed to be robust to congestion. + +When congestion occurs, something **MUST** get dropped. +MoQ puts each subscriber (viewer) in control, allowing them to choose how much latency they can tolerate. +This is how the same protocol can deliver the same content anywhere between 100ms of latency to 30s of latency. + +Each Subscription consists of a few properties: + +- **Track Priority**: A value between 0 and 255. Tracks with higher priority will be delivered first. +- **Group Order**: The order in which groups are delivered. Defaults to descending; higher IDs are delivered first. +- **Group Timeout**: The maximum duration to keep old groups in cache/transit. Defaults to 30 seconds. + +By utilizing these properties, you can choose how your application behaves during congestion. +For example, consider a conference room with Alice and Bob: + +| Track | Priority | Order | Timeout | +|-------|----------|-------|---------| +| `alice/audio` | 100 | ascending | 500ms | +| `bob/audio` | 90 | ascending | 500ms | +| `alice/video` | 50 | descending | 2s | +| `bob/video` | 40 | descending | 2s | + +When combined with a local jitter buffer, this should result in different user experiences based on the network conditions: + +- **No Congestion**: Every frame is delivered immediately. +- **Minor Congestion**: Bob's video might skip a few frames at the tail of each group. +- **Moderate Congestion**: Bob and Alice's video will skip the tail of each group, but audio will still be delivered. +- **Heavy Congestion**: Bob and Alice's audio might fall behind, but never more than 500ms. Video is completely dropped. + +There's no optimal solution for this, but we think these subscription properties provide a GOOD ENOUGH user experience for most use-cases. +They're simple to implement and easy enough to understand. + +## Compatibility + +`moq-lite` is forward compatible with `moq-transport`. +That means for every moq-lite API, there's a corresponding moq-transport API. + +That's good! +You're not locked into moq-lite and can use moq-transport in the future. +I can get hit by a bus and you wouldn't shed a tear. + +When `moq-transport` wire format is negotiated, we still enforce the moq-lite API. +If the peer insists on using a moq-transport-only feature, we fake it or worst case, return an error. +For example, if there's a gap in a group (valid in moq-transport), we drop the tail of the group instead of erroring. + +The following table shows the simplified compatibility matrix. +Note that there are typically 2 clients, a publisher and a subscriber. +But if a publisher needs a feature, then the subscriber needs it too, so you can lump them together. + +| client | relay | supported | notes | +|---------------|---------------|:---------:|----------------------------------------------------------------------| +| moq-lite | moq-lite | ✅ | | +| moq-lite | moq-transport | ✅ | | +| moq-transport | moq-lite | ⚠️ | No moq-transport-only features. | +| moq-transport | moq-transport | ⚠️ | Depends on the implementations. | + +### Major Differences + +- **No Request IDs**: A bidirectional stream for each request to avoid HoLB. (NOTE: likely to be upstreamed into moq-transport) +- **No Push**: A subscriber must explicitly subscribe to each track. +- **No FETCH**: Use HTTP for VOD instead of reinventing the wheel. +- **No Joining Fetch**: Subscriptions start at the latest group, not the latest frame. +- **No sub-groups**: SVC layers should be separate tracks. +- **No gaps**: Makes life much easier for the relay and every application. +- **No object properties**: Encode your metadata into the frame payload. +- **No pausing**: Unsubscribe if you don't want a track. +- **No binary names**: Uses UTF-8 strings instead of arrays of byte arrays. +- **No datagrams**: Maybe one day. + +This may seem like a lot of missing features, but in practice you don't need them. +For example, [MSF](/concept/standard/msf) doesn't use any of these features so it's fully compatible with moq-lite. diff --git a/doc/concept/layer/quic.md b/doc/concept/layer/quic.md new file mode 100644 index 0000000000..07b7e6b0c5 --- /dev/null +++ b/doc/concept/layer/quic.md @@ -0,0 +1,117 @@ +--- +title: QUIC +description: The transport protocol that makes MoQ possible +--- + +# QUIC + +[RFC9000](https://datatracker.ietf.org/doc/html/rfc9000) - QUIC: A UDP-Based Multiplexed and Secure Transport + +QUIC is why MoQ exists. +It's the protocol that finally grants us the web support needed for real-time streaming. + +## History + +To explain the purpose of QUIC, it's helpful to understand the history of HTTP. +Let's take a quick trip through history: + +- **HTTP/1**: One request at a time per TCP connection. Want to load 10 images? You either suffer from head-of-line blocking or open 10 connections, each with an expensive TCP/TLS handshake. +- **HTTP/2**: Multiplexing! Multiple requests over one TCP connection. But wait... TCP still delivers bytes in order, so one lost packet blocks *everything*. We traded one form of head-of-line blocking for another. +- **HTTP/3**: Built on QUIC with multiplexed streams that are truly independent. A lost packet in one stream doesn't block the others. + +RTMP and HLS suffer from this same head-of-line blocking problem. +Old audio/video frames end up blocking new frames from being delivered, driving up latency during congestion. + +## Why Not Raw UDP? + +"Just use UDP" has been the rallying cry of real-time media for decades. +That's exactly the route that protocols like WebRTC and SRT have taken, but they incur a high complexity cost. +Every implementation needs custom encryption, congestion control, flow control, retransmissions, prioritization, NAT traversal, browser support, and more. + +Only Google (WebRTC) has managed to navigate these problems and create a solid protocol that works in browsers. +But despite all of the complexity, it can really only support a single use-case: conferencing. + +The point of MoQ is to avoid reinventing the wheel and focus on **media** instead of **networking**. +QUIC is a fantastic protocol with wide support and the features we need. + +## Features + +Speaking of features, here's a QUICk summary of the features MoQ relies on. + +### Streams + +After establishing a QUIC connection, both sides can create streams. +This is can be done instantly (without overhead) provided the configurable limit has not been reached. + +There's two flavors of streams: + +- **Bidirectional**: A stream that can be read from and written to. +- **Unidirectional**: A stream that can only be written to. + +Each stream is a reliable sequence of bytes, with any gaps automatically retransmitted. +A stream can be closed to mark the final size, or it can be reset (by either side) to immediately terminate it. + +In MoQ, we use bidirectional streams for control messages and unidirectional streams for subscription data. + +Each stream is *mostly* independent of each other, containing its own data and flow control. +A lost packet on stream A doesn't stall stream B, nor do they have to be retransmitted together. +Stream A can be closed or reset independently of stream B. + +In MoQ, we create a new stream for each video Group of Pictures. +All frames within a GoP are reliably delivered in order so the decoder will not error. +But Group A won't block Group B, nor will Track A block Track B. + +**NOTE**: Some other implementations use QUIC datagrams instead of streams. +This can make sense for real-time audio when retransmissions are not needed. + +### Reliability + +QUIC provides three flavors of reliability: + +- **Full Reliability**: A QUIC stream will be retransmitted until every byte arrives. Perfect for mandatory data like the catalog. +- **Partial Reliability**: A QUIC stream can be immediately RESET with an error code, aborting any forward progress. Perfect for skipping old video frames when you're behind - just reset the stream and move on. +- **No Reliability**: QUIC datagrams (an extension) can be sent without any queuing or retransmission. Fire and forget when retransmissions are not desired. + +MoQ primarily uses partial reliability, reseting streams once the content is no longer desired (max latency). +However, in order to support multiple different latency targets, we prefer to prioritize streams instead of resetting them. + +### Prioritization + +The QUIC library is responsible for constructing and sending each UDP packet. +This means a QUIC library can prioritize streams by deciding which packet to send next. + +This is useful in order to: + +- Prioritize audio over video +- Prioritize recent frames over old frames + +MoQ uses this extensively. +When the network is congested, old groups get starved while new groups get through immediately. +We'll eventually reset old groups once a maximum latency is reached, but it's better to prioritize than to reset. + +### Connection Migration + +Something we get for free is connection migration. +QUIC connections can survive IP address changes, such as switching from WiFi to cellular. + +This is because QUIC uses connection IDs rather than the traditional `IP:port` tuple. +It's also the basis for some pretty neat [load balancing](https://datatracker.ietf.org/doc/html/draft-ietf-quic-load-balancers) techniques. + +## Browser Support + +QUIC is available in browsers via [WebTransport](https://developer.mozilla.org/en-US/docs/Web/API/WebTransport_API): + +- **Chrome/Edge** - Supported since 2021 (97) +- **Firefox** - Supported since 2023 (114) +- **Safari** - Supported since 2026 (26.4) + +The late arrival of Safari support is a bit of a bummer, because the Safari version is tied to the OS version. +That means MacOS 26.4 and iOS 26.4 is the minimum version for Safari support. +We have an (automatic) WebSocket fallback in the meantime. + +## Security + +TLS 1.3 is required for QUIC. + +This can be annoying for local development and private networks. +There is some performance overhead of course, but the main problem is that you need TLS certificates. diff --git a/doc/concept/layer/web-socket.md b/doc/concept/layer/web-socket.md new file mode 100644 index 0000000000..1899a941f8 --- /dev/null +++ b/doc/concept/layer/web-socket.md @@ -0,0 +1,123 @@ +--- +title: WebSocket +description: A TCP fallback for corporate nerds who block QUIC, and Safari users. +--- + +# WebSocket + +I'm bored of writing so much documentation. +Check out the next page on [moq-lite](/concept/layer/moq-lite) instead; it's way more interesting. + +Here's some AI slop for now: + +## AI SLOP + +WebSocket is a TCP fallback for when QUIC/WebTransport isn't available. +This happens more often than you'd think: corporate firewalls love blocking UDP, and Safari didn't support WebTransport until 26.4. + +We use a thin polyfill called [web-transport-ws](https://github.com/moq-dev/web-transport/tree/main/rs/web-transport-ws) that emulates the WebTransport API over a WebSocket connection. +It multiplexes streams using a simple binary framing protocol, so the rest of the stack doesn't need to know or care that it's running over TCP. + +### How It Works + +When establishing a connection, the client races QUIC/WebTransport against WebSocket in parallel. +WebSocket wins the race when UDP is blocked or WebTransport isn't supported. + +The polyfill converts the URL scheme (`https://` → `wss://`, `http://` → `ws://`) and connects with the `webtransport` subprotocol. +Once connected, it provides the same API as WebTransport: bidirectional streams, unidirectional streams, and connection management. + +Obviously it won't perform as well as QUIC during congestion — everything gets head-of-line blocked over TCP. +But it's better than not working at all. + +### Streams + +Stream IDs are encoded as variable-length integers with the lower 2 bits indicating the stream type: + +| Bit 0 | Bit 1 | Type | +|-------|-------|------| +| 0 | 0 | Client-initiated bidirectional | +| 1 | 0 | Server-initiated bidirectional | +| 0 | 1 | Client-initiated unidirectional | +| 1 | 1 | Server-initiated unidirectional | + +This matches the [QUIC stream ID scheme](https://datatracker.ietf.org/doc/html/rfc9000#section-2.1). + +### Framing + +Each WebSocket binary message contains a single frame. +The frame type is identified by the first byte, borrowing values from the QUIC spec: + +#### `STREAM` (0x08) / `STREAM_FIN` (0x09) + +Carries data for a stream. `STREAM_FIN` indicates the final data on the stream. + +```text ++--------+-----------+---------+ +| Type | Stream ID | Payload | +| 1 byte | VarInt | ... | ++--------+-----------+---------+ +``` + +No length field is needed since WebSocket already provides message boundaries. + +#### `RESET_STREAM` (0x04) + +Abruptly terminates the sending side of a stream with an error code. + +```text ++--------+-----------+------------+ +| Type | Stream ID | Error Code | +| 1 byte | VarInt | VarInt | ++--------+-----------+------------+ +``` + +#### `STOP_SENDING` (0x05) + +Requests the peer stop sending on a stream. The peer should respond with a `RESET_STREAM`. + +```text ++--------+-----------+------------+ +| Type | Stream ID | Error Code | +| 1 byte | VarInt | VarInt | ++--------+-----------+------------+ +``` + +#### `APPLICATION_CLOSE` (0x1d) + +Gracefully closes the connection with an error code and reason. + +```text ++--------+------------+--------+ +| Type | Error Code | Reason | +| 1 byte | VarInt | UTF-8 | ++--------+------------+--------+ +``` + +### VarInt Encoding + +Variable-length integers use the [QUIC VarInt encoding](https://datatracker.ietf.org/doc/html/rfc9000#section-16). +The first two bits indicate the length: + +| Prefix | Length | Max Value | +|--------|--------|-----------| +| `00` | 1 byte | 63 | +| `01` | 2 bytes | 16,383 | +| `10` | 4 bytes | 1,073,741,823 | +| `11` | 8 bytes | 4,611,686,018,427,387,903 | + +### Limitations + +Let's be real: this is a polyfill, not a replacement. + +- **Head-of-line blocking**: TCP delivers bytes in order, so a lost packet stalls everything. The whole point of QUIC streams is to avoid this. +- **No prioritization**: The sender can't choose which stream gets bandwidth first. With QUIC, we prioritize new video over old video — over WebSocket, they're all stuck in line. +- **No partial reliability**: You can reset a logical stream, but the bytes already in the TCP buffer will still be delivered (and block everything behind them). + +It's good enough for low-congestion scenarios and ensures your app works everywhere. +For the best experience, use a browser that supports WebTransport. + +### Future + +There is a [WebTransport over HTTP/2 draft](https://datatracker.ietf.org/doc/html/draft-ietf-webtrans-http2-13) that could replace this WebSocket polyfill. +It's too little, too late for now, but maybe one day. +In the meantime, WebSocket is the only reliable fallback for Safari and older iOS devices. diff --git a/doc/concept/layer/web-transport.md b/doc/concept/layer/web-transport.md new file mode 100644 index 0000000000..30e014ba53 --- /dev/null +++ b/doc/concept/layer/web-transport.md @@ -0,0 +1,54 @@ +--- +title: WebTransport +description: The layer that makes MoQ browser compatible +--- + +# WebTransport + +[RFC9000](https://datatracker.ietf.org/doc/html/rfc9000) introduced QUIC and [RFC9114](https://datatracker.ietf.org/doc/html/rfc9114) introduced HTTP/3. + +However, HTTP/3 is not the only way to use QUIC in a browser. +HTTP semantics can make things awkward as the client needs to initiate each request; there's no (good) way for the server to push live content. + +WebTransport was created as an alternative to WebSockets, using QUIC instead of TCP. +It exposes more-or-less the same API as QUIC so it works great for MoQ. + +- [Network Specification](https://www.ietf.org/archive/id/draft-ietf-webtrans-http3-14.html) +- [Browser Specification](https://www.w3.org/TR/webtransport/) + +## Handshake + +WebTransport actually uses HTTP/3 under the hood. +A `CONNECT` request is sent by the client to the server, indicating it wants to establish a WebTransport session. +There's also an optional `protocol` header similar to ALPN and WebSocket's subprotocol. + +This sharing of a QUIC connection actually makes WebTransport a bit problematic. +HTTP/3 requests and other WebTransport sessions fight for resources, requiring extra management in the form of capsules. +Both sides negotiate the maximum number of WebTransport sessions that can be established on the same QUIC connection; my recommendation is to set it to 1. + +## API + +There are some subtle differences between the WebTransport API and the QUIC API. +Most of the time, you can assume they are the same, but there are some differences: + +1. **Stream ID Gaps**: Because WebTransport shares a connection, we can't always tell if a RESET stream was for a WebTransport session or a HTTP/3 request. +2. **Smaller Errors**: WebTransport supports a smaller set of error codes than QUIC. +3. **Browser API**: The [W3C API](https://developer.mozilla.org/en-US/docs/Web/API/WebTransport_API) is more limited than most QUIC libraries. + +Shameless plug: use my [web-transport](/lib/rs/crate/web-transport) libraries for Rust. +It implements most of the Quinn API so you can support both QUIC and WebTransport with minimal changes. + +## Why Not HTTP/3? + +MoQ could use HTTP/3 directly instead of WebTransport, but HTTP semantics make it awkward: + +- **With WebTransport**: both sides can create streams whenever and immediately write new frames. +- **With HTTP/3**: only the client can create a stream (HTTP request), as HTTP push is gone and a mistake anyway. The client needs to know when the server wants to write a new stream. + +[moq-relay](/bin/relay/) does provide an HTTP endpoint so a client can still request content on-demand instead of subscribing. +This is useful for backwards compatibility with HLS, but the long-term goal is to make publishing and subscribing symmetrical via WebTransport. + +## Native Clients + +Native MoQ clients can skip WebTransport entirely and use QUIC directly via an ALPN. +This avoids the HTTP/3 handshake overhead and the quirks of sharing a connection. diff --git a/doc/concept/standard/cmaf.md b/doc/concept/standard/cmaf.md new file mode 100644 index 0000000000..4967557494 --- /dev/null +++ b/doc/concept/standard/cmaf.md @@ -0,0 +1,6 @@ +--- +title: CMAF +description: Common Media Application Format (CMAF) for streaming media +--- + +TODO diff --git a/doc/concept/standard/index.md b/doc/concept/standard/index.md new file mode 100644 index 0000000000..9bc2eb0353 --- /dev/null +++ b/doc/concept/standard/index.md @@ -0,0 +1,47 @@ +--- +title: Standards +description: IETF drafts and protocol specifications +--- + +# Standards + +MoQ is a big tent, full of many different opinions and ideas. +I consider any media protocol that uses QUIC to be part of MoQ, even if it's part of a standards body or organization. + +Additionally, MoQ is experimental and not yet battle-tested, so expect all of these standards to change. +If you're interested in participating, join any of these communities and get involved. + +## IETF MoQ Working Group + +The IETF MoQ Working Group is the official standardization body for MoQ. +The group is primarily focusing on the [MoqTransport](/concept/standard/moq-transport) specification, but there's a number of other drafts too. + +There's no membership fee or criteria to join. +If you want to participate, you should show up to the regular online (and in-person) meetings. +Once you get more involved, jump into the excessive number of [GitHub issues](https://github.com/moq-wg/moq-transport/issues) and join the [mailing list](https://mailarchive.ietf.org/arch/browse/moq/). + +- [Working Group](https://datatracker.ietf.org/group/moq/about/) +- [Documents](https://datatracker.ietf.org/group/moq/documents/) +- [GitHub](https://github.com/moq-wg/moq-transport) + +## moq.dev + +[moq.dev](https://moq.dev) is an open-source implementation of MoQ primarily focused on production usage. + +The goal is to support compatibility with the IETF drafts, but not a full implementation. +The IETF process is slow and involves a lot of debate, discussion, and negotiation. +All of this is *on purpose* and produces a better standard in the end. + +But the standard is too immature, full of bloat, and there's too much churn. +If we had to gate every change behind IETF approval, it would take months to make even the smallest change. + +To that end, we've created a forwards-compatible subset of [MoqTransport](/concept/standard/moq-transport) called [moq-lite](/concept/layer/moq-lite). +moq-lite is forwards compatible with moq-transport, so it works with any moq-transport CDN (ex. [Cloudflare](https://moq.dev/blog/first-cdn)). + +On the media side, there are the [MSF](/concept/standard/msf) (catalog) and [LOC](/concept/standard/loc) (container) drafts. +They are too early/unstable to be useful, so we're using a custom [hang](/concept/layer/hang) media format instead. + +- [Website](https://moq.dev) +- [GitHub](https://github.com/moq-dev/moq) +- [Documentation](https://doc.moq.dev) +- [Discord](https://discord.gg/FCYF3p99mr) diff --git a/doc/concept/standard/interop.md b/doc/concept/standard/interop.md new file mode 100644 index 0000000000..af8f0ac972 --- /dev/null +++ b/doc/concept/standard/interop.md @@ -0,0 +1,90 @@ +# Interoperability + +Want to test some standards against this code? + +It's recommended that you run the code locally for easier debugging. See the [Setup Guide](/setup/dev), it's pretty easy. + +## Transport + +[moq-lite](/concept/layer/moq-lite) is a forwards-compatible subset of moq-transport. +A moq-lite client can talk to any moq-transport relay, but not necessarily the other way around. + +### Versions + +- moq-transport-14 +- moq-transport-15 (untested) +- moq-transport-16 +- moq-transport-17 + +### Protocols + +- WebTransport +- QMux over WebSocket +- (Rust) QUIC +- (Rust) QMux over TLS + +### Client + +If you want to test your relay: + +```bash +# Rust: Publishes a media broadcast +just pub bbb https:// + +# Javascript: Subscribes to a media broadcast +just web https:// +``` + +> **Note:** WebTransport automatically prepends the URL path (e.g., `/anon`) to broadcast names. Raw QUIC and iroh have no HTTP layer, so you must manually include that prefix in the broadcast name (e.g., publish as `/anon/bbb`). + +The publisher sends a `PUBLISH_NAMESPACE` and the subscriber **requires** a `SUBSCRIBE_NAMESPACE`. +If you haven't implemented the latter yet, remove `reload` in `demo/web/src/index.html`. + +**Feeling spicy?** +You can use [gstreamer](/bin/gstreamer) or [obs](/bin/obs) too, both support publishing and subscribing. +There's also bindings for Rust, Javascript, C, Python, Kotlin, Swift, etc. + +### Relay + +The relay is less useful to test against because we purposely implement a shallow subset of the moq-transport draft. + +```bash +# Rust: Runs a localhost relay +# Also available at: https://cdn.moq.dev/anon +just relay +``` + +The relay **WILL IGNORE** the following: + +- Any sub-group >0 +- Any datagrams +- Any FETCH, except JOINING FETCH is a no-op. +- Any objects with delta >0 (must be contiguous) +- Any object properties +- Any SUBSCRIBE `forward=0` +- Any multi-publisher nonsense +- Probably some other stuff + +Note that all subscriptions start at the latest group. + +## Media + +I'm primarily using `hang`, which is like a mix between MSF + LOC. +I'd love to standardize eventually but I need more media homies that want to interop, not just write a spec. + +### Rust + +The publisher currently makes two catalog tracks pointing to the same media tracks: + +- `catalog.json` ([hang](/concept/layer/hang)) +- `catalog` ([MSF](/concept/standard/msf)) + +We support two possible containers, but currently `cmaf` is experimental: + +- `legacy` ([hang](/concept/layer/hang)) +- `cmaf` ([CMAF](/concept/standard/cmaf)) + +### Javascript + +The Javascript code currently only supports `catalog.json`. +However, the subscriber can consume both `legacy` and `cmaf` containers diff --git a/doc/concept/standard/loc.md b/doc/concept/standard/loc.md new file mode 100644 index 0000000000..0ae41c600c --- /dev/null +++ b/doc/concept/standard/loc.md @@ -0,0 +1,14 @@ +--- +title: LOC - Low Overhead Container +description: A low-overhead container format for MoQ. +--- + +# LOC - Low Overhead Container + +We originally wanted to use [CMAF](/concept/standard/msf) but there's a lot of overhead. +Like 100 bytes per frame sort of overhead (`moof` + `mdat`), the type of overhead that kills audio-only streams. + +LOC is a super simple container format that's designed to be lightweight. +It's similar to the [hang container](../layer/hang) and we'll probably merge them in the future. + +[See the draft](https://www.ietf.org/archive/id/draft-ietf-moq-loc-00.html) for the latest details. diff --git a/doc/concept/standard/moq-transport.md b/doc/concept/standard/moq-transport.md new file mode 100644 index 0000000000..f7688ead9b --- /dev/null +++ b/doc/concept/standard/moq-transport.md @@ -0,0 +1,110 @@ +--- +title: MoqTransport +description: The generic pub/sub protocol that powers everything. +--- + +# MoqTransport + +The generic pub/sub protocol that powers everything. +It doesn't know anything about media - it just moves bytes around really efficiently. +CDNs implement this layer, and it's designed to scale to millions of subscribers. + +This guide assumes that you are familiar with [moq-lite](/concept/layer/moq-lite). +Many of the concepts are the same and it's easier to point out the differences rather than start from scratch. + +- [Latest Draft](https://datatracker.ietf.org/doc/draft-ietf-moq-transport/) + +## Model + +### Namespace + +A named collection of related **tracks**, called a `Broadcast` in moq-lite. +Each namespace is identified by an array of byte arrays, but most people use an array of strings. + +Everything is scoped, so if you `SUBSCRIBE_NAMESPACE` to `["sports", "nba"]` you'll also get `["sports", "nba", "highlights"]`. +MoqTransport also has the `forward=1` flag to automatically subscribe to any `PUBLISH`'d tracks in the namespace. + +Unlike moq-lite, a namespace *could* be shared by multiple publishers. +However, I don't think CDNs will ever implement this feature due to conflicts/complexity/bugs. + +### Track + +A named collection of **groups**, potentially served out-of-order. +Each track is identified by a byte array, but most people use a string. + +Each subscription is scoped to a single track. +Unlike moq-lite, a track can have multiple publishers. +Again, I don't think a CDN will ever implement this due to conflicts/complexity/bugs. + +### Group + +A collection of **sub-groups**, potentially served out-of-order. +Each group is identified by a monotonically increasing group ID, with gaps allowed. + +### Sub-Group + +A collection of **frames**, served in order over a single QUIC stream. +Each sub-group is identified by a sub-group ID, where 0 is considered the base layer. + +Sub-groups are intended for layered encodings (SVC), such that an enhancement layer can be dropped without affecting a base layer. +In moq-lite, you would make a separate track for each layer so you can select/prioritize them independently. + +### Object + +The smallest unit in MoQ: a sized chunk of data. +Each object is identified by a monotonically increasing object ID. + +Unlike moq-lite, there may be both explicit and implicit gaps in the object ID. +There are also "Object Properties" that can be used to store K/V metadata pairs. + +## Request + +MoqTransport has a bunch of different request types, each with a different purpose. +They are identified by a request ID and have corresponding \_OK and \_ERROR responses. + +Note that `moq-lite` contains the equivalent of: `SUBSCRIBE` and `SUBSCRIBE_NAMESPACE`. +The other requests are unique to MoqTransport. + +### SUBSCRIBE + +Allows access to future objects. +When a new object is available, each active subscriber will receive a copy of it over the corresponding sub-group QUIC stream. + +Unlike moq-lite, a subscription starts at the latest object within a group, not the first object. +This is quite annoying because you have to issue a `JOINING FETCH` request to get the earlier objects within the group (ex. the I-frame). + +Unlike moq-lite, there is a `forward=0` flag to pause a subscription. + +### PUBLISH + +A publisher can start pushing subscription data rather than waiting for a `SUBSCRIBE`. + +This can avoid a round-trip when the peer definitely wants to receive the track. +It can also be used to discover track names, as that information is not available in `PUBLISH_NAMESPACE` + +### SUBSCRIBE\_NAMESPACE + +Announces that a namespace is newly available or unavailable. +There's no information about the tracks within the namespace. + +Unlike moq-lite, there is a `forward=1` flag to automatically receive any `PUBLISH`'d tracks in the namespace. + +### PUBLISH\_NAMESPACE + +Announces the availability of a namespace. +There's no information about the tracks within the namespace. + +Unlike moq-lite, this can be sent without a corresponding `SUBSCRIBE_NAMESPACE`. + +### FETCH + +Allows access to past objects. +All objects that match the provided range will be delivered in Group ID, Object ID order over a single QUIC stream. + +FETCH appears nice on paper, but there are numerous issues due to the HoLB blocking and implicit gaps. +I would strongly encourage fetching objects via HTTP or some other mechanism for now. + +### JOINING FETCH + +A special variant of FETCH that is relative to an existing subscription. +This is used to get the prior objects within a group (ex. the I-frame). diff --git a/doc/concept/standard/msf.md b/doc/concept/standard/msf.md new file mode 100644 index 0000000000..ceefbda891 --- /dev/null +++ b/doc/concept/standard/msf.md @@ -0,0 +1,15 @@ +--- +title: MSF - MoQ Streaming Format +description: A catalog format for MoQ. +--- + +# MSF - MoQ Streaming Format + +HLS/DASH playlists suck. +WebRTC SDP is even worse. +MSF is a replacement for both, utilizing MoQ live streams. + +[MSF](https://www.ietf.org/archive/id/draft-ietf-moq-msf-00.html) is a catalog format for MoQ. +It's similar to the [hang catalog](../layer/hang) and we'll probably merge them in the future. + +[See the draft](https://www.ietf.org/archive/id/draft-ietf-moq-msf-00.html) for the latest details. diff --git a/doc/concept/use-case/ai.md b/doc/concept/use-case/ai.md new file mode 100644 index 0000000000..4eb9ace38c --- /dev/null +++ b/doc/concept/use-case/ai.md @@ -0,0 +1,79 @@ +--- +title: AI +description: Welcome to the future, old man. +--- + +# AI + +Hopefully you had this square on your buzzword bingo card. + +WebRTC is a great protocol for conferencing, but it's not designed for AI. +But I haven't personally worked in this space either so take my suggestions with a grain of salt. + +## Latency + +Inference is still quite slow and expensive, even for the big players. +If you're going to spend >300ms and literal dollars on expensive inference, you want at least *some* reliability guarantees. + +Unfortunately, WebRTC will never try to retransmit audio packets. +A single lost packet will cause noticeable audio distortion. +And if you have the audacity to generate audio/video separately, WebRTC won't synchronize them for you. +Frames are rendered on receipt, so unless you introduce a delay, audio will be out of sync with video. + +One of the core tenets of MoQ is adjustable latency. +The viewer (and thus your application) controls how long it's willing to wait for content before it gets skipped/desynced. +The latency budget of the network protocol can match the latency budget of the application. + +## On-Demand + +MoQ is pull-based, so nothing is transmitted over the network until there's at least one subscriber. +You can further extend this by not generating/encoding content either. + +Both of these were mentioned briefly on the [contribution](/concept/use-case/contribution) page if you want to read more. + +### Inference + +If you want to save compute resources, you can defer inference until it's actually needed. + +For example, let's say you're publishing a `captions` track populated by Whisper or something. +If nobody has enabled captions, then nobody will subscribe to the `captions` track. +You can stop generating the track (or use a smaller model) until it's actually requested. + +### Simulcast + +If you want to save bandwidth, you can publish media in a format expected by the AI model. + +For example, let's say you're doing object detection on a bunch of security cameras. +The model inputs video at 360p and 10fps or something like that, so that's what you publish. +But if a human (those still exist) wants to audit the full video, you can separately serve the full resolution video. +Since this is on-demand, you will only encode/transmit the 1080p video when it's actually needed. + +## Browser Control + +One of the perks of using WebSockets/MoQ instead of WebRTC is that you get full control over the media pipeline. + +[WebCodecs](https://developer.mozilla.org/en-US/docs/Web/API/WebCodecs_API) is used to encode/decode media within the browser. + +- For video, you use [VideoFrame](https://developer.mozilla.org/en-US/docs/Web/API/VideoFrame) which directly maps to a texture on the GPU. You can use WebGPU to perform inference, encoding, rendering, etc without ever touching the CPU. +- For audio, you get [AudioData](https://developer.mozilla.org/en-US/docs/Web/API/AudioData) which is (usually) just a float32 array. You control exactly how these are processed, captured, emitted, etc. + +It's more work to do this instead of using a `