diff --git a/.github/workflows/api-diff.yml b/.github/workflows/api-diff.yml new file mode 100644 index 00000000000..e1ae4853d50 --- /dev/null +++ b/.github/workflows/api-diff.yml @@ -0,0 +1,54 @@ +name: API diff + +# Diffs every published API against its last release on PRs into `release`. +# A backport fails on any break, since it must keep the published API. The cut +# (a PR from `main`) only reports, for the migration audit: release-plz bumps +# the versions after it lands, so its breaks are expected. +permissions: + contents: read + +on: + workflow_call: + +concurrency: + group: api-diff-${{ github.ref }} + cancel-in-progress: true + +jobs: + diff: + name: Public API + runs-on: ubuntu-24.04-arm + # cargo-semver-checks documents every published crate twice, baseline and current. + timeout-minutes: 120 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: ./.github/actions/nix + - uses: ./.github/actions/rust-cache + with: + access-key-id: ${{ secrets.MBX_R2_ACCESS_KEY_ID }} + secret-access-key: ${{ secrets.MBX_R2_SECRET_ACCESS_KEY }} + # The JS baseline is the API reports committed on `release`. + - name: Fetch release + run: git fetch --no-tags --depth=1 origin +refs/heads/release:refs/remotes/origin/release + - name: Diff against the last release + id: diff + run: | + mode=(--deny) + # Only this repository's own `main` is the cut; a fork's `main` is a backport. + [[ "$HEAD_REF" != main || "$HEAD_REPO" != "$GITHUB_REPOSITORY" ]] || mode=() + nix develop --command just api-diff "${mode[@]}" + env: + HEAD_REF: ${{ github.head_ref }} + HEAD_REPO: ${{ github.event.pull_request.head.repo.full_name }} + # Lists and downloads the moq-c and moq-ffi release assets. + GH_TOKEN: ${{ github.token }} + - name: Keep the report + if: ${{ !cancelled() && steps.diff.outcome != 'skipped' }} + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7 + with: + name: api-diff + path: target/api-diff/ + retention-days: 30 + if-no-files-found: error diff --git a/.github/workflows/release-gate.yml b/.github/workflows/release-gate.yml index 8b0d8ac4816..1ce89a0f6da 100644 --- a/.github/workflows/release-gate.yml +++ b/.github/workflows/release-gate.yml @@ -30,6 +30,7 @@ jobs: timeout-minutes: 10 outputs: android: ${{ steps.filter.outputs.android }} + api-diff: ${{ steps.filter.outputs.api-diff }} audio-quality: ${{ steps.filter.outputs.audio-quality }} cpp: ${{ steps.filter.outputs.cpp }} interop: ${{ steps.filter.outputs.interop }} @@ -82,6 +83,20 @@ jobs: - "Cargo.lock" - "rust-toolchain.toml" - ".github/workflows/android.yml" + # Anything a published API is built from, including the lockfiles, + # since a bumped dependency can change a re-exported type. + api-diff: + - "rs/**" + - "js/**" + - "Cargo.toml" + - "Cargo.lock" + - "package.json" + - "bun.lock" + - "cpp/moq/uniffi.toml" + - "sh/api-diff/**" + - "justfile" + - ".github/workflows/api-diff.yml" + - ".github/workflows/release-gate.yml" audio-quality: - "js/watch/**" # The container consumer decides what a replay delivers, waits for, and skips, on the @@ -318,6 +333,13 @@ jobs: if: needs.scope.outputs.android == 'true' uses: ./.github/workflows/android.yml + api-diff: + name: API diff + needs: scope + if: needs.scope.outputs.api-diff == 'true' + uses: ./.github/workflows/api-diff.yml + secrets: inherit + audio-quality: name: Audio quality needs: scope @@ -469,6 +491,7 @@ jobs: - platform - features - android + - api-diff - audio-quality - cpp - interop diff --git a/.remarkignore b/.remarkignore index 3598de8537d..61765bd7fa4 100644 --- a/.remarkignore +++ b/.remarkignore @@ -9,6 +9,9 @@ pkg/ result **/CHANGELOG.md +# API Extractor reports, generated and checked by each package's build. +js/*/api/*.api.md + # IETF drafts are kramdown-rfc markdown, not CommonMark; linted by `just # drafts check` (kramdown-rfc) instead. doc/draft/ is generated from them by # doc/.vitepress/drafts.ts. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f9f56e23177..1a2ec1d343f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -95,7 +95,7 @@ For an advisory against Quinn, follow the advisory triage in [`rs/moq-quic/READM - A release is cut by hand: a PR merging `main` into `release`, with a merge commit. - A breaking cut first writes, on `main`, each changed package's version-transition section in its `MIGRATE.md` (`## 0.3 -> 0.4`) from the migration audit: the `!` subjects since the `release` merge base, each of those PRs' Impact section, and the API diff. -- Suggest a `release` backport for any serious bug fix (crash, security, data loss, broken interop), whether found on `main` or reported against a release. Land it on `main` first, then port it onto `release` as a separate PR that keeps the published API, so it ships as a patch. +- Suggest a `release` backport for any serious bug fix (crash, security, data loss, broken interop), whether found on `main` or reported against a release. Land it on `main` first, then port it onto `release` as a separate PR that keeps the published API, so it ships as a patch. The Release gate's API diff (`just api-diff --deny`) fails a backport that changes one; on the cut PR, whose head is `main`, it only reports. - After any release publishes, patch or breaking, run `just test wire-compat --remeasure` on `main` and land the rewritten `test/interop/compat/planned-breaks.json` with refreshed reasons. Otherwise the nightly wire-compat check fails on the stale pins. - Nothing merges `release` into `main` automatically. Before cutting a minor or breaking release, the maintainer merges `release` into `main` once, so trunk carries the published versions, CHANGELOGs, and any `release`-only commits. It lands as a merge commit with `--admin`, never squashed, so the cut starts from an advanced merge base. diff --git a/bun.lock b/bun.lock index 11df5291611..bfec4f2844b 100644 --- a/bun.lock +++ b/bun.lock @@ -7,6 +7,7 @@ "devDependencies": { "@babel/parser": "^8.0.7", "@biomejs/biome": "^2.5.15", + "@microsoft/api-extractor": "7.59.4", "concurrently": "^10.0.6", "markdown-extensions": "^2.0.0", "publint": "^0.3.25", @@ -821,6 +822,14 @@ "@libav.js/types": ["@libav.js/types@6.10.9", "", {}, "sha512-AdngxD/VO8OI6/w7wlJC77kuFcsSvCUuo2RuC6gGeSW2DEvbzgBo2JtFLV6UWZp/tRNZhKm6jS0Tv8gwCKBHLg=="], + "@microsoft/api-extractor": ["@microsoft/api-extractor@7.59.4", "", { "dependencies": { "@microsoft/api-extractor-model": "7.33.15", "@microsoft/tsdoc": "~0.17.0", "@microsoft/tsdoc-config": "~0.18.2", "@rushstack/node-core-library": "5.25.1", "@rushstack/rig-package": "0.7.4", "@rushstack/terminal": "0.24.7", "@rushstack/ts-command-line": "5.3.17", "diff": "~8.0.2", "minimatch": "10.2.3", "resolve": "~1.22.1", "semver": "~7.7.4", "source-map": "~0.6.1", "typescript": "5.9.3" }, "bin": { "api-extractor": "bin/api-extractor" } }, "sha512-XqseDKIw736qlhQwS9SOpbY4veOiP2Nc7YiWmgXXBmeA3kY9qGXw+Tu7DFpU9FvXywE1z8SvLJKUVxFpcX0kig=="], + + "@microsoft/api-extractor-model": ["@microsoft/api-extractor-model@7.33.15", "", { "dependencies": { "@microsoft/tsdoc": "~0.17.0", "@microsoft/tsdoc-config": "~0.18.2", "@rushstack/node-core-library": "5.25.1" } }, "sha512-UpCnItIJwu03iNTWtJVKv8Qbf0MXN7WLQZUail9cpAQmnZiIX36YPRRoRxz0pocwytzUpmJhstsLkyW5tsaHBA=="], + + "@microsoft/tsdoc": ["@microsoft/tsdoc@0.17.1", "", {}, "sha512-VHyYyyoH63jFoO3shpw9Zfijk5v/9p/VrClW35z0/q6ooK7sSmxpzOkS4iZPxs3vO4XtBW4H38HRAKkAMIK7DA=="], + + "@microsoft/tsdoc-config": ["@microsoft/tsdoc-config@0.18.3", "", { "dependencies": { "@microsoft/tsdoc": "0.17.1", "ajv": "~8.18.0", "jju": "~1.4.0", "resolve": "~1.22.2" } }, "sha512-0I0rGXo1eJziw3EEErkDS9p/0RzBcyOiV+zbSDqOZTeURmhtut+WIvpih0LM5g+ZpZ9SyFxDfkhAcl/r8e2zGw=="], + "@moq/audio-quality": ["@moq/audio-quality@workspace:test/audio-quality/clients/js"], "@moq/auth": ["@moq/auth@workspace:js/auth"], @@ -1007,6 +1016,16 @@ "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.62.2", "", { "os": "win32", "cpu": "x64" }, "sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA=="], + "@rushstack/node-core-library": ["@rushstack/node-core-library@5.25.1", "", { "dependencies": { "ajv": "~8.20.0", "ajv-draft-04": "~1.0.0", "ajv-formats": "~3.0.1", "fs-extra": "~11.3.0", "import-lazy": "~4.0.0", "jju": "~1.4.0", "resolve": "~1.22.1", "semver": "~7.7.4" }, "peerDependencies": { "@types/node": "*" }, "optionalPeers": ["@types/node"] }, "sha512-ozoRDwIx3jStOYpx86rFyXH4SaUR+DVT6HubQ59avLplJkWXSm5InztYH7RrOzzq9PJXTdq9/+lKX06SfkLVsA=="], + + "@rushstack/problem-matcher": ["@rushstack/problem-matcher@0.2.1", "", { "peerDependencies": { "@types/node": "*" }, "optionalPeers": ["@types/node"] }, "sha512-gulfhBs6n+I5b7DvjKRfhMGyUejtSgOHTclF/eONr8hcgF1APEDjhxIsfdUYYMzC3rvLwGluqLjbwCFZ8nxrog=="], + + "@rushstack/rig-package": ["@rushstack/rig-package@0.7.4", "", { "dependencies": { "jju": "~1.4.0", "resolve": "~1.22.1" } }, "sha512-SHZdzc9b2ptUb5uvRWALtAceD/QKZ4UAnZjcaKviTMPmHBnW14gs7XDocn6sDv2EqgnxxFPFkpV7/I3cUijCbw=="], + + "@rushstack/terminal": ["@rushstack/terminal@0.24.7", "", { "dependencies": { "@rushstack/node-core-library": "5.25.1", "@rushstack/problem-matcher": "0.2.1", "supports-color": "~8.1.1" }, "peerDependencies": { "@types/node": "*" }, "optionalPeers": ["@types/node"] }, "sha512-o8J9nHOIwfYb0s0eG2WYhx7ed3YIvBXQHVFxYdXCmVdBOkTkdArJcgVzRS8ewUepmlic4nGgJPjKIVaNKSqEnA=="], + + "@rushstack/ts-command-line": ["@rushstack/ts-command-line@5.3.17", "", { "dependencies": { "@rushstack/terminal": "0.24.7", "@types/argparse": "1.0.38", "argparse": "~1.0.9", "string-argv": "~0.3.1" } }, "sha512-pIwhWawZXAT0nTXwvcE/InQ7uaVAgSeIzILMb2mBrI01Hz1yEvxrhV2+DE2Fzux8aZY9OJTdLsI+sk9kZDuAJw=="], + "@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=="], "@shikijs/engine-javascript": ["@shikijs/engine-javascript@2.5.0", "", { "dependencies": { "@shikijs/types": "2.5.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^3.1.0" } }, "sha512-VjnOpnQf8WuCEZtNUdjjwGUbtAVKuZkVQ/5cHy/tojVVRIRtlWMYVjyWhxOmIq05AlSOv72z7hRNRGVBgQOl0w=="], @@ -1059,6 +1078,8 @@ "@tailwindcss/vite": ["@tailwindcss/vite@4.3.3", "", { "dependencies": { "@tailwindcss/node": "4.3.3", "@tailwindcss/oxide": "4.3.3", "tailwindcss": "4.3.3" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7 || ^8" } }, "sha512-yYU8cogLeSh/ms2jh8Fj7jaba/EWa7Ja6GoUqYZaraEuCI5YS6ms6ObZgjjedm+jm6XZjdNRWBpPP6Z86oOxcw=="], + "@types/argparse": ["@types/argparse@1.0.38", "", {}, "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA=="], + "@types/audioworklet": ["@types/audioworklet@0.0.100", "", {}, "sha512-mWt4Z5CWi0CupDnSYWJgx6dw61XUk9JSRGrM9F/YNrpOoY/0XG+sxP+8rAjQq80H4febOe8PrzGmmN/X3w8LsQ=="], "@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=="], @@ -1197,13 +1218,19 @@ "abbrev": ["abbrev@2.0.0", "", {}, "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ=="], + "ajv": ["ajv@8.18.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A=="], + + "ajv-draft-04": ["ajv-draft-04@1.0.0", "", { "peerDependencies": { "ajv": "^8.5.0" }, "optionalPeers": ["ajv"] }, "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw=="], + + "ajv-formats": ["ajv-formats@3.0.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="], + "algoliasearch": ["algoliasearch@5.55.1", "", { "dependencies": { "@algolia/abtesting": "1.21.1", "@algolia/client-abtesting": "5.55.1", "@algolia/client-analytics": "5.55.1", "@algolia/client-common": "5.55.1", "@algolia/client-insights": "5.55.1", "@algolia/client-personalization": "5.55.1", "@algolia/client-query-suggestions": "5.55.1", "@algolia/client-search": "5.55.1", "@algolia/ingestion": "1.55.1", "@algolia/monitoring": "1.55.1", "@algolia/recommend": "5.55.1", "@algolia/requester-browser-xhr": "5.55.1", "@algolia/requester-fetch": "5.55.1", "@algolia/requester-node-http": "5.55.1" } }, "sha512-FyaFnnsbVPtevQwqSj/SdxE3jAsSsY0BEH8IVLf9rXxEBdAhAmT6VKCVSMWoaPIHVN1Eufh/1w8q6k8URpIkWw=="], "ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], "ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], - "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], + "argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], "async-mutex": ["async-mutex@0.5.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA=="], @@ -1293,6 +1320,8 @@ "devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "^2.0.0" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="], + "diff": ["diff@8.0.4", "", {}, "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw=="], + "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], "electron-to-chromium": ["electron-to-chromium@1.5.459", "", {}, "sha512-4SC9HHSFjO/liAhifpdOL5hG9b4BP7/5G3y3UPZVO8trlAXr1CaUEEJL0gWK3kOcYcZrOA5rkwG45Gra/lTIgg=="], @@ -1311,6 +1340,8 @@ "error-stack-parser-es": ["error-stack-parser-es@1.0.5", "", {}, "sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA=="], + "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], + "esbuild": ["esbuild@0.28.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.2", "@esbuild/android-arm": "0.28.2", "@esbuild/android-arm64": "0.28.2", "@esbuild/android-x64": "0.28.2", "@esbuild/darwin-arm64": "0.28.2", "@esbuild/darwin-x64": "0.28.2", "@esbuild/freebsd-arm64": "0.28.2", "@esbuild/freebsd-x64": "0.28.2", "@esbuild/linux-arm": "0.28.2", "@esbuild/linux-arm64": "0.28.2", "@esbuild/linux-ia32": "0.28.2", "@esbuild/linux-loong64": "0.28.2", "@esbuild/linux-mips64el": "0.28.2", "@esbuild/linux-ppc64": "0.28.2", "@esbuild/linux-riscv64": "0.28.2", "@esbuild/linux-s390x": "0.28.2", "@esbuild/linux-x64": "0.28.2", "@esbuild/netbsd-arm64": "0.28.2", "@esbuild/netbsd-x64": "0.28.2", "@esbuild/openbsd-arm64": "0.28.2", "@esbuild/openbsd-x64": "0.28.2", "@esbuild/openharmony-arm64": "0.28.2", "@esbuild/sunos-x64": "0.28.2", "@esbuild/win32-arm64": "0.28.2", "@esbuild/win32-ia32": "0.28.2", "@esbuild/win32-x64": "0.28.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA=="], "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], @@ -1325,6 +1356,10 @@ "fast-check": ["fast-check@4.10.2", "", { "dependencies": { "pure-rand": "^8.0.0" } }, "sha512-iK2f+YrcmoeGqk6fA0ea2bptcu/itMIm4NfEozq6N25+aG6h7s5HZbB/k1aV7b5w5sFLMCbbtRUsTVR+BgC3xw=="], + "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], + + "fast-uri": ["fast-uri@3.1.9", "", {}, "sha512-hS/0Wt3Ya043oKXs0sIxrMpKQITXhMLIrVAKKXi4gozGC9v7YRWVnXIZzjNPTO02M9BdxLCWqK1yRXgNziVyJQ=="], + "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=="], @@ -1337,8 +1372,12 @@ "format": ["format@0.2.2", "", {}, "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww=="], + "fs-extra": ["fs-extra@11.3.6", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-w8ZNZr2mKIc7qeNaQ9AVPT1+iFaI+Avd4xudVOvdDJ8VytREi1Ft5Ih7hd9jjehod8vAM5GMsfQ/TpPf4EyoEA=="], + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], + "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=="], @@ -1349,6 +1388,10 @@ "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + + "hasown": ["hasown@2.0.4", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A=="], + "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=="], @@ -1365,6 +1408,8 @@ "ignore": ["ignore@6.0.2", "", {}, "sha512-InwqeHHN2XpumIkMvpl/DCJVrAHgCsG5+cn1XlnLWGwtZBm8QJfSusItfrwx81CTp5agNZqpKU2J/ccC5nGT4A=="], + "import-lazy": ["import-lazy@4.0.0", "", {}, "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw=="], + "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=="], @@ -1377,6 +1422,8 @@ "is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="], + "is-core-module": ["is-core-module@2.17.0", "", { "dependencies": { "hasown": "^2.0.4" } }, "sha512-J/vG0zBCbIKOQFfufSwyXdMrsohyJIUNkrnmo6WZGzoM7tr/lsbfW5b2BvisL6zsyMzK9UxV9L6c7AoFbyXHOA=="], + "is-decimal": ["is-decimal@2.0.1", "", {}, "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A=="], "is-docker": ["is-docker@3.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="], @@ -1405,6 +1452,8 @@ "jiti": ["jiti@2.7.0", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ=="], + "jju": ["jju@1.4.0", "", {}, "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA=="], + "jose": ["jose@6.2.12", "", {}, "sha512-9NiFmJEex0sy2Dk58j2UGBSHgUs2ypF9eZSu4L6vjOX3Dp96Sw1F3uL+H+D1sx02jZZdzUT0HgvCy59CuvXcWw=="], "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], @@ -1415,8 +1464,12 @@ "json-parse-even-better-errors": ["json-parse-even-better-errors@3.0.2", "", {}, "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ=="], + "json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], + "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], + "jsonfile": ["jsonfile@6.2.1", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q=="], + "kind-of": ["kind-of@6.0.3", "", {}, "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="], "kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="], @@ -1547,7 +1600,7 @@ "miniflare": ["miniflare@5.20261012.0-beta", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "sharp": "0.35.5", "undici": "7.29.1", "workerd": "1.20261012.1", "ws": "8.21.0", "youch": "4.1.0-beta.10" } }, "sha512-Cjrs+vHHQ7krLO4HYELYpYBJBuMhcnNZD/Z5z/UcQSnFqWSQY3DhtTCFalXgI1/yO1iK+YrRKK8EYkumrEopxg=="], - "minimatch": ["minimatch@10.2.6", "", { "dependencies": { "brace-expansion": "^5.0.8" } }, "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A=="], + "minimatch": ["minimatch@10.2.3", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-Rwi3pnapEqirPSbWbrZaa6N3nmqq4Xer/2XooiOKyV3q12ML06f7MOuc5DVH8ONZIFhwIYQ3yzPH4nt7iWHaTg=="], "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], @@ -1597,6 +1650,8 @@ "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], + "path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="], "path-to-regexp": ["path-to-regexp@6.3.0", "", {}, "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ=="], @@ -1727,6 +1782,10 @@ "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], + "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], + + "resolve": ["resolve@1.22.13", "", { "dependencies": { "es-errors": "^1.3.0", "is-core-module": "^2.17.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-Dj/cW9zBV2aRj6XzCxuGIs3ESZKv02jixne3q6jFZYZ3/Tg09gHHviSMDL4kObh9pqSahdRHEnDoaP2gn8YLhA=="], + "retry": ["retry@0.12.0", "", {}, "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow=="], "rfdc": ["rfdc@1.4.1", "", {}, "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="], @@ -1749,7 +1808,7 @@ "section-matter": ["section-matter@1.0.0", "", { "dependencies": { "extend-shallow": "^2.0.1", "kind-of": "^6.0.0" } }, "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA=="], - "semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], "seroval": ["seroval@1.6.11", "", {}, "sha512-hpb6XnMCGN/A+79Uf8V7/iTGkyyyazNn5X0CoCAp7Uy9vT3RT8jZ9GLcnxGoVjg3P8AArbe4ZVHq6C8oT2a0kA=="], @@ -1771,6 +1830,8 @@ "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=="], + "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + "source-map-js": ["source-map-js@1.2.2", "", {}, "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw=="], "space-separated-tokens": ["space-separated-tokens@2.0.2", "", {}, "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="], @@ -1785,6 +1846,10 @@ "speakingurl": ["speakingurl@14.0.1", "", {}, "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ=="], + "sprintf-js": ["sprintf-js@1.0.3", "", {}, "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="], + + "string-argv": ["string-argv@0.3.2", "", {}, "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q=="], + "string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], "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=="], @@ -1801,6 +1866,8 @@ "supports-color": ["supports-color@10.2.2", "", {}, "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g=="], + "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], + "tabbable": ["tabbable@6.5.0", "", {}, "sha512-wieBHXygIm7OyQOu5hQlkk62/WyCFYGlWg7L6/ZCUZwx0o398Zkn4pVmMyfYhfMG8kGrj/Krt8eIk6UKC6VzwA=="], "tailwindcss": ["tailwindcss@4.3.3", "", {}, "sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ=="], @@ -1863,6 +1930,8 @@ "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=="], + "update-browserslist-db": ["update-browserslist-db@1.3.4", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-t8wonIOdQyOjtPd2VktlBu6QjTVTks6v8bSi7kd0r2Vll8TK1JYDZtRRdbmCHOAMphkZgrzK+L+vXK4pyZ8t4A=="], "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], @@ -1937,12 +2006,16 @@ "@babel/core/@babel/types": ["@babel/types@7.29.7", "", { "dependencies": { "@babel/helper-string-parser": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7" } }, "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA=="], + "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "@babel/generator/@babel/parser": ["@babel/parser@7.29.9", "", { "dependencies": { "@babel/types": "^7.29.8" }, "bin": "./bin/babel-parser.js" }, "sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA=="], "@babel/generator/@babel/types": ["@babel/types@7.29.7", "", { "dependencies": { "@babel/helper-string-parser": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7" } }, "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA=="], "@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], + "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "@babel/helper-module-imports/@babel/types": ["@babel/types@7.29.7", "", { "dependencies": { "@babel/helper-string-parser": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7" } }, "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA=="], "@babel/helper-module-transforms/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.29.7", "", {}, "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg=="], @@ -1963,6 +2036,8 @@ "@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=="], + "@microsoft/api-extractor/typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + "@npmcli/config/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], "@npmcli/git/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], @@ -1981,6 +2056,10 @@ "@npmcli/promise-spawn/which": ["which@4.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg=="], + "@rushstack/node-core-library/ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="], + + "@rushstack/terminal/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], + "@tailwindcss/node/lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.11.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" }, "bundled": true }, "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ=="], @@ -2031,6 +2110,8 @@ "@vue/server-renderer/@vue/shared": ["@vue/shared@3.5.44", "", {}, "sha512-H82XLH0DjmSOdbEwO15x3QTo1f5PWEtv237eLpYKc0mqLu+B8hnq16lFWmuBmNurkeiG3wr+oM1FhOll/YVFRg=="], + "ajv-formats/ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="], + "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=="], "babel-plugin-jsx-dom-expressions/@babel/types": ["@babel/types@7.29.7", "", { "dependencies": { "@babel/helper-string-parser": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7" } }, "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA=="], @@ -2041,6 +2122,10 @@ "hosted-git-info/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + "js-yaml/argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], + + "markdown-it/argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], + "millify/yargs": ["yargs@17.7.3", "", { "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-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g=="], "normalize-package-data/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], @@ -2079,6 +2164,8 @@ "vitepress/vite": ["vite@6.4.5", "", { "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-4enwjFfi4IwtEh0w+jPzpLVOFQiPHmmzPxcHXQOyEur47o6u0jE573DmGpjA+7irXoMLYRZD5ZaFUEneS3abPg=="], + "vitepress-plugin-llms/minimatch": ["minimatch@10.2.6", "", { "dependencies": { "brace-expansion": "^5.0.8" } }, "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A=="], + "vue/@vue/shared": ["@vue/shared@3.5.44", "", {}, "sha512-H82XLH0DjmSOdbEwO15x3QTo1f5PWEtv237eLpYKc0mqLu+B8hnq16lFWmuBmNurkeiG3wr+oM1FhOll/YVFRg=="], "wrap-ansi-cjs/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], diff --git a/doc/setup/dev.md b/doc/setup/dev.md index 9d5bbd3157b..5c97b1eb79a 100644 --- a/doc/setup/dev.md +++ b/doc/setup/dev.md @@ -15,11 +15,12 @@ match CI. `just check` and `just fix` refuse to run outside it; set | `just` | Start the local relay, test publisher, and web demo. | | `just --list` | List recipes; use `just --list test` or another module to narrow the list. | | `just ci-select` | Report whether CI and Rust build setup are needed, without running checks. | -| `just fix` | Format and lint the packages this branch changed. | +| `just fix` | Format and lint the packages this branch changed, and regenerate their committed JS API reports (`js/*/api/`). | | `just check` | Compile, lint, and test the same scope. | | `just ci` | Run the merge queue's gate locally, strictly. PRs into `main` get no other CI, so run it before every push. | | `just gate` | `just ci` over every package, as nightly and release PRs run it. | | `just fix --all`, `just check --all` | The same, over every package. | +| `just api-diff` | Diff every published API against its last release, the JS reports against `origin/release`'s. PRs into `release` run it; `--deny` fails a backport on any break. | | `just pub bbb ` | Publish Big Buck Bunny (also `tos`, `clock`, `gst`, `hls`). | | `just sub gst bbb ` | Play a broadcast through GStreamer. | | `just relay` | Run a local relay on its own. | diff --git a/js/auth/api/index.api.md b/js/auth/api/index.api.md new file mode 100644 index 00000000000..f969aecddff --- /dev/null +++ b/js/auth/api/index.api.md @@ -0,0 +1,795 @@ +## API Report File for "@moq/auth" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { compareSpecificity } from '@moq/pattern'; +import { InvalidPattern } from '@moq/pattern'; +import { Pattern } from '@moq/pattern'; +import { Patterns } from '@moq/pattern'; +import { Segment } from '@moq/pattern'; +import { Specificity } from '@moq/pattern'; +import * as z from '@zod/mini'; + +type Algorithm_2 = z.infer; +export { Algorithm_2 as Algorithm } + +export const AlgorithmSchema: z.ZodMiniEnum<{ + ES256: "ES256"; + ES384: "ES384"; + EdDSA: "EdDSA"; + HS256: "HS256"; + HS384: "HS384"; + HS512: "HS512"; + PS256: "PS256"; + PS384: "PS384"; + PS512: "PS512"; + RS256: "RS256"; + RS384: "RS384"; + RS512: "RS512"; +}>; + +export type AsymmetricKey = Exclude; + +export function authorize(claims: Claims, path: string): Permissions_2; + +export type Bytes = z.infer; + +export const BytesSchema: z.ZodMiniObject<{ + sent: z.ZodMiniInt; + received: z.ZodMiniInt; +}, z.core.$strip>; + +export type Claims = z.output; + +export const ClaimsSchema: z.ZodMiniPipe>; + publish: z.ZodMiniOptional>>; + subscribe: z.ZodMiniOptional>>; + exp: z.ZodMiniOptional; + iat: z.ZodMiniOptional; + nbf: z.ZodMiniOptional; + iss: z.ZodMiniOptional; + sub: z.ZodMiniOptional; + jti: z.ZodMiniOptional; + put: z.ZodMiniOptional, z.ZodMiniArray>]>>; + get: z.ZodMiniOptional, z.ZodMiniArray>]>>; +}, z.core.$strict>, z.ZodMiniTransform & { + publish?: string[]; + subscribe?: string[]; +}, { + root: string; + publish?: string[] | undefined; + subscribe?: string[] | undefined; + exp?: number | undefined; + iat?: number | undefined; + nbf?: number | undefined; + iss?: unknown; + sub?: unknown; + jti?: unknown; + put?: string | string[] | undefined; + get?: string | string[] | undefined; +}>>; + +export { compareSpecificity } + +function find(set: KeySet, kid: string): Key | undefined; + +function generate(algorithm: Algorithm_2, kid?: string): Promise; + +export type Grant = z.infer; + +export const GrantSchema: z.ZodMiniObject<{ + publish: z.ZodMiniOptional>>; + subscribe: z.ZodMiniOptional>>; + root: z.ZodMiniOptional>; + mounts: z.ZodMiniOptional, z.ZodMiniString>>; + expires: z.ZodMiniOptional; + revalidate: z.ZodMiniOptional; + tier: z.ZodMiniOptional>; + label: z.ZodMiniOptional>; + peer: z.ZodMiniOptional>; + upstream: z.ZodMiniOptional>; +}, z.core.$strip>; + +export { InvalidPattern } + +export type Key = z.infer; + +export const Key: { + parse: typeof parse; + public: typeof toPublic; + sign: typeof sign; + verify: typeof verify; + generate: typeof generate; +}; + +export type KeyId = z.infer; + +export const KeyIdSchema: z.ZodMiniString; + +export const KeySchema: z.ZodMiniDiscriminatedUnion<[z.ZodMiniObject<{ + alg: z.ZodMiniEnum<{ + ES256: "ES256"; + ES384: "ES384"; + EdDSA: "EdDSA"; + HS256: "HS256"; + HS384: "HS384"; + HS512: "HS512"; + PS256: "PS256"; + PS384: "PS384"; + PS512: "PS512"; + RS256: "RS256"; + RS384: "RS384"; + RS512: "RS512"; + }>; + key_ops: z.ZodMiniDefault>>; + kid: z.ZodMiniOptional>; + scope: z.ZodMiniOptional>; + publish: z.ZodMiniOptional>>; + subscribe: z.ZodMiniOptional>>; + put: z.ZodMiniOptional>>; + get: z.ZodMiniOptional>>; + }, z.core.$strict>, z.ZodMiniTransform & { + publish?: string[]; + subscribe?: string[]; + }, { + root: string; + publish?: string[] | undefined; + subscribe?: string[] | undefined; + put?: string[] | undefined; + get?: string[] | undefined; + }>>>; + kty: z.ZodMiniLiteral<"oct">; + k: z.ZodMiniString; +}, z.core.$strip>, z.ZodMiniObject<{ + alg: z.ZodMiniEnum<{ + ES256: "ES256"; + ES384: "ES384"; + EdDSA: "EdDSA"; + HS256: "HS256"; + HS384: "HS384"; + HS512: "HS512"; + PS256: "PS256"; + PS384: "PS384"; + PS512: "PS512"; + RS256: "RS256"; + RS384: "RS384"; + RS512: "RS512"; + }>; + key_ops: z.ZodMiniDefault>>; + kid: z.ZodMiniOptional>; + scope: z.ZodMiniOptional>; + publish: z.ZodMiniOptional>>; + subscribe: z.ZodMiniOptional>>; + put: z.ZodMiniOptional>>; + get: z.ZodMiniOptional>>; + }, z.core.$strict>, z.ZodMiniTransform & { + publish?: string[]; + subscribe?: string[]; + }, { + root: string; + publish?: string[] | undefined; + subscribe?: string[] | undefined; + put?: string[] | undefined; + get?: string[] | undefined; + }>>>; + kty: z.ZodMiniLiteral<"RSA">; + n: z.ZodMiniString; + e: z.ZodMiniString; + d: z.ZodMiniOptional>; + p: z.ZodMiniOptional>; + q: z.ZodMiniOptional>; + dp: z.ZodMiniOptional>; + dq: z.ZodMiniOptional>; + qi: z.ZodMiniOptional>; +}, z.core.$strip>, z.ZodMiniObject<{ + alg: z.ZodMiniEnum<{ + ES256: "ES256"; + ES384: "ES384"; + EdDSA: "EdDSA"; + HS256: "HS256"; + HS384: "HS384"; + HS512: "HS512"; + PS256: "PS256"; + PS384: "PS384"; + PS512: "PS512"; + RS256: "RS256"; + RS384: "RS384"; + RS512: "RS512"; + }>; + key_ops: z.ZodMiniDefault>>; + kid: z.ZodMiniOptional>; + scope: z.ZodMiniOptional>; + publish: z.ZodMiniOptional>>; + subscribe: z.ZodMiniOptional>>; + put: z.ZodMiniOptional>>; + get: z.ZodMiniOptional>>; + }, z.core.$strict>, z.ZodMiniTransform & { + publish?: string[]; + subscribe?: string[]; + }, { + root: string; + publish?: string[] | undefined; + subscribe?: string[] | undefined; + put?: string[] | undefined; + get?: string[] | undefined; + }>>>; + kty: z.ZodMiniLiteral<"EC">; + crv: z.ZodMiniEnum<{ + "P-256": "P-256"; + "P-384": "P-384"; + }>; + x: z.ZodMiniString; + y: z.ZodMiniString; + d: z.ZodMiniOptional>; +}, z.core.$strip>, z.ZodMiniObject<{ + alg: z.ZodMiniEnum<{ + ES256: "ES256"; + ES384: "ES384"; + EdDSA: "EdDSA"; + HS256: "HS256"; + HS384: "HS384"; + HS512: "HS512"; + PS256: "PS256"; + PS384: "PS384"; + PS512: "PS512"; + RS256: "RS256"; + RS384: "RS384"; + RS512: "RS512"; + }>; + key_ops: z.ZodMiniDefault>>; + kid: z.ZodMiniOptional>; + scope: z.ZodMiniOptional>; + publish: z.ZodMiniOptional>>; + subscribe: z.ZodMiniOptional>>; + put: z.ZodMiniOptional>>; + get: z.ZodMiniOptional>>; + }, z.core.$strict>, z.ZodMiniTransform & { + publish?: string[]; + subscribe?: string[]; + }, { + root: string; + publish?: string[] | undefined; + subscribe?: string[] | undefined; + put?: string[] | undefined; + get?: string[] | undefined; + }>>>; + kty: z.ZodMiniLiteral<"OKP">; + crv: z.ZodMiniLiteral<"Ed25519">; + x: z.ZodMiniString; + d: z.ZodMiniOptional>; +}, z.core.$strip>], "kty">; + +export type KeySet = z.infer; + +export const KeySet: { + parse: typeof parse_2; + public: typeof toPublic_2; + find: typeof find; + sign: typeof sign_2; + verify: typeof verify_2; +}; + +export const KeySetSchema: z.ZodMiniObject<{ + keys: z.ZodMiniArray; + key_ops: z.ZodMiniDefault>>; + kid: z.ZodMiniOptional>; + scope: z.ZodMiniOptional>; + publish: z.ZodMiniOptional>>; + subscribe: z.ZodMiniOptional>>; + put: z.ZodMiniOptional>>; + get: z.ZodMiniOptional>>; + }, z.core.$strict>, z.ZodMiniTransform & { + publish?: string[]; + subscribe?: string[]; + }, { + root: string; + publish?: string[] | undefined; + subscribe?: string[] | undefined; + put?: string[] | undefined; + get?: string[] | undefined; + }>>>; + kty: z.ZodMiniLiteral<"oct">; + k: z.ZodMiniString; + }, z.core.$strip>, z.ZodMiniObject<{ + alg: z.ZodMiniEnum<{ + ES256: "ES256"; + ES384: "ES384"; + EdDSA: "EdDSA"; + HS256: "HS256"; + HS384: "HS384"; + HS512: "HS512"; + PS256: "PS256"; + PS384: "PS384"; + PS512: "PS512"; + RS256: "RS256"; + RS384: "RS384"; + RS512: "RS512"; + }>; + key_ops: z.ZodMiniDefault>>; + kid: z.ZodMiniOptional>; + scope: z.ZodMiniOptional>; + publish: z.ZodMiniOptional>>; + subscribe: z.ZodMiniOptional>>; + put: z.ZodMiniOptional>>; + get: z.ZodMiniOptional>>; + }, z.core.$strict>, z.ZodMiniTransform & { + publish?: string[]; + subscribe?: string[]; + }, { + root: string; + publish?: string[] | undefined; + subscribe?: string[] | undefined; + put?: string[] | undefined; + get?: string[] | undefined; + }>>>; + kty: z.ZodMiniLiteral<"RSA">; + n: z.ZodMiniString; + e: z.ZodMiniString; + d: z.ZodMiniOptional>; + p: z.ZodMiniOptional>; + q: z.ZodMiniOptional>; + dp: z.ZodMiniOptional>; + dq: z.ZodMiniOptional>; + qi: z.ZodMiniOptional>; + }, z.core.$strip>, z.ZodMiniObject<{ + alg: z.ZodMiniEnum<{ + ES256: "ES256"; + ES384: "ES384"; + EdDSA: "EdDSA"; + HS256: "HS256"; + HS384: "HS384"; + HS512: "HS512"; + PS256: "PS256"; + PS384: "PS384"; + PS512: "PS512"; + RS256: "RS256"; + RS384: "RS384"; + RS512: "RS512"; + }>; + key_ops: z.ZodMiniDefault>>; + kid: z.ZodMiniOptional>; + scope: z.ZodMiniOptional>; + publish: z.ZodMiniOptional>>; + subscribe: z.ZodMiniOptional>>; + put: z.ZodMiniOptional>>; + get: z.ZodMiniOptional>>; + }, z.core.$strict>, z.ZodMiniTransform & { + publish?: string[]; + subscribe?: string[]; + }, { + root: string; + publish?: string[] | undefined; + subscribe?: string[] | undefined; + put?: string[] | undefined; + get?: string[] | undefined; + }>>>; + kty: z.ZodMiniLiteral<"EC">; + crv: z.ZodMiniEnum<{ + "P-256": "P-256"; + "P-384": "P-384"; + }>; + x: z.ZodMiniString; + y: z.ZodMiniString; + d: z.ZodMiniOptional>; + }, z.core.$strip>, z.ZodMiniObject<{ + alg: z.ZodMiniEnum<{ + ES256: "ES256"; + ES384: "ES384"; + EdDSA: "EdDSA"; + HS256: "HS256"; + HS384: "HS384"; + HS512: "HS512"; + PS256: "PS256"; + PS384: "PS384"; + PS512: "PS512"; + RS256: "RS256"; + RS384: "RS384"; + RS512: "RS512"; + }>; + key_ops: z.ZodMiniDefault>>; + kid: z.ZodMiniOptional>; + scope: z.ZodMiniOptional>; + publish: z.ZodMiniOptional>>; + subscribe: z.ZodMiniOptional>>; + put: z.ZodMiniOptional>>; + get: z.ZodMiniOptional>>; + }, z.core.$strict>, z.ZodMiniTransform & { + publish?: string[]; + subscribe?: string[]; + }, { + root: string; + publish?: string[] | undefined; + subscribe?: string[] | undefined; + put?: string[] | undefined; + get?: string[] | undefined; + }>>>; + kty: z.ZodMiniLiteral<"OKP">; + crv: z.ZodMiniLiteral<"Ed25519">; + x: z.ZodMiniString; + d: z.ZodMiniOptional>; + }, z.core.$strip>], "kty">>; +}, z.core.$strip>; + +export type Operation = z.infer; + +export const OperationSchema: z.ZodMiniEnum<{ + decrypt: "decrypt"; + encrypt: "encrypt"; + sign: "sign"; + verify: "verify"; +}>; + +function parse(jwk: string): Key; + +function parse_2(jwks: string): KeySet; + +export { Pattern } + +export const PatternListSchema: z.ZodMiniArray>; + +export { Patterns } + +export function patterns(texts: readonly string[] | undefined): Patterns; + +export type Peer = z.infer; + +export const PeerSchema: z.ZodMiniObject<{ + name: z.ZodMiniString; + fingerprint: z.ZodMiniString; + expires: z.ZodMiniOptional; + issuer: z.ZodMiniString; +}, z.core.$strip>; + +interface Permissions_2 { + publish: Patterns; + subscribe: Patterns; +} +export { Permissions_2 as Permissions } + +export type PublicKey = Omit; + +export interface PublicKeySet { + keys: PublicKey[]; +} + +export type Refusal = z.infer; + +export const RefusalSchema: z.ZodMiniObject<{ + reason: z.ZodMiniPipe, z.ZodMiniCatch>>; + root: z.ZodMiniOptional>; + tier: z.ZodMiniOptional>; +}, z.core.$strip>; + +type Request_2 = z.infer; +export { Request_2 as Request } + +export const RequestSchema: z.ZodMiniDiscriminatedUnion<[z.ZodMiniObject<{ + id: z.ZodMiniString; + node: z.ZodMiniString; + transport: z.ZodMiniPipe, z.ZodMiniCatch>>; + remote: z.ZodMiniOptional>; + local: z.ZodMiniOptional>; + server_name: z.ZodMiniOptional>; + alpn: z.ZodMiniOptional>; + path: z.ZodMiniString; + query: z.ZodMiniOptional>; + token: z.ZodMiniOptional; + }, z.core.$strip>>; + role: z.ZodMiniOptional>; + implementation: z.ZodMiniOptional>; + tls: z.ZodMiniOptional; + fingerprint: z.ZodMiniString; + expires: z.ZodMiniOptional; + issuer: z.ZodMiniString; + }, z.core.$strip>>; + event: z.ZodMiniLiteral<"connect">; +}, z.core.$strip>, z.ZodMiniObject<{ + id: z.ZodMiniString; + node: z.ZodMiniString; + transport: z.ZodMiniPipe, z.ZodMiniCatch>>; + remote: z.ZodMiniOptional>; + local: z.ZodMiniOptional>; + server_name: z.ZodMiniOptional>; + alpn: z.ZodMiniOptional>; + path: z.ZodMiniString; + query: z.ZodMiniOptional>; + token: z.ZodMiniOptional; + }, z.core.$strip>>; + role: z.ZodMiniOptional>; + implementation: z.ZodMiniOptional>; + tls: z.ZodMiniOptional; + fingerprint: z.ZodMiniString; + expires: z.ZodMiniOptional; + issuer: z.ZodMiniString; + }, z.core.$strip>>; + event: z.ZodMiniLiteral<"revalidate">; +}, z.core.$strip>, z.ZodMiniObject<{ + id: z.ZodMiniString; + node: z.ZodMiniString; + transport: z.ZodMiniPipe, z.ZodMiniCatch>>; + remote: z.ZodMiniOptional>; + local: z.ZodMiniOptional>; + server_name: z.ZodMiniOptional>; + alpn: z.ZodMiniOptional>; + path: z.ZodMiniString; + query: z.ZodMiniOptional>; + token: z.ZodMiniOptional; + }, z.core.$strip>>; + role: z.ZodMiniOptional>; + implementation: z.ZodMiniOptional>; + tls: z.ZodMiniOptional; + fingerprint: z.ZodMiniString; + expires: z.ZodMiniOptional; + issuer: z.ZodMiniString; + }, z.core.$strip>>; + event: z.ZodMiniLiteral<"end">; + reason: z.ZodMiniString; + duration: z.ZodMiniNumber; + bytes: z.ZodMiniObject<{ + sent: z.ZodMiniInt; + received: z.ZodMiniInt; + }, z.core.$strip>; +}, z.core.$strip>], "event">; + +export type Role = z.infer; + +export const RoleSchema: z.ZodMiniEnum<{ + publisher: "publisher"; + subscriber: "subscriber"; +}>; + +export type Scope = z.output; + +export function scopeAllows(scope: Scope, claims: Claims): boolean; + +export const ScopeSchema: z.ZodMiniPipe>; + publish: z.ZodMiniOptional>>; + subscribe: z.ZodMiniOptional>>; + put: z.ZodMiniOptional>>; + get: z.ZodMiniOptional>>; +}, z.core.$strict>, z.ZodMiniTransform & { + publish?: string[]; + subscribe?: string[]; +}, { + root: string; + publish?: string[] | undefined; + subscribe?: string[] | undefined; + put?: string[] | undefined; + get?: string[] | undefined; +}>>; + +export { Segment } + +function sign(key: Key, claims: z.input): Promise; + +function sign_2(set: KeySet, claims: z.input): Promise; + +export { Specificity } + +export type SymmetricKey = Extract; + +export type Token = z.infer; + +export const TokenSchema: z.ZodMiniObject<{ + kind: z.ZodMiniInt; + value: z.ZodMiniString; +}, z.core.$strip>; + +function toPublic(key: Key): PublicKey; + +function toPublic_2(set: KeySet): PublicKeySet; + +export type Transport = z.infer; + +export const TransportSchema: z.ZodMiniPipe, z.ZodMiniCatch>>; + +function verify(key: PublicKey | SymmetricKey, token: string): Promise; + +function verify_2(set: KeySet, token: string): Promise; + + +``` diff --git a/js/clock/api/index.api.md b/js/clock/api/index.api.md new file mode 100644 index 00000000000..544569a94b2 --- /dev/null +++ b/js/clock/api/index.api.md @@ -0,0 +1,143 @@ +## API Report File for "@moq/clock" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +export class Elapsed extends Error { + constructor(); +} + +export interface Installed { + close(): void; +} + +export type Instant = number & { + readonly _brand: "clock-instant"; +}; + +export const Instant: ((value: number) => Instant) & { + zero: Instant; + add: (at: Instant, duration: Nano) => Instant; + sub: (at: Instant, duration: Nano) => Instant; + durationSince: (at: Instant, earlier: Instant) => Nano; +}; + +export class Interval { + constructor(period: Nano); + close(): void; + period(): Nano; + setMissedTickBehavior(behavior: MissedTickBehavior): void; + tick(): Promise; +} + +export function interval(period: Nano): Interval; + +export class Manual { + advance(duration: Nano): Promise; + drive(work: PromiseLike): Promise; + fire(): Promise; + install(): Installed; + jump(duration: Nano): void; + now(): Instant; + stepWall(wall: Wall): void; + wall(): Wall; + static readonly WALL_START: Wall; +} + +export type Micro = number & { + readonly _brand: "clock-micro"; +}; + +export const Micro: ((value: number) => Micro) & { + zero: Micro; + fromNano: (value: Nano) => Micro; + toNano: (value: Micro) => Nano; + fromMilli: (value: Milli) => Micro; + toMilli: (value: Micro) => Milli; + fromSecond: (value: Second) => Micro; + toSecond: (value: Micro) => Second; +}; + +export type Milli = number & { + readonly _brand: "clock-milli"; +}; + +export const Milli: ((value: number) => Milli) & { + zero: Milli; + fromNano: (value: Nano) => Milli; + toNano: (value: Milli) => Nano; + fromMicro: (value: Micro) => Milli; + toMicro: (value: Milli) => Micro; + fromSecond: (value: Second) => Milli; + toSecond: (value: Milli) => Second; +}; + +export const MissedTickBehavior: { + readonly Burst: "burst"; + readonly Delay: "delay"; + readonly Skip: "skip"; +}; + +export type MissedTickBehavior = (typeof MissedTickBehavior)[keyof typeof MissedTickBehavior]; + +export type Nano = number & { + readonly _brand: "clock-nano"; +}; + +export const Nano: ((value: number) => Nano) & { + zero: Nano; + fromMicro: (value: Micro) => Nano; + toMicro: (value: Nano) => Micro; + fromMilli: (value: Milli) => Nano; + toMilli: (value: Nano) => Milli; + fromSecond: (value: Second) => Nano; + toSecond: (value: Nano) => Second; +}; + +export function now(): Instant; + +function origin_2(): Wall; +export { origin_2 as origin } + +export type Second = number & { + readonly _brand: "clock-second"; +}; + +export const Second: ((value: number) => Second) & { + zero: Second; + fromNano: (value: Nano) => Second; + toNano: (value: Second) => Nano; + fromMicro: (value: Micro) => Second; + toMicro: (value: Second) => Micro; + fromMilli: (value: Milli) => Second; + toMilli: (value: Second) => Milli; +}; + +export function sleep(duration: Nano, options?: { + signal?: AbortSignal; + ref?: boolean; +}): Promise; + +export function sleepUntil(at: Instant, options?: { + signal?: AbortSignal; + ref?: boolean; +}): Promise; + +export function timeout(duration: Nano, operation: PromiseLike): Promise; + +export type Wall = number & { + readonly _brand: "clock-wall"; +}; + +export const Wall: ((unixMillis: number) => Wall) & { + UNIX_EPOCH: Wall; + add: (at: Wall, duration: Nano) => Wall; + sub: (at: Wall, duration: Nano) => Wall; + durationSince: (at: Wall, earlier: Wall) => Nano; +}; + +export function wall(): Wall; + + +``` diff --git a/js/common/api.ts b/js/common/api.ts new file mode 100644 index 00000000000..a871a3e1b6f --- /dev/null +++ b/js/common/api.ts @@ -0,0 +1,135 @@ +// The API Extractor setup every `@moq/*` package shares: one report per `exports` entrypoint, +// committed beside the package and diffed by the release gate. +// +// The built `dist/` is analyzed in a copy outside the repository, where no `node_modules` +// resolves its imports, so a package's report never depends on whether its dependencies are built. + +import { cpSync, existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { Extractor, ExtractorConfig, ExtractorLogLevel } from "@microsoft/api-extractor"; + +/** + * Compare the built package in `dir` with its committed reports in `api/`, exiting on a + * difference, or rewrite them when `MOQ_API_REPORT=update`, as `just fix` sets. + */ +export function checkReports(dir: string) { + const folder = join(dir, "api"); + const current = reports(join(dir, "dist")); + const committed = existsSync(folder) ? readdirSync(folder).filter((file) => file.endsWith(".api.md")) : []; + const stale = [...new Set([...current.keys(), ...committed])].filter((file) => { + const path = join(folder, file); + return current.get(file) !== (existsSync(path) ? readFileSync(path, "utf8") : undefined); + }); + + if (process.env.MOQ_API_REPORT === "update") { + mkdirSync(folder, { recursive: true }); + for (const file of stale) { + const report = current.get(file); + if (report === undefined) rmSync(join(folder, file)); + else writeFileSync(join(folder, file), report); + } + } else if (stale.length > 0) { + console.error("The public API no longer matches its committed report; run `just fix` and review the diff:"); + for (const file of stale) console.error(` api/${file}`); + process.exit(1); + } +} + +/** Every entrypoint's API report for the built package in `dist`, by file name such as `index.api.md`. */ +function reports(dist: string): Map { + const work = mkdtempSync(join(tmpdir(), "moq-api-")); + try { + const root = join(work, "package"); + cpSync(dist, root, { recursive: true }); + rewriteExternalNamespaces(root); + const folder = join(work, "reports"); + mkdirSync(folder); + + const found = new Map(); + const exports: Record = + JSON.parse(readFileSync(join(root, "package.json"), "utf8")).exports ?? {}; + for (const [subpath, target] of Object.entries(exports)) { + const types = (target as { types?: string }).types; + if (!types) continue; + const entry = subpath === "." ? "index" : subpath.replace(/^\.\//, "").replaceAll("/", "-"); + found.set(`${entry}.api.md`, extract(root, join(root, types), folder, entry)); + } + return found; + } finally { + rmSync(work, { recursive: true, force: true }); + } +} + +// API Extractor cannot follow `export * as X from ""`, which every entrypoint uses to +// re-export its dependencies, but reads the equivalent import-then-export form. +function rewriteExternalNamespaces(root: string) { + for (const rel of new Bun.Glob("**/*.d.ts").scanSync(root)) { + const file = join(root, rel); + const body = readFileSync(file, "utf8"); + const next = body.replace( + /^export \* as ([A-Za-z_$][\w$]*) from "([^."][^"]*)";$/gm, + 'import * as $1 from "$2";\nexport { $1 };', + ); + if (next !== body) writeFileSync(file, next); + } +} + +function extract(root: string, entrypoint: string, folder: string, entry: string): string { + const config = ExtractorConfig.prepare({ + configObject: { + projectFolder: root, + newlineKind: "lf", + mainEntryPointFilePath: entrypoint, + compiler: { + overrideTsconfig: { + compilerOptions: { + target: "esnext", + module: "esnext", + moduleResolution: "bundler", + lib: ["esnext", "dom"], + strict: true, + }, + files: [entrypoint], + }, + }, + apiReport: { + enabled: true, + reportFolder: folder, + reportTempFolder: join(root, ".api-extractor"), + reportFileName: entry, + // A type the API references without exporting is still part of it, so a change to + // its declaration must change the report. + includeForgottenExports: true, + }, + docModel: { enabled: false }, + dtsRollup: { enabled: false }, + tsdocMetadata: { enabled: false }, + // The report is the output. Its findings about doc comments and unresolved + // dependencies are left to the build's own declaration checks. + messages: { + compilerMessageReporting: { default: { logLevel: ExtractorLogLevel.None } }, + extractorMessageReporting: { default: { logLevel: ExtractorLogLevel.None } }, + tsdocMessageReporting: { default: { logLevel: ExtractorLogLevel.None } }, + }, + }, + configObjectFullPath: join(root, "api-extractor.json"), + packageJsonFullPath: join(root, "package.json"), + }); + + // localBuild writes the report into the scratch folder instead of failing because it is new, + // and the console chatter about that is suppressed; errors still fail the result. + const result = Extractor.invoke(config, { + localBuild: true, + messageCallback: (message) => { + if (message.logLevel !== ExtractorLogLevel.Error) message.handled = true; + }, + }); + if (!result.succeeded) throw new Error(`API Extractor failed on ${entry}: ${result.errorCount} errors`); + + // Keep only the API: whether an item has a doc comment is not part of it, and every exported + // item is @public, so neither marker churns the report or reads as a break. + return readFileSync(join(folder, `${entry}.api.md`), "utf8") + .replaceAll(" (undocumented)", "") + .replace(/^ *\/\/( @public| \(No @packageDocumentation comment for this package\))?\n/gm, ""); +} diff --git a/js/common/declarations.test.ts b/js/common/declarations.test.ts index 0d16784913a..25129af1e5e 100644 --- a/js/common/declarations.test.ts +++ b/js/common/declarations.test.ts @@ -66,3 +66,49 @@ test("a trailing slash resolves to the directory index over a file", () => { ]); expect(problems(root, files)).toEqual([]); }); + +test("a name its source declares but the declarations strip is reported", () => { + const source = { + path: "/src/access.ts", + text: [ + 'import { Patterns } from "@moq/pattern";', + "/** @internal */ type Input = string | Patterns;", + "/** @internal */ const defaults = {};", + "/** @internal */ class Base {}", + "export const Schema = transform();", + "export class Access extends Base { static defaults: typeof defaults; }", + ].join("\n"), + }; + const files = new Map([ + [ + "/dist/access.d.ts", + 'import { Patterns } from "@moq/pattern";\nexport declare const Schema: Transform;\nexport declare class Access extends Base {\n static defaults: typeof defaults.value;\n}\n', + ], + ]); + expect(problems(root, files, new Map([["/dist/access.d.ts", source]]))).toEqual([ + "access.d.ts: references Input, which its declarations do not declare", + "access.d.ts: references Base, which its declarations do not declare", + "access.d.ts: references defaults, which its declarations do not declare", + ]); +}); + +test("globals, type parameters, and names the declarations keep resolve", () => { + const source = { + path: "/src/element.tsx", + text: [ + 'import type { Track } from "./track.ts";', + "type Key = string;", + "function Render(props: { value: T }) { return
{String(props.value)}
; }", + "export type Map = { [P in Key]: K extends Promise ? U : Track };", + "export { Render };", + ].join("\n"), + }; + const files = new Map([ + [ + "/dist/element.d.ts", + 'import type { Track } from "./track.ts";\ntype Key = string;\ndeclare function Render(props: { value: T }): HTMLElement;\nexport type Map = { [P in Key]: K extends Promise ? U : Track };\nexport { Render };\n', + ], + ["/dist/track.d.ts", "export interface Track {}\n"], + ]); + expect(problems(root, files, new Map([["/dist/element.d.ts", source]]))).toEqual([]); +}); diff --git a/js/common/declarations.ts b/js/common/declarations.ts index c53b6b3c1ce..f361dc4bf17 100644 --- a/js/common/declarations.ts +++ b/js/common/declarations.ts @@ -1,24 +1,40 @@ -// Checks a package's emitted `.d.ts` files for imports the target file no longer exports. +// Checks a package's emitted `.d.ts` files for names that no longer resolve. // -// `stripInternal` drops an `@internal` export from its own `.d.ts` but leaves the import in any -// file that names the type, so a published consumer sees a module that does not export it. Only -// declaration emit shows this, which is why it runs over `dist/` after the build rather than as a -// test that would have to run the compiler again. +// `stripInternal` drops an `@internal` declaration but leaves every reference to it: an import in +// another file, which then names an export its target lacks, or a type in the same file, which +// then names nothing. A published consumer sees a broken type either way. Only declaration emit +// shows this, which is why it runs over `dist/` after the build rather than as a test that would +// have to run the compiler again. import { dirname, extname, join, relative, resolve } from "node:path"; -import { parse } from "@babel/parser"; +import { type ParserPlugin, parse } from "@babel/parser"; type Statement = ReturnType["program"]["body"][number]; type Declaration = Extract["declaration"]; +type DefaultDeclaration = Extract["declaration"]; type FileExports = { names: Set; stars: string[]; imports: Array<{ specifier: string; names: string[] }>; + // Every module-scope name, exported or not, including imports. + bound: Set; + // Every name the file looks up at module scope. + referenced: Set; }; -/** Every import in `files` (path to `.d.ts` source) that its relative target does not export. */ -export function problems(root: string, files: Map): string[] { +/** The TypeScript a declaration file was emitted from. */ +export type Source = { path: string; text: string }; + +/** + * Every import in `files` (path to `.d.ts` source) that its relative target does not export, and + * every name a file references without declaring that its source in `sources` (keyed like `files`) + * declares at module scope. + * + * A name its source does not declare either is a global, so only the source can tell a stripped + * declaration from one the declarations rightly leave to the environment. + */ +export function problems(root: string, files: Map, sources = new Map()): string[] { const parsed = new Map(); for (const [file, source] of files) { parsed.set(file, fileExports(source)); @@ -26,6 +42,17 @@ export function problems(root: string, files: Map): string[] { const found: string[] = []; for (const [file, info] of parsed) { + const source = sources.get(file); + if (source) { + const plugins: ParserPlugin[] = extname(source.path) === ".tsx" ? ["typescript", "jsx"] : ["typescript"]; + const declaredBySource = bindings(parse(source.text, { sourceType: "module", plugins }).program.body); + for (const name of info.referenced) { + if (declaredBySource.has(name) && !info.bound.has(name)) { + found.push(`${relative(root, file)}: references ${name}, which its declarations do not declare`); + } + } + } + for (const { specifier, names } of info.imports) { const target = dtsPath(parsed, file, specifier); if (!target) continue; @@ -116,7 +143,99 @@ function fileExports(source: string): FileExports { } } - return { names, stars, imports }; + return { names, stars, imports, bound: bindings(ast.program.body), referenced: references(ast.program.body) }; +} + +// The names a module declares or imports at its top level. +function bindings(body: Statement[]): Set { + const names = new Set(); + for (const statement of body) { + switch (statement.type) { + case "ImportDeclaration": + for (const s of statement.specifiers) names.add(s.local.name); + break; + case "TSImportEqualsDeclaration": + names.add(statement.id.name); + break; + case "ExportNamedDeclaration": + case "ExportDefaultDeclaration": + for (const name of declared(statement.declaration)) names.add(name); + break; + default: + for (const name of declared(statement)) names.add(name); + } + } + return names; +} + +// The leftmost identifier of every name the AST looks up in its enclosing scope: type references, +// `typeof` queries, heritage clauses, computed keys, and local re-exports. Type parameters are +// excluded file-wide, so a stripped name that shares a type parameter's name goes unnoticed. +function references(body: Statement[]): Set { + const found = new Set(); + const parameters = new Set(); + + const lookup = (node: unknown, into = found) => { + const name = leftmost(node); + if (name) into.add(name); + }; + + const walk = (node: unknown) => { + if (Array.isArray(node)) { + for (const child of node) walk(child); + return; + } + if (!node || typeof node !== "object" || !("type" in node)) return; + const n = node as Record; + + switch (n.type) { + case "TSTypeReference": + lookup(n.typeName); + break; + case "TSTypeQuery": + lookup(n.exprName); + break; + case "TSInterfaceHeritage": + case "TSClassImplements": + lookup(n.expression); + break; + case "ClassDeclaration": + lookup(n.superClass); + break; + case "ExportNamedDeclaration": + if (!n.source) for (const s of n.specifiers as Array<{ local: unknown }>) lookup(s.local); + break; + case "ExportDefaultDeclaration": + lookup(n.declaration); + break; + case "TSTypeParameter": + lookup(n.name, parameters); + break; + case "TSMappedType": + lookup(n.key, parameters); + break; + } + if (n.computed) lookup(n.key); + + for (const [key, value] of Object.entries(n)) { + if (key === "loc" || key.endsWith("Comments")) continue; + walk(value); + } + }; + walk(body); + + for (const name of parameters) found.delete(name); + return found; +} + +// The identifier a qualified name, member expression, or plain identifier starts with. +function leftmost(node: unknown): string | undefined { + if (!node || typeof node !== "object" || !("type" in node)) return undefined; + const n = node as Record; + if (n.type === "Identifier") return n.name as string; + if (n.type === "TSQualifiedName") return leftmost(n.left); + if (n.type === "MemberExpression") return leftmost(n.object); + return undefined; } /** The name an import or export specifier spells, as an identifier or a string. */ @@ -126,8 +245,8 @@ export function moduleName( return node.type === "Identifier" ? node.name : node.value; } -// The names an `export declare ...` statement introduces. -function declared(declaration: Declaration | null | undefined): string[] { +// The names a declaration statement introduces. +function declared(declaration: Statement | Declaration | DefaultDeclaration | null | undefined): string[] { if (!declaration) return []; if (declaration.type === "VariableDeclaration") { return declaration.declarations.flatMap((d) => (d.id.type === "Identifier" ? [d.id.name] : [])); diff --git a/js/common/package.ts b/js/common/package.ts index 2122ab8192d..08af7f4da5b 100644 --- a/js/common/package.ts +++ b/js/common/package.ts @@ -3,10 +3,11 @@ // Split from release.ts to allow building packages without publishing import { copyFileSync, existsSync, readFileSync, writeFileSync } from "node:fs"; -import { basename, join, resolve } from "node:path"; +import { basename, dirname, join, resolve } from "node:path"; import { publint } from "publint"; import { formatMessage } from "publint/utils"; -import { problems } from "./declarations.ts"; +import { checkReports } from "./api.ts"; +import { problems, type Source } from "./declarations.ts"; import { undocumented } from "./docs.ts"; console.log("✍️ Rewriting package.json..."); @@ -144,13 +145,22 @@ if (messages.length > 0) { process.exit(1); } -console.log("🔍 Checking declaration imports..."); +console.log("🔍 Checking declaration names..."); const declarations = new Map(); +const sources = new Map(); for (const rel of new Bun.Glob("**/*.d.ts").scanSync("dist")) { const file = resolve("dist", rel); declarations.set(file, readFileSync(file, "utf8")); + + // A declaration copied rather than emitted has no map, and no source to compare against. + const map = `${file}.map`; + if (!existsSync(map)) continue; + const [source] = JSON.parse(readFileSync(map, "utf8")).sources as string[]; + if (!source) continue; + const path = resolve(dirname(map), source); + sources.set(file, { path, text: readFileSync(path, "utf8") }); } -const unresolved = problems(resolve("dist"), declarations); +const unresolved = problems(resolve("dist"), declarations, sources); if (unresolved.length > 0) { for (const problem of unresolved) console.error(problem); process.exit(1); @@ -168,6 +178,9 @@ if (published) { for (const problem of missing) console.error(` dist/${problem}`); process.exit(1); } + + console.log("🔍 Checking API reports..."); + checkReports("."); } console.log("📦 Package built successfully in dist/"); diff --git a/js/flate/api/index.api.md b/js/flate/api/index.api.md new file mode 100644 index 00000000000..e1f38464cef --- /dev/null +++ b/js/flate/api/index.api.md @@ -0,0 +1,112 @@ +## API Report File for "@moq/flate" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import * as Moq from '@moq/net'; +import { Timed } from '@moq/net'; + +export type Compression = "none" | "deflate"; + +interface Config { + compression?: Compression; +} + +interface Config_2 { + compression?: Compression; +} + +class Consumer { + [Symbol.asyncIterator](): AsyncIterator>; + constructor(config: Consumer.Config); + latest(): Promise | undefined>; + next(): Promise | undefined>; +} + +namespace Consumer { + type Config = Config & { + track: Moq.Track.Subscriber; + }; +} + +class Consumer_2 { + [Symbol.asyncIterator](): AsyncIterator>; + constructor(config: Consumer_2.Config); + next(): Promise | undefined>; +} + +namespace Consumer_2 { + type Config = Config_2 & { + track: Moq.Track.Subscriber; + }; +} + +export class Decoder { + constructor(); + frame(slice: Uint8Array): Uint8Array; +} + +export const DEFAULT_LEVEL = 6; + +export class Encoder { + constructor(options?: EncoderOptions); + static bound(len: number): number; + frame(payload: Uint8Array): Uint8Array; +} + +export interface EncoderOptions { + level?: number; +} + +type Init = Config & { + track: Moq.Track.Producer; +}; + +type Init_2 = Config_2 & { + track: Moq.Track.Producer; +}; + +class Producer { + constructor(config: Producer.Config); + finish(): void; + update(input: Timed): void; +} + +namespace Producer { + type Config = Init; +} + +class Producer_2 { + constructor(config: Producer_2.Config); + append(input: Timed): void; + finish(): void; +} + +namespace Producer_2 { + type Config = Init_2; +} + +class Rolled extends Error { + constructor(); +} + +declare namespace Snapshot { + export { + Consumer, + Config, + Producer + } +} + +declare namespace Stream { + export { + Consumer_2 as Consumer, + Rolled, + Config_2 as Config, + Producer_2 as Producer + } +} + + +``` diff --git a/js/hang/api/catalog.api.md b/js/hang/api/catalog.api.md new file mode 100644 index 00000000000..ed5ed88b5ac --- /dev/null +++ b/js/hang/api/catalog.api.md @@ -0,0 +1,1671 @@ +## API Report File for "@moq/hang" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import type * as Moq from '@moq/net'; +import * as z from '@zod/mini'; +import * as z_2 from 'zod/mini'; + +export type Archive = z.infer; + +export const ARCHIVE_VERSION = 3; + +export const ArchiveSchema: z.ZodMiniObject<{ + timelines: z.ZodMiniRecord, z.ZodMiniObject<{ + track: z.ZodMiniString; + duration: z.ZodMiniOptional, "u53", "out">>; + }, z.core.$strip>>; + timescale: z.ZodMiniDefault, "u53", "out">>; + replay: z.ZodMiniOptional>>; + replayEpoch: z.ZodMiniOptional>>; + store: z.ZodMiniOptional; + version: z.ZodMiniOptional, "u53", "out">>; +}, z.core.$strip>; + +declare namespace audio { + export { + ranked, + AudioConfigSchema, + AudioSchema, + Audio_3 as Audio, + AudioConfig + } +} + +const Audio_2: typeof audio; + +type Audio_2 = audio.Audio; +export { Audio_2 as Audio } + +type Audio_3 = z.infer; + +export type AudioConfig = z.infer; + +export const AudioConfigSchema: z.ZodMiniObject<{ + broadcast: z.ZodMiniOptional>>; + epoch: z.ZodMiniOptional>>; + track: z.ZodMiniOptional>; + label: z.ZodMiniOptional>; + codec: z.ZodMiniString; + container: z.ZodMiniDefault; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"cmaf">; + init: z.ZodMiniBase64; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"loc">; + }, z.core.$strip>], "kind">, z.ZodMiniPipe; + }, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + description: z.ZodMiniOptional>; + sampleRate: z.core.$ZodBranded, "u53", "out">; + numberOfChannels: z.core.$ZodBranded, "u53", "out">; + layout: z.ZodMiniOptional>; + bitrate: z.ZodMiniOptional, "u53", "out">>; + enabled: z.ZodMiniOptional>; + jitter: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + warmup: z.ZodMiniOptional, "u53", "out">>; + delay: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; +}, z.core.$strip>; + +export const AudioSchema: z.ZodMiniUnion, z.ZodMiniObject<{ + broadcast: z.ZodMiniOptional>>; + epoch: z.ZodMiniOptional>>; + track: z.ZodMiniOptional>; + label: z.ZodMiniOptional>; + codec: z.ZodMiniString; + container: z.ZodMiniDefault; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"cmaf">; + init: z.ZodMiniBase64; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"loc">; + }, z.core.$strip>], "kind">, z.ZodMiniPipe; + }, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + description: z.ZodMiniOptional>; + sampleRate: z.core.$ZodBranded, "u53", "out">; + numberOfChannels: z.core.$ZodBranded, "u53", "out">; + layout: z.ZodMiniOptional>; + bitrate: z.ZodMiniOptional, "u53", "out">>; + enabled: z.ZodMiniOptional>; + jitter: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + warmup: z.ZodMiniOptional, "u53", "out">>; + delay: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + }, z.core.$strip>>; +}, z.core.$strip>, z.ZodMiniPipe; + }, z.core.$strip>; + config: z.ZodMiniObject<{ + broadcast: z.ZodMiniOptional>>; + epoch: z.ZodMiniOptional>>; + track: z.ZodMiniOptional>; + label: z.ZodMiniOptional>; + codec: z.ZodMiniString; + container: z.ZodMiniDefault; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"cmaf">; + init: z.ZodMiniBase64; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"loc">; + }, z.core.$strip>], "kind">, z.ZodMiniPipe; + }, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + description: z.ZodMiniOptional>; + sampleRate: z.core.$ZodBranded, "u53", "out">; + numberOfChannels: z.core.$ZodBranded, "u53", "out">; + layout: z.ZodMiniOptional>; + bitrate: z.ZodMiniOptional, "u53", "out">>; + enabled: z.ZodMiniOptional>; + jitter: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + warmup: z.ZodMiniOptional, "u53", "out">>; + delay: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + }, z.core.$strip>; +}, z.core.$strip>, z.ZodMiniTransform<{ + renditions: { + [x: string]: { + broadcast?: RelativeBroadcast | undefined; + epoch?: ReferenceEpoch | undefined; + track?: string | undefined; + label?: string | undefined; + codec: string; + container: { + kind: "legacy"; + } | { + kind: "cmaf"; + init: string; + } | { + kind: "loc"; + } | { + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }; + description?: string | undefined; + sampleRate: number & z.$brand<"u53">; + numberOfChannels: number & z.$brand<"u53">; + layout?: string | undefined; + bitrate?: (number & z.$brand<"u53">) | undefined; + enabled?: boolean | undefined; + jitter?: (number & z.$brand<"u53">) | undefined; + warmup?: (number & z.$brand<"u53">) | undefined; + delay?: (number & z.$brand<"u53">) | undefined; + }; + }; +}, { + track: { + name: string; + }; + config: { + broadcast?: RelativeBroadcast | undefined; + epoch?: ReferenceEpoch | undefined; + track?: string | undefined; + label?: string | undefined; + codec: string; + container: { + kind: "legacy"; + } | { + kind: "cmaf"; + init: string; + } | { + kind: "loc"; + } | { + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }; + description?: string | undefined; + sampleRate: number & z.$brand<"u53">; + numberOfChannels: number & z.$brand<"u53">; + layout?: string | undefined; + bitrate?: (number & z.$brand<"u53">) | undefined; + enabled?: boolean | undefined; + jitter?: (number & z.$brand<"u53">) | undefined; + warmup?: (number & z.$brand<"u53">) | undefined; + delay?: (number & z.$brand<"u53">) | undefined; + }; +}>>]>; + +export type Binary = z_2.infer; + +export type BinaryConfig = z_2.infer; + +export const BinaryConfigSchema: z_2.ZodMiniObject<{ + broadcast: z_2.ZodMiniOptional>>; + epoch: z_2.ZodMiniOptional>>; + track: z_2.ZodMiniOptional>; + mode: z_2.ZodMiniString; + compression: z_2.ZodMiniOptional>; + mime: z_2.ZodMiniOptional>; + bitrate: z_2.ZodMiniOptional, "u53", "out">>; + jitter: z_2.ZodMiniOptional, "u53", "out">, z_2.ZodMiniTransform<(number & z_2.$brand<"u53">) | undefined, number & z_2.$brand<"u53">>>>; + delay: z_2.ZodMiniOptional, "u53", "out">, z_2.ZodMiniTransform<(number & z_2.$brand<"u53">) | undefined, number & z_2.$brand<"u53">>>>; +}, z_2.core.$loose>; + +export const BinarySchema: z_2.ZodMiniObject<{ + tracks: z_2.ZodMiniRecord, z_2.ZodMiniObject<{ + broadcast: z_2.ZodMiniOptional>>; + epoch: z_2.ZodMiniOptional>>; + track: z_2.ZodMiniOptional>; + mode: z_2.ZodMiniString; + compression: z_2.ZodMiniOptional>; + mime: z_2.ZodMiniOptional>; + bitrate: z_2.ZodMiniOptional, "u53", "out">>; + jitter: z_2.ZodMiniOptional, "u53", "out">, z_2.ZodMiniTransform<(number & z_2.$brand<"u53">) | undefined, number & z_2.$brand<"u53">>>>; + delay: z_2.ZodMiniOptional, "u53", "out">, z_2.ZodMiniTransform<(number & z_2.$brand<"u53">) | undefined, number & z_2.$brand<"u53">>>>; + }, z_2.core.$loose>>; +}, z_2.core.$strip>; + +export function checkRenditions(root: Root): Root; + +export function checkResolvable(root: Root, base: Moq.Path.Valid): Root; + +export type Clock = z.infer; + +export const ClockSchema: z.ZodMiniObject<{ + wall: z.core.$ZodBranded, "u53", "out">; + timescale: z.ZodMiniDefault>; +}, z.core.$strip>; + +export type CmafContainer = Extract; + +export type Color = z.infer; + +export const ColorSchema: z.ZodMiniObject<{ + primaries: z.ZodMiniOptional, "u8", "out">>; + transfer: z.ZodMiniOptional, "u8", "out">>; + matrix: z.ZodMiniOptional, "u8", "out">>; + range: z.ZodMiniOptional>; + mastering: z.ZodMiniOptional; + y: z.ZodMiniNumber; + }, z.core.$strip>; + green: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + blue: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + white: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + maxLuminance: z.ZodMiniNumber; + minLuminance: z.ZodMiniNumber; + }, z.core.$strip>>; + contentLight: z.ZodMiniOptional; + maxFall: z.ZodMiniNumber; + }, z.core.$strip>>; +}, z.core.$strip>; + +export type Compression = z_2.infer; + +export const CompressionSchema: z_2.ZodMiniString; + +export function compressionSupported(compression: Compression): compression is KnownCompression; + +export type Container = z.infer; + +export const ContainerSchema: z.ZodMiniDefault; +}, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"cmaf">; + init: z.ZodMiniBase64; +}, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"loc">; +}, z.core.$strip>], "kind">, z.ZodMiniPipe; +}, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; +}, { + [x: string]: unknown; + kind: string; +}>>]>>; + +export function containerSupported(container: Container): boolean; + +export const DEFAULT_FORMAT: Format; + +export function detectFormat(name: string): Format | undefined; + +export class DuplicateRendition extends Error { + constructor(id: string); + readonly id: string; +} + +export type Echo = z.infer; + +export const EchoSchema: z.ZodMiniObject<{ + path: z.ZodMiniType>; +}, z.core.$strip>; + +export function encode(root: Root): Root; + +export const EpochSchema: z.ZodMiniType; + +export class EscapingBroadcast extends Error { + constructor(broadcast: RelativeBroadcast); + readonly broadcast: RelativeBroadcast; +} + +export type Format = (typeof FORMATS)[number]; + +export const FORMATS: readonly ["hang", "msf"]; + +export type Hex = z.infer; + +export const hexSchema: z.ZodMiniString; + +export type Json = z_2.infer; + +export type JsonConfig = z_2.infer; + +export const JsonConfigSchema: z_2.ZodMiniObject<{ + broadcast: z_2.ZodMiniOptional>>; + epoch: z_2.ZodMiniOptional>>; + track: z_2.ZodMiniOptional>; + mode: z_2.ZodMiniString; + compression: z_2.ZodMiniOptional>; + schema: z_2.ZodMiniOptional>; + bitrate: z_2.ZodMiniOptional, "u53", "out">>; + jitter: z_2.ZodMiniOptional, "u53", "out">, z_2.ZodMiniTransform<(number & z_2.$brand<"u53">) | undefined, number & z_2.$brand<"u53">>>>; + delay: z_2.ZodMiniOptional, "u53", "out">, z_2.ZodMiniTransform<(number & z_2.$brand<"u53">) | undefined, number & z_2.$brand<"u53">>>>; +}, z_2.core.$loose>; + +export const JsonSchema: z_2.ZodMiniObject<{ + tracks: z_2.ZodMiniRecord, z_2.ZodMiniObject<{ + broadcast: z_2.ZodMiniOptional>>; + epoch: z_2.ZodMiniOptional>>; + track: z_2.ZodMiniOptional>; + mode: z_2.ZodMiniString; + compression: z_2.ZodMiniOptional>; + schema: z_2.ZodMiniOptional>; + bitrate: z_2.ZodMiniOptional, "u53", "out">>; + jitter: z_2.ZodMiniOptional, "u53", "out">, z_2.ZodMiniTransform<(number & z_2.$brand<"u53">) | undefined, number & z_2.$brand<"u53">>>>; + delay: z_2.ZodMiniOptional, "u53", "out">, z_2.ZodMiniTransform<(number & z_2.$brand<"u53">) | undefined, number & z_2.$brand<"u53">>>>; + }, z_2.core.$loose>>; +}, z_2.core.$strip>; + +export type KnownCompression = "deflate"; + +export type KnownMode = "snapshot" | "stream"; + +export const MAX_RENDITIONS = 64; + +export type Mode = z_2.infer; + +export const ModeSchema: z_2.ZodMiniString; + +export function modeSupported(mode: Mode): mode is KnownMode; + +export const MOQ_EPOCH_UNIX_MILLIS = 1577836800000; + +export const nonzeroU53Schema: z.core.$ZodBranded, "u53", "out">; + +export const PRIORITY: { + readonly catalog: 100; + readonly text: 90; + readonly audio: 80; + readonly video: 60; +}; + +export type Projection = z.infer; + +export const ProjectionSchema: z.ZodMiniUnion; +}, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"equirectangular">; + fov: z.ZodMiniOptional>; +}, z.core.$strip>], "kind">, z.ZodMiniPipe; +}, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; +}, { + [x: string]: unknown; + kind: string; +}>>]>; + +function ranked(renditions: Record): [string, AudioConfig][]; + +function ranked_2(renditions: Record): [string, VideoConfig][]; + +export type ReferenceEpoch = string & { + readonly _brand: "epoch"; +}; + +export type RelativeBroadcast = string & { + __brand: "Relative"; +}; + +export const RelativeBroadcastSchema: z.ZodMiniType; + +export type Root = z.infer; + +export const RootSchema: z.ZodMiniObject<{ + version: z.ZodMiniOptional>; + video: z.ZodMiniOptional, z.ZodMiniObject<{ + broadcast: z.ZodMiniOptional>>; + epoch: z.ZodMiniOptional>>; + track: z.ZodMiniOptional>; + label: z.ZodMiniOptional>; + codec: z.ZodMiniString; + container: z.ZodMiniDefault; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"cmaf">; + init: z.ZodMiniBase64; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"loc">; + }, z.core.$strip>], "kind">, z.ZodMiniPipe; + }, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + description: z.ZodMiniOptional>; + codedWidth: z.ZodMiniOptional, "u53", "out">>; + codedHeight: z.ZodMiniOptional, "u53", "out">>; + displayAspectWidth: z.ZodMiniOptional, "u53", "out">>; + displayAspectHeight: z.ZodMiniOptional, "u53", "out">>; + color: z.ZodMiniOptional, "u8", "out">>; + transfer: z.ZodMiniOptional, "u8", "out">>; + matrix: z.ZodMiniOptional, "u8", "out">>; + range: z.ZodMiniOptional>; + mastering: z.ZodMiniOptional; + y: z.ZodMiniNumber; + }, z.core.$strip>; + green: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + blue: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + white: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + maxLuminance: z.ZodMiniNumber; + minLuminance: z.ZodMiniNumber; + }, z.core.$strip>>; + contentLight: z.ZodMiniOptional; + maxFall: z.ZodMiniNumber; + }, z.core.$strip>>; + }, z.core.$strip>>; + projection: z.ZodMiniOptional; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"equirectangular">; + fov: z.ZodMiniOptional>; + }, z.core.$strip>], "kind">, z.ZodMiniPipe; + }, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + stereo: z.ZodMiniOptional>; + interlaced: z.ZodMiniOptional>; + framerate: z.ZodMiniOptional>; + reorder: z.ZodMiniOptional, "u8", "out">>; + bitrate: z.ZodMiniOptional, "u53", "out">>; + enabled: z.ZodMiniOptional>; + preference: z.ZodMiniOptional; + optimizeForLatency: z.ZodMiniOptional>; + jitter: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + warmup: z.ZodMiniOptional, "u53", "out">>; + delay: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + }, z.core.$strip>>; + display: z.ZodMiniOptional, "u53", "out">; + height: z.core.$ZodBranded, "u53", "out">; + }, z.core.$strip>>; + rotation: z.ZodMiniOptional>; + flip: z.ZodMiniOptional>; + }, z.core.$strip>, z.ZodMiniPipe; + }, z.core.$strip>; + config: z.ZodMiniObject<{ + broadcast: z.ZodMiniOptional>>; + epoch: z.ZodMiniOptional>>; + track: z.ZodMiniOptional>; + label: z.ZodMiniOptional>; + codec: z.ZodMiniString; + container: z.ZodMiniDefault; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"cmaf">; + init: z.ZodMiniBase64; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"loc">; + }, z.core.$strip>], "kind">, z.ZodMiniPipe; + }, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + description: z.ZodMiniOptional>; + codedWidth: z.ZodMiniOptional, "u53", "out">>; + codedHeight: z.ZodMiniOptional, "u53", "out">>; + displayAspectWidth: z.ZodMiniOptional, "u53", "out">>; + displayAspectHeight: z.ZodMiniOptional, "u53", "out">>; + color: z.ZodMiniOptional, "u8", "out">>; + transfer: z.ZodMiniOptional, "u8", "out">>; + matrix: z.ZodMiniOptional, "u8", "out">>; + range: z.ZodMiniOptional>; + mastering: z.ZodMiniOptional; + y: z.ZodMiniNumber; + }, z.core.$strip>; + green: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + blue: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + white: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + maxLuminance: z.ZodMiniNumber; + minLuminance: z.ZodMiniNumber; + }, z.core.$strip>>; + contentLight: z.ZodMiniOptional; + maxFall: z.ZodMiniNumber; + }, z.core.$strip>>; + }, z.core.$strip>>; + projection: z.ZodMiniOptional; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"equirectangular">; + fov: z.ZodMiniOptional>; + }, z.core.$strip>], "kind">, z.ZodMiniPipe; + }, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + stereo: z.ZodMiniOptional>; + interlaced: z.ZodMiniOptional>; + framerate: z.ZodMiniOptional>; + reorder: z.ZodMiniOptional, "u8", "out">>; + bitrate: z.ZodMiniOptional, "u53", "out">>; + enabled: z.ZodMiniOptional>; + preference: z.ZodMiniOptional; + optimizeForLatency: z.ZodMiniOptional>; + jitter: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + warmup: z.ZodMiniOptional, "u53", "out">>; + delay: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + }, z.core.$strip>; + }, z.core.$strip>>, z.ZodMiniTransform<{ + renditions: { + [k: string]: { + broadcast?: RelativeBroadcast | undefined; + epoch?: ReferenceEpoch | undefined; + track?: string | undefined; + label?: string | undefined; + codec: string; + container: { + kind: "legacy"; + } | { + kind: "cmaf"; + init: string; + } | { + kind: "loc"; + } | { + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }; + description?: string | undefined; + codedWidth?: (number & z.$brand<"u53">) | undefined; + codedHeight?: (number & z.$brand<"u53">) | undefined; + displayAspectWidth?: (number & z.$brand<"u53">) | undefined; + displayAspectHeight?: (number & z.$brand<"u53">) | undefined; + color?: { + primaries?: (number & z.$brand<"u8">) | undefined; + transfer?: (number & z.$brand<"u8">) | undefined; + matrix?: (number & z.$brand<"u8">) | undefined; + range?: "full" | "limited" | undefined; + mastering?: { + red: { + x: number; + y: number; + }; + green: { + x: number; + y: number; + }; + blue: { + x: number; + y: number; + }; + white: { + x: number; + y: number; + }; + maxLuminance: number; + minLuminance: number; + } | undefined; + contentLight?: { + maxCll: number; + maxFall: number; + } | undefined; + } | undefined; + projection?: { + kind: "rectilinear"; + } | { + kind: "equirectangular"; + fov?: number | undefined; + } | { + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + } | undefined; + stereo?: string | undefined; + interlaced?: boolean | undefined; + framerate?: number | undefined; + reorder?: (number & z.$brand<"u8">) | undefined; + bitrate?: (number & z.$brand<"u53">) | undefined; + enabled?: boolean | undefined; + preference?: number | undefined; + optimizeForLatency?: boolean | undefined; + jitter?: (number & z.$brand<"u53">) | undefined; + warmup?: (number & z.$brand<"u53">) | undefined; + delay?: (number & z.$brand<"u53">) | undefined; + }; + }; + display: { + width: number & z.$brand<"u53">; + height: number & z.$brand<"u53">; + } | undefined; + rotation: undefined; + flip: undefined; + }, { + track: { + name: string; + }; + config: { + broadcast?: RelativeBroadcast | undefined; + epoch?: ReferenceEpoch | undefined; + track?: string | undefined; + label?: string | undefined; + codec: string; + container: { + kind: "legacy"; + } | { + kind: "cmaf"; + init: string; + } | { + kind: "loc"; + } | { + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }; + description?: string | undefined; + codedWidth?: (number & z.$brand<"u53">) | undefined; + codedHeight?: (number & z.$brand<"u53">) | undefined; + displayAspectWidth?: (number & z.$brand<"u53">) | undefined; + displayAspectHeight?: (number & z.$brand<"u53">) | undefined; + color?: { + primaries?: (number & z.$brand<"u8">) | undefined; + transfer?: (number & z.$brand<"u8">) | undefined; + matrix?: (number & z.$brand<"u8">) | undefined; + range?: "full" | "limited" | undefined; + mastering?: { + red: { + x: number; + y: number; + }; + green: { + x: number; + y: number; + }; + blue: { + x: number; + y: number; + }; + white: { + x: number; + y: number; + }; + maxLuminance: number; + minLuminance: number; + } | undefined; + contentLight?: { + maxCll: number; + maxFall: number; + } | undefined; + } | undefined; + projection?: { + kind: "rectilinear"; + } | { + kind: "equirectangular"; + fov?: number | undefined; + } | { + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + } | undefined; + stereo?: string | undefined; + interlaced?: boolean | undefined; + framerate?: number | undefined; + reorder?: (number & z.$brand<"u8">) | undefined; + bitrate?: (number & z.$brand<"u53">) | undefined; + enabled?: boolean | undefined; + preference?: number | undefined; + optimizeForLatency?: boolean | undefined; + jitter?: (number & z.$brand<"u53">) | undefined; + warmup?: (number & z.$brand<"u53">) | undefined; + delay?: (number & z.$brand<"u53">) | undefined; + }; + }[]>>]>>; + audio: z.ZodMiniOptional, z.ZodMiniObject<{ + broadcast: z.ZodMiniOptional>>; + epoch: z.ZodMiniOptional>>; + track: z.ZodMiniOptional>; + label: z.ZodMiniOptional>; + codec: z.ZodMiniString; + container: z.ZodMiniDefault; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"cmaf">; + init: z.ZodMiniBase64; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"loc">; + }, z.core.$strip>], "kind">, z.ZodMiniPipe; + }, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + description: z.ZodMiniOptional>; + sampleRate: z.core.$ZodBranded, "u53", "out">; + numberOfChannels: z.core.$ZodBranded, "u53", "out">; + layout: z.ZodMiniOptional>; + bitrate: z.ZodMiniOptional, "u53", "out">>; + enabled: z.ZodMiniOptional>; + jitter: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + warmup: z.ZodMiniOptional, "u53", "out">>; + delay: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + }, z.core.$strip>>; + }, z.core.$strip>, z.ZodMiniPipe; + }, z.core.$strip>; + config: z.ZodMiniObject<{ + broadcast: z.ZodMiniOptional>>; + epoch: z.ZodMiniOptional>>; + track: z.ZodMiniOptional>; + label: z.ZodMiniOptional>; + codec: z.ZodMiniString; + container: z.ZodMiniDefault; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"cmaf">; + init: z.ZodMiniBase64; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"loc">; + }, z.core.$strip>], "kind">, z.ZodMiniPipe; + }, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + description: z.ZodMiniOptional>; + sampleRate: z.core.$ZodBranded, "u53", "out">; + numberOfChannels: z.core.$ZodBranded, "u53", "out">; + layout: z.ZodMiniOptional>; + bitrate: z.ZodMiniOptional, "u53", "out">>; + enabled: z.ZodMiniOptional>; + jitter: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + warmup: z.ZodMiniOptional, "u53", "out">>; + delay: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + }, z.core.$strip>; + }, z.core.$strip>, z.ZodMiniTransform<{ + renditions: { + [x: string]: { + broadcast?: RelativeBroadcast | undefined; + epoch?: ReferenceEpoch | undefined; + track?: string | undefined; + label?: string | undefined; + codec: string; + container: { + kind: "legacy"; + } | { + kind: "cmaf"; + init: string; + } | { + kind: "loc"; + } | { + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }; + description?: string | undefined; + sampleRate: number & z.$brand<"u53">; + numberOfChannels: number & z.$brand<"u53">; + layout?: string | undefined; + bitrate?: (number & z.$brand<"u53">) | undefined; + enabled?: boolean | undefined; + jitter?: (number & z.$brand<"u53">) | undefined; + warmup?: (number & z.$brand<"u53">) | undefined; + delay?: (number & z.$brand<"u53">) | undefined; + }; + }; + }, { + track: { + name: string; + }; + config: { + broadcast?: RelativeBroadcast | undefined; + epoch?: ReferenceEpoch | undefined; + track?: string | undefined; + label?: string | undefined; + codec: string; + container: { + kind: "legacy"; + } | { + kind: "cmaf"; + init: string; + } | { + kind: "loc"; + } | { + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }; + description?: string | undefined; + sampleRate: number & z.$brand<"u53">; + numberOfChannels: number & z.$brand<"u53">; + layout?: string | undefined; + bitrate?: (number & z.$brand<"u53">) | undefined; + enabled?: boolean | undefined; + jitter?: (number & z.$brand<"u53">) | undefined; + warmup?: (number & z.$brand<"u53">) | undefined; + delay?: (number & z.$brand<"u53">) | undefined; + }; + }>>]>>; + archive: z.ZodMiniCatch, z.ZodMiniObject<{ + track: z.ZodMiniString; + duration: z.ZodMiniOptional, "u53", "out">>; + }, z.core.$strip>>; + timescale: z.ZodMiniDefault, "u53", "out">>; + replay: z.ZodMiniOptional>>; + replayEpoch: z.ZodMiniOptional>>; + store: z.ZodMiniOptional; + version: z.ZodMiniOptional, "u53", "out">>; + }, z.core.$strip>>>; + clock: z.ZodMiniOptional, "u53", "out">; + timescale: z.ZodMiniDefault>; + }, z.core.$strip>>; + stats: z.ZodMiniOptional; + }, z.core.$strip>, z.ZodMiniPipe, z.ZodMiniTransform>]>>; + echo: z.ZodMiniOptional>; + }, z.core.$strip>, z.ZodMiniPipe, z.ZodMiniTransform>]>>; + text: z.ZodMiniOptional, z.ZodMiniObject<{ + broadcast: z.ZodMiniOptional>>; + epoch: z.ZodMiniOptional>>; + track: z.ZodMiniOptional>; + format: z.ZodMiniString; + role: z.ZodMiniDefault>; + lang: z.ZodMiniOptional>; + label: z.ZodMiniOptional>; + container: z.ZodMiniDefault; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"cmaf">; + init: z.ZodMiniBase64; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"loc">; + }, z.core.$strip>], "kind">, z.ZodMiniPipe; + }, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + jitter: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + delay: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + }, z.core.$strip>>; + }, z.core.$strip>, z.ZodMiniPipe, z.ZodMiniTransform>]>>; + json: z.ZodMiniOptional, z.ZodMiniObject<{ + broadcast: z.ZodMiniOptional>>; + epoch: z.ZodMiniOptional>>; + track: z.ZodMiniOptional>; + mode: z.ZodMiniString; + compression: z.ZodMiniOptional>; + schema: z.ZodMiniOptional>; + bitrate: z.ZodMiniOptional, "u53", "out">>; + jitter: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + delay: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + }, z.core.$loose>>; + }, z.core.$strip>, z.ZodMiniPipe, z.ZodMiniTransform>]>>; + binary: z.ZodMiniOptional, z.ZodMiniObject<{ + broadcast: z.ZodMiniOptional>>; + epoch: z.ZodMiniOptional>>; + track: z.ZodMiniOptional>; + mode: z.ZodMiniString; + compression: z.ZodMiniOptional>; + mime: z.ZodMiniOptional>; + bitrate: z.ZodMiniOptional, "u53", "out">>; + jitter: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + delay: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + }, z.core.$loose>>; + }, z.core.$strip>, z.ZodMiniPipe, z.ZodMiniTransform>]>>; +}, z.core.$loose>; + +export type Stats = z.infer; + +export const StatsSchema: z.ZodMiniObject<{ + track: z.ZodMiniString; +}, z.core.$strip>; + +type Text_2 = z_2.infer; +export { Text_2 as Text } + +export type TextConfig = z_2.infer; + +export const TextConfigSchema: z_2.ZodMiniObject<{ + broadcast: z_2.ZodMiniOptional>>; + epoch: z_2.ZodMiniOptional>>; + track: z_2.ZodMiniOptional>; + format: z_2.ZodMiniString; + role: z_2.ZodMiniDefault>; + lang: z_2.ZodMiniOptional>; + label: z_2.ZodMiniOptional>; + container: z_2.ZodMiniDefault; + }, z_2.core.$strip>, z_2.ZodMiniObject<{ + kind: z_2.ZodMiniLiteral<"cmaf">; + init: z_2.ZodMiniBase64; + }, z_2.core.$strip>, z_2.ZodMiniObject<{ + kind: z_2.ZodMiniLiteral<"loc">; + }, z_2.core.$strip>], "kind">, z_2.ZodMiniPipe; + }, z_2.core.$loose>, z_2.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + jitter: z_2.ZodMiniOptional, "u53", "out">, z_2.ZodMiniTransform<(number & z_2.$brand<"u53">) | undefined, number & z_2.$brand<"u53">>>>; + delay: z_2.ZodMiniOptional, "u53", "out">, z_2.ZodMiniTransform<(number & z_2.$brand<"u53">) | undefined, number & z_2.$brand<"u53">>>>; +}, z_2.core.$strip>; + +export const TextFormatSchema: z_2.ZodMiniString; + +export type TextRole = z_2.infer; + +export const TextRoleSchema: z_2.ZodMiniString; + +export const TextSchema: z_2.ZodMiniObject<{ + renditions: z_2.ZodMiniRecord, z_2.ZodMiniObject<{ + broadcast: z_2.ZodMiniOptional>>; + epoch: z_2.ZodMiniOptional>>; + track: z_2.ZodMiniOptional>; + format: z_2.ZodMiniString; + role: z_2.ZodMiniDefault>; + lang: z_2.ZodMiniOptional>; + label: z_2.ZodMiniOptional>; + container: z_2.ZodMiniDefault; + }, z_2.core.$strip>, z_2.ZodMiniObject<{ + kind: z_2.ZodMiniLiteral<"cmaf">; + init: z_2.ZodMiniBase64; + }, z_2.core.$strip>, z_2.ZodMiniObject<{ + kind: z_2.ZodMiniLiteral<"loc">; + }, z_2.core.$strip>], "kind">, z_2.ZodMiniPipe; + }, z_2.core.$loose>, z_2.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + jitter: z_2.ZodMiniOptional, "u53", "out">, z_2.ZodMiniTransform<(number & z_2.$brand<"u53">) | undefined, number & z_2.$brand<"u53">>>>; + delay: z_2.ZodMiniOptional, "u53", "out">, z_2.ZodMiniTransform<(number & z_2.$brand<"u53">) | undefined, number & z_2.$brand<"u53">>>>; + }, z_2.core.$strip>>; +}, z_2.core.$strip>; + +export class TooManyRenditions extends Error { + constructor(count: number); + readonly count: number; +} + +export const TRACK = "catalog.json"; + +export type Track = z.infer; + +export function track(id: string, config: { + track?: string; +}): string; + +export const TRACK_COMPRESSED = "catalog.json.z"; + +export const TrackSchema: z.ZodMiniObject<{ + name: z.ZodMiniString; +}, z.core.$strip>; + +export type U53 = z.infer; + +export function u53(value: number): U53; + +export const u53Schema: z.core.$ZodBranded, "u53", "out">; + +export type U8 = z.infer; + +export function u8(value: number): U8; + +export const u8Schema: z.core.$ZodBranded, "u8", "out">; + +export const UnknownContainerSchema: z.ZodMiniPipe; +}, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; +}, { + [x: string]: unknown; + kind: string; +}>>; + +export class UnsupportedVersion extends Error { + constructor(version: number); + readonly version: number; +} + +export const VERSION = 4; + +export const Video: typeof video; + +export type Video = video.Video; + +declare namespace video { + export { + ranked_2 as ranked, + ColorSchema, + Color, + ProjectionSchema, + Projection, + VideoConfigSchema, + VideoSchema, + Video_2 as Video, + VideoConfig + } +} + +type Video_2 = z.infer; + +export type VideoConfig = z.infer; + +export const VideoConfigSchema: z.ZodMiniObject<{ + broadcast: z.ZodMiniOptional>>; + epoch: z.ZodMiniOptional>>; + track: z.ZodMiniOptional>; + label: z.ZodMiniOptional>; + codec: z.ZodMiniString; + container: z.ZodMiniDefault; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"cmaf">; + init: z.ZodMiniBase64; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"loc">; + }, z.core.$strip>], "kind">, z.ZodMiniPipe; + }, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + description: z.ZodMiniOptional>; + codedWidth: z.ZodMiniOptional, "u53", "out">>; + codedHeight: z.ZodMiniOptional, "u53", "out">>; + displayAspectWidth: z.ZodMiniOptional, "u53", "out">>; + displayAspectHeight: z.ZodMiniOptional, "u53", "out">>; + color: z.ZodMiniOptional, "u8", "out">>; + transfer: z.ZodMiniOptional, "u8", "out">>; + matrix: z.ZodMiniOptional, "u8", "out">>; + range: z.ZodMiniOptional>; + mastering: z.ZodMiniOptional; + y: z.ZodMiniNumber; + }, z.core.$strip>; + green: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + blue: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + white: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + maxLuminance: z.ZodMiniNumber; + minLuminance: z.ZodMiniNumber; + }, z.core.$strip>>; + contentLight: z.ZodMiniOptional; + maxFall: z.ZodMiniNumber; + }, z.core.$strip>>; + }, z.core.$strip>>; + projection: z.ZodMiniOptional; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"equirectangular">; + fov: z.ZodMiniOptional>; + }, z.core.$strip>], "kind">, z.ZodMiniPipe; + }, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + stereo: z.ZodMiniOptional>; + interlaced: z.ZodMiniOptional>; + framerate: z.ZodMiniOptional>; + reorder: z.ZodMiniOptional, "u8", "out">>; + bitrate: z.ZodMiniOptional, "u53", "out">>; + enabled: z.ZodMiniOptional>; + preference: z.ZodMiniOptional; + optimizeForLatency: z.ZodMiniOptional>; + jitter: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + warmup: z.ZodMiniOptional, "u53", "out">>; + delay: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; +}, z.core.$strip>; + +export const VideoSchema: z.ZodMiniUnion, z.ZodMiniObject<{ + broadcast: z.ZodMiniOptional>>; + epoch: z.ZodMiniOptional>>; + track: z.ZodMiniOptional>; + label: z.ZodMiniOptional>; + codec: z.ZodMiniString; + container: z.ZodMiniDefault; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"cmaf">; + init: z.ZodMiniBase64; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"loc">; + }, z.core.$strip>], "kind">, z.ZodMiniPipe; + }, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + description: z.ZodMiniOptional>; + codedWidth: z.ZodMiniOptional, "u53", "out">>; + codedHeight: z.ZodMiniOptional, "u53", "out">>; + displayAspectWidth: z.ZodMiniOptional, "u53", "out">>; + displayAspectHeight: z.ZodMiniOptional, "u53", "out">>; + color: z.ZodMiniOptional, "u8", "out">>; + transfer: z.ZodMiniOptional, "u8", "out">>; + matrix: z.ZodMiniOptional, "u8", "out">>; + range: z.ZodMiniOptional>; + mastering: z.ZodMiniOptional; + y: z.ZodMiniNumber; + }, z.core.$strip>; + green: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + blue: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + white: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + maxLuminance: z.ZodMiniNumber; + minLuminance: z.ZodMiniNumber; + }, z.core.$strip>>; + contentLight: z.ZodMiniOptional; + maxFall: z.ZodMiniNumber; + }, z.core.$strip>>; + }, z.core.$strip>>; + projection: z.ZodMiniOptional; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"equirectangular">; + fov: z.ZodMiniOptional>; + }, z.core.$strip>], "kind">, z.ZodMiniPipe; + }, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + stereo: z.ZodMiniOptional>; + interlaced: z.ZodMiniOptional>; + framerate: z.ZodMiniOptional>; + reorder: z.ZodMiniOptional, "u8", "out">>; + bitrate: z.ZodMiniOptional, "u53", "out">>; + enabled: z.ZodMiniOptional>; + preference: z.ZodMiniOptional; + optimizeForLatency: z.ZodMiniOptional>; + jitter: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + warmup: z.ZodMiniOptional, "u53", "out">>; + delay: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + }, z.core.$strip>>; + display: z.ZodMiniOptional, "u53", "out">; + height: z.core.$ZodBranded, "u53", "out">; + }, z.core.$strip>>; + rotation: z.ZodMiniOptional>; + flip: z.ZodMiniOptional>; +}, z.core.$strip>, z.ZodMiniPipe; + }, z.core.$strip>; + config: z.ZodMiniObject<{ + broadcast: z.ZodMiniOptional>>; + epoch: z.ZodMiniOptional>>; + track: z.ZodMiniOptional>; + label: z.ZodMiniOptional>; + codec: z.ZodMiniString; + container: z.ZodMiniDefault; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"cmaf">; + init: z.ZodMiniBase64; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"loc">; + }, z.core.$strip>], "kind">, z.ZodMiniPipe; + }, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + description: z.ZodMiniOptional>; + codedWidth: z.ZodMiniOptional, "u53", "out">>; + codedHeight: z.ZodMiniOptional, "u53", "out">>; + displayAspectWidth: z.ZodMiniOptional, "u53", "out">>; + displayAspectHeight: z.ZodMiniOptional, "u53", "out">>; + color: z.ZodMiniOptional, "u8", "out">>; + transfer: z.ZodMiniOptional, "u8", "out">>; + matrix: z.ZodMiniOptional, "u8", "out">>; + range: z.ZodMiniOptional>; + mastering: z.ZodMiniOptional; + y: z.ZodMiniNumber; + }, z.core.$strip>; + green: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + blue: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + white: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + maxLuminance: z.ZodMiniNumber; + minLuminance: z.ZodMiniNumber; + }, z.core.$strip>>; + contentLight: z.ZodMiniOptional; + maxFall: z.ZodMiniNumber; + }, z.core.$strip>>; + }, z.core.$strip>>; + projection: z.ZodMiniOptional; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"equirectangular">; + fov: z.ZodMiniOptional>; + }, z.core.$strip>], "kind">, z.ZodMiniPipe; + }, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + stereo: z.ZodMiniOptional>; + interlaced: z.ZodMiniOptional>; + framerate: z.ZodMiniOptional>; + reorder: z.ZodMiniOptional, "u8", "out">>; + bitrate: z.ZodMiniOptional, "u53", "out">>; + enabled: z.ZodMiniOptional>; + preference: z.ZodMiniOptional; + optimizeForLatency: z.ZodMiniOptional>; + jitter: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + warmup: z.ZodMiniOptional, "u53", "out">>; + delay: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + }, z.core.$strip>; +}, z.core.$strip>>, z.ZodMiniTransform<{ + renditions: { + [k: string]: { + broadcast?: RelativeBroadcast | undefined; + epoch?: ReferenceEpoch | undefined; + track?: string | undefined; + label?: string | undefined; + codec: string; + container: { + kind: "legacy"; + } | { + kind: "cmaf"; + init: string; + } | { + kind: "loc"; + } | { + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }; + description?: string | undefined; + codedWidth?: (number & z.$brand<"u53">) | undefined; + codedHeight?: (number & z.$brand<"u53">) | undefined; + displayAspectWidth?: (number & z.$brand<"u53">) | undefined; + displayAspectHeight?: (number & z.$brand<"u53">) | undefined; + color?: { + primaries?: (number & z.$brand<"u8">) | undefined; + transfer?: (number & z.$brand<"u8">) | undefined; + matrix?: (number & z.$brand<"u8">) | undefined; + range?: "full" | "limited" | undefined; + mastering?: { + red: { + x: number; + y: number; + }; + green: { + x: number; + y: number; + }; + blue: { + x: number; + y: number; + }; + white: { + x: number; + y: number; + }; + maxLuminance: number; + minLuminance: number; + } | undefined; + contentLight?: { + maxCll: number; + maxFall: number; + } | undefined; + } | undefined; + projection?: { + kind: "rectilinear"; + } | { + kind: "equirectangular"; + fov?: number | undefined; + } | { + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + } | undefined; + stereo?: string | undefined; + interlaced?: boolean | undefined; + framerate?: number | undefined; + reorder?: (number & z.$brand<"u8">) | undefined; + bitrate?: (number & z.$brand<"u53">) | undefined; + enabled?: boolean | undefined; + preference?: number | undefined; + optimizeForLatency?: boolean | undefined; + jitter?: (number & z.$brand<"u53">) | undefined; + warmup?: (number & z.$brand<"u53">) | undefined; + delay?: (number & z.$brand<"u53">) | undefined; + }; + }; + display: { + width: number & z.$brand<"u53">; + height: number & z.$brand<"u53">; + } | undefined; + rotation: undefined; + flip: undefined; +}, { + track: { + name: string; + }; + config: { + broadcast?: RelativeBroadcast | undefined; + epoch?: ReferenceEpoch | undefined; + track?: string | undefined; + label?: string | undefined; + codec: string; + container: { + kind: "legacy"; + } | { + kind: "cmaf"; + init: string; + } | { + kind: "loc"; + } | { + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }; + description?: string | undefined; + codedWidth?: (number & z.$brand<"u53">) | undefined; + codedHeight?: (number & z.$brand<"u53">) | undefined; + displayAspectWidth?: (number & z.$brand<"u53">) | undefined; + displayAspectHeight?: (number & z.$brand<"u53">) | undefined; + color?: { + primaries?: (number & z.$brand<"u8">) | undefined; + transfer?: (number & z.$brand<"u8">) | undefined; + matrix?: (number & z.$brand<"u8">) | undefined; + range?: "full" | "limited" | undefined; + mastering?: { + red: { + x: number; + y: number; + }; + green: { + x: number; + y: number; + }; + blue: { + x: number; + y: number; + }; + white: { + x: number; + y: number; + }; + maxLuminance: number; + minLuminance: number; + } | undefined; + contentLight?: { + maxCll: number; + maxFall: number; + } | undefined; + } | undefined; + projection?: { + kind: "rectilinear"; + } | { + kind: "equirectangular"; + fov?: number | undefined; + } | { + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + } | undefined; + stereo?: string | undefined; + interlaced?: boolean | undefined; + framerate?: number | undefined; + reorder?: (number & z.$brand<"u8">) | undefined; + bitrate?: (number & z.$brand<"u53">) | undefined; + enabled?: boolean | undefined; + preference?: number | undefined; + optimizeForLatency?: boolean | undefined; + jitter?: (number & z.$brand<"u53">) | undefined; + warmup?: (number & z.$brand<"u53">) | undefined; + delay?: (number & z.$brand<"u53">) | undefined; + }; +}[]>>]>; + +export function wallClockTime(clock: Clock, pts: number, ptsTimescale: number): Date; + +export function watch(broadcast: Moq.Broadcast.Consumer): AsyncIterable; + + +``` diff --git a/js/hang/api/cmaf.api.md b/js/hang/api/cmaf.api.md new file mode 100644 index 00000000000..e085c62f39f --- /dev/null +++ b/js/hang/api/cmaf.api.md @@ -0,0 +1,50 @@ +## API Report File for "@moq/hang" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { Micro } from '@moq/clock'; +import type { Time } from '@moq/net'; + +export function decodeDataSegment(segment: Uint8Array, init: InitSegment, timestamp: Time.Timestamp | undefined): Sample[]; + +export function decodeInitSegment(init: Uint8Array): InitSegment; + +export class Format implements Format_2 { + constructor(init: InitSegment); + decode(payload: Uint8Array, timestamp: Time.Timestamp | undefined): Frame[]; +} + +interface Format_2 { + decode(payload: Uint8Array, timestamp: Time.Timestamp | undefined): Frame[]; + end?(frame: Frame): Micro | undefined; + readonly kind?: "audio" | "video" | "data"; +} + +interface Frame { + duration?: Micro; + keyframe: boolean; + payload: Uint8Array; + timestamp: Micro; +} + +export interface InitSegment { + defaultSampleDuration: number; + defaultSampleFlags: number; + defaultSampleSize: number; + description?: Uint8Array; + kind: "audio" | "video"; + timescale: number; + trackId: number; +} + +export interface Sample { + data: Uint8Array; + duration: number; + keyframe: boolean; + timestamp: number; +} + + +``` diff --git a/js/hang/api/container.api.md b/js/hang/api/container.api.md new file mode 100644 index 00000000000..b95f1f7cad2 --- /dev/null +++ b/js/hang/api/container.api.md @@ -0,0 +1,274 @@ +## API Report File for "@moq/hang" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { Getter } from '@moq/signals'; +import { GetterInit } from '@moq/signals'; +import * as Loc from '@moq/loc'; +import { Micro } from '@moq/clock'; +import { Milli } from '@moq/clock'; +import * as Moq from '@moq/net'; +import type { Time } from '@moq/net'; +import { Track } from '@moq/net'; +import * as z from '@zod/mini'; + +type AudioConfig = z.infer; + +const AudioConfigSchema: z.ZodMiniObject<{ + broadcast: z.ZodMiniOptional>>; + epoch: z.ZodMiniOptional>>; + track: z.ZodMiniOptional>; + label: z.ZodMiniOptional>; + codec: z.ZodMiniString; + container: z.ZodMiniDefault; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"cmaf">; + init: z.ZodMiniBase64; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"loc">; + }, z.core.$strip>], "kind">, z.ZodMiniPipe; + }, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + description: z.ZodMiniOptional>; + sampleRate: z.core.$ZodBranded, "u53", "out">; + numberOfChannels: z.core.$ZodBranded, "u53", "out">; + layout: z.ZodMiniOptional>; + bitrate: z.ZodMiniOptional, "u53", "out">>; + enabled: z.ZodMiniOptional>; + jitter: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + warmup: z.ZodMiniOptional, "u53", "out">>; + delay: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; +}, z.core.$strip>; + +export interface BufferedRange { + end: Milli; + start: Milli; +} + +export type BufferedRanges = BufferedRange[]; + +export class Consumer { + constructor(track: Moq.Track.Subscriber, props: ConsumerProps); + readonly buffered: Getter; + close(): void; + next(): Promise; + readonly spread: Getter; +} + +export interface ConsumerProps { + format: Format; + maxDelay?: GetterInit; + predecessor?: Consumer; +} + +function encodeFrame(source: Uint8Array | Source, timestamp: Micro): Uint8Array; + +export interface Format { + decode(payload: Uint8Array, timestamp: Time.Timestamp | undefined): Frame[]; + end?(frame: Frame): Micro | undefined; + readonly kind?: "audio" | "video" | "data"; +} + +class Format_2 implements Format { + constructor(config: AudioConfig | VideoConfig | "audio" | "video" | "data"); + decode(frame: Uint8Array): Frame[]; + end(frame: Frame): Micro | undefined; + finishGroup(group: Moq.Group.Producer, end?: Micro): void; + readonly kind: "audio" | "video" | "data"; +} + +export interface Frame { + duration?: Micro; + keyframe: boolean; + payload: Uint8Array; + timestamp: Micro; +} + +declare namespace Legacy { + export { + encodeFrame, + BufferedRange, + BufferedRanges, + Frame, + Format_2 as Format, + Source, + Producer + } +} + +export { Loc } + +export function mergeBufferedRanges(a: BufferedRanges, b: BufferedRanges): BufferedRanges; + +class Producer { + constructor(track: Moq.Track.Producer, format: Format_2); + close(err?: Error): void; + discontinuity(end?: Micro): void; + encode(data: Uint8Array | Source, timestamp: Micro, keyframe: boolean): void; +} + +export type Read = +/** A media frame from `group`. Only group equality means anything: numbers may skip. */ + { + kind: "frame"; + group: number; + frame: ReceivedFrame; +} +/** +* Media after an item already read will never reach this reader: a group was skipped, evicted, +* truncated, or never arrived. A decoder resumes without the references or state that media +* built. Joining mid-track is not a gap: nothing was read before it. +* +* The span is an upper bound. `timestamp` is the furthest point already read; without a +* per-frame duration that is the last frame's timestamp, one frame early. `duration` runs to +* where the next item resumes, so it also covers any declared pause in between. +*/ +| { + kind: "gap"; + timestamp: Micro; + duration: Micro; +} +/** +* The publisher declared that its media stops at `end`: it paused, switched source, or finished. +* Frames that follow from the same `group` are the stopped encoder's final packets (an audio +* codec's drain), whose output at or past `end` is padding. The next group starts fresh. +*/ +| { + kind: "end"; + group: number; + end: Micro; +}; + +export interface ReceivedFrame extends Frame { + arrival: Milli; +} + +type ReferenceEpoch = string & { + readonly _brand: "epoch"; +}; + +type RelativeBroadcast = string & { + __brand: "Relative"; +}; + +interface Source { + byteLength: number; + copyTo(buffer: Uint8Array): void; +} + +export function trackInfo(options: TrackInfoOptions): Partial; + +export type TrackInfoOptions = { + priority: number; + maxAge?: Milli; +}; + +type VideoConfig = z.infer; + +const VideoConfigSchema: z.ZodMiniObject<{ + broadcast: z.ZodMiniOptional>>; + epoch: z.ZodMiniOptional>>; + track: z.ZodMiniOptional>; + label: z.ZodMiniOptional>; + codec: z.ZodMiniString; + container: z.ZodMiniDefault; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"cmaf">; + init: z.ZodMiniBase64; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"loc">; + }, z.core.$strip>], "kind">, z.ZodMiniPipe; + }, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + description: z.ZodMiniOptional>; + codedWidth: z.ZodMiniOptional, "u53", "out">>; + codedHeight: z.ZodMiniOptional, "u53", "out">>; + displayAspectWidth: z.ZodMiniOptional, "u53", "out">>; + displayAspectHeight: z.ZodMiniOptional, "u53", "out">>; + color: z.ZodMiniOptional, "u8", "out">>; + transfer: z.ZodMiniOptional, "u8", "out">>; + matrix: z.ZodMiniOptional, "u8", "out">>; + range: z.ZodMiniOptional>; + mastering: z.ZodMiniOptional; + y: z.ZodMiniNumber; + }, z.core.$strip>; + green: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + blue: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + white: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + maxLuminance: z.ZodMiniNumber; + minLuminance: z.ZodMiniNumber; + }, z.core.$strip>>; + contentLight: z.ZodMiniOptional; + maxFall: z.ZodMiniNumber; + }, z.core.$strip>>; + }, z.core.$strip>>; + projection: z.ZodMiniOptional; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"equirectangular">; + fov: z.ZodMiniOptional>; + }, z.core.$strip>], "kind">, z.ZodMiniPipe; + }, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + stereo: z.ZodMiniOptional>; + interlaced: z.ZodMiniOptional>; + framerate: z.ZodMiniOptional>; + reorder: z.ZodMiniOptional, "u8", "out">>; + bitrate: z.ZodMiniOptional, "u53", "out">>; + enabled: z.ZodMiniOptional>; + preference: z.ZodMiniOptional; + optimizeForLatency: z.ZodMiniOptional>; + jitter: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + warmup: z.ZodMiniOptional, "u53", "out">>; + delay: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; +}, z.core.$strip>; + + +``` diff --git a/js/hang/api/index.api.md b/js/hang/api/index.api.md new file mode 100644 index 00000000000..baa73f62779 --- /dev/null +++ b/js/hang/api/index.api.md @@ -0,0 +1,2313 @@ +## API Report File for "@moq/hang" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import type { Epoch } from '@moq/net'; +import { Getter } from '@moq/signals'; +import { GetterInit } from '@moq/signals'; +import * as Json_2 from '@moq/json'; +import * as Loc from '@moq/loc'; +import { Micro } from '@moq/clock'; +import { Milli } from '@moq/clock'; +import * as Net from '@moq/net'; +import type { Path } from '@moq/net'; +import * as Signals from '@moq/signals'; +import type { Time } from '@moq/net'; +import { Track as Track_2 } from '@moq/net'; +import * as z from '@zod/mini'; +import * as z_2 from 'zod/mini'; + +type Archive = z.infer; + +const ARCHIVE_VERSION = 3; + +const ArchiveSchema: z.ZodMiniObject<{ + timelines: z.ZodMiniRecord, z.ZodMiniObject<{ + track: z.ZodMiniString; + duration: z.ZodMiniOptional, "u53", "out">>; + }, z.core.$strip>>; + timescale: z.ZodMiniDefault, "u53", "out">>; + replay: z.ZodMiniOptional>>; + replayEpoch: z.ZodMiniOptional>>; + store: z.ZodMiniOptional; + version: z.ZodMiniOptional, "u53", "out">>; +}, z.core.$strip>; + +type Arrival = z.infer; + +const ArrivalSchema: z.ZodMiniObject<{ + timestamp: z.core.$ZodBranded, "u53", "out">; + wall: z.core.$ZodBranded, "u53", "out">; +}, z.core.$strip>; + +declare namespace audio { + export { + ranked, + AudioConfigSchema, + AudioSchema, + Audio_3 as Audio, + AudioConfig + } +} + +const Audio_2: typeof audio; + +type Audio_2 = audio.Audio; + +type Audio_3 = z.infer; + +type AudioConfig = z.infer; + +const AudioConfigSchema: z.ZodMiniObject<{ + broadcast: z.ZodMiniOptional>>; + epoch: z.ZodMiniOptional>>; + track: z.ZodMiniOptional>; + label: z.ZodMiniOptional>; + codec: z.ZodMiniString; + container: z.ZodMiniDefault; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"cmaf">; + init: z.ZodMiniBase64; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"loc">; + }, z.core.$strip>], "kind">, z.ZodMiniPipe; + }, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + description: z.ZodMiniOptional>; + sampleRate: z.core.$ZodBranded, "u53", "out">; + numberOfChannels: z.core.$ZodBranded, "u53", "out">; + layout: z.ZodMiniOptional>; + bitrate: z.ZodMiniOptional, "u53", "out">>; + enabled: z.ZodMiniOptional>; + jitter: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + warmup: z.ZodMiniOptional, "u53", "out">>; + delay: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; +}, z.core.$strip>; + +const AudioSchema: z.ZodMiniUnion, z.ZodMiniObject<{ + broadcast: z.ZodMiniOptional>>; + epoch: z.ZodMiniOptional>>; + track: z.ZodMiniOptional>; + label: z.ZodMiniOptional>; + codec: z.ZodMiniString; + container: z.ZodMiniDefault; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"cmaf">; + init: z.ZodMiniBase64; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"loc">; + }, z.core.$strip>], "kind">, z.ZodMiniPipe; + }, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + description: z.ZodMiniOptional>; + sampleRate: z.core.$ZodBranded, "u53", "out">; + numberOfChannels: z.core.$ZodBranded, "u53", "out">; + layout: z.ZodMiniOptional>; + bitrate: z.ZodMiniOptional, "u53", "out">>; + enabled: z.ZodMiniOptional>; + jitter: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + warmup: z.ZodMiniOptional, "u53", "out">>; + delay: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + }, z.core.$strip>>; +}, z.core.$strip>, z.ZodMiniPipe; + }, z.core.$strip>; + config: z.ZodMiniObject<{ + broadcast: z.ZodMiniOptional>>; + epoch: z.ZodMiniOptional>>; + track: z.ZodMiniOptional>; + label: z.ZodMiniOptional>; + codec: z.ZodMiniString; + container: z.ZodMiniDefault; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"cmaf">; + init: z.ZodMiniBase64; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"loc">; + }, z.core.$strip>], "kind">, z.ZodMiniPipe; + }, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + description: z.ZodMiniOptional>; + sampleRate: z.core.$ZodBranded, "u53", "out">; + numberOfChannels: z.core.$ZodBranded, "u53", "out">; + layout: z.ZodMiniOptional>; + bitrate: z.ZodMiniOptional, "u53", "out">>; + enabled: z.ZodMiniOptional>; + jitter: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + warmup: z.ZodMiniOptional, "u53", "out">>; + delay: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + }, z.core.$strip>; +}, z.core.$strip>, z.ZodMiniTransform<{ + renditions: { + [x: string]: { + broadcast?: RelativeBroadcast | undefined; + epoch?: ReferenceEpoch | undefined; + track?: string | undefined; + label?: string | undefined; + codec: string; + container: { + kind: "legacy"; + } | { + kind: "cmaf"; + init: string; + } | { + kind: "loc"; + } | { + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }; + description?: string | undefined; + sampleRate: number & z.$brand<"u53">; + numberOfChannels: number & z.$brand<"u53">; + layout?: string | undefined; + bitrate?: (number & z.$brand<"u53">) | undefined; + enabled?: boolean | undefined; + jitter?: (number & z.$brand<"u53">) | undefined; + warmup?: (number & z.$brand<"u53">) | undefined; + delay?: (number & z.$brand<"u53">) | undefined; + }; + }; +}, { + track: { + name: string; + }; + config: { + broadcast?: RelativeBroadcast | undefined; + epoch?: ReferenceEpoch | undefined; + track?: string | undefined; + label?: string | undefined; + codec: string; + container: { + kind: "legacy"; + } | { + kind: "cmaf"; + init: string; + } | { + kind: "loc"; + } | { + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }; + description?: string | undefined; + sampleRate: number & z.$brand<"u53">; + numberOfChannels: number & z.$brand<"u53">; + layout?: string | undefined; + bitrate?: (number & z.$brand<"u53">) | undefined; + enabled?: boolean | undefined; + jitter?: (number & z.$brand<"u53">) | undefined; + warmup?: (number & z.$brand<"u53">) | undefined; + delay?: (number & z.$brand<"u53">) | undefined; + }; +}>>]>; + +type Binary = z_2.infer; + +type BinaryConfig = z_2.infer; + +const BinaryConfigSchema: z_2.ZodMiniObject<{ + broadcast: z_2.ZodMiniOptional>>; + epoch: z_2.ZodMiniOptional>>; + track: z_2.ZodMiniOptional>; + mode: z_2.ZodMiniString; + compression: z_2.ZodMiniOptional>; + mime: z_2.ZodMiniOptional>; + bitrate: z_2.ZodMiniOptional, "u53", "out">>; + jitter: z_2.ZodMiniOptional, "u53", "out">, z_2.ZodMiniTransform<(number & z_2.$brand<"u53">) | undefined, number & z_2.$brand<"u53">>>>; + delay: z_2.ZodMiniOptional, "u53", "out">, z_2.ZodMiniTransform<(number & z_2.$brand<"u53">) | undefined, number & z_2.$brand<"u53">>>>; +}, z_2.core.$loose>; + +const BinarySchema: z_2.ZodMiniObject<{ + tracks: z_2.ZodMiniRecord, z_2.ZodMiniObject<{ + broadcast: z_2.ZodMiniOptional>>; + epoch: z_2.ZodMiniOptional>>; + track: z_2.ZodMiniOptional>; + mode: z_2.ZodMiniString; + compression: z_2.ZodMiniOptional>; + mime: z_2.ZodMiniOptional>; + bitrate: z_2.ZodMiniOptional, "u53", "out">>; + jitter: z_2.ZodMiniOptional, "u53", "out">, z_2.ZodMiniTransform<(number & z_2.$brand<"u53">) | undefined, number & z_2.$brand<"u53">>>>; + delay: z_2.ZodMiniOptional, "u53", "out">, z_2.ZodMiniTransform<(number & z_2.$brand<"u53">) | undefined, number & z_2.$brand<"u53">>>>; + }, z_2.core.$loose>>; +}, z_2.core.$strip>; + +interface BufferedRange { + end: Milli; + start: Milli; +} + +type BufferedRanges = BufferedRange[]; + +declare namespace Catalog { + export { + Audio_2 as Audio, + Video, + AudioConfig, + AudioConfigSchema, + AudioSchema, + Color, + Projection, + VideoConfig, + ColorSchema, + ProjectionSchema, + VideoConfigSchema, + VideoSchema, + MOQ_EPOCH_UNIX_MILLIS, + ARCHIVE_VERSION, + ArchiveSchema, + Archive, + BinaryConfigSchema, + BinarySchema, + Binary, + BinaryConfig, + wallClockTime, + ClockSchema, + Clock, + compressionSupported, + KnownCompression, + CompressionSchema, + Compression, + containerSupported, + UnknownContainerSchema, + ContainerSchema, + Container_2 as Container, + CmafContainer, + EchoSchema, + Echo_2 as Echo, + detectFormat, + TRACK, + TRACK_COMPRESSED, + FORMATS, + Format, + DEFAULT_FORMAT, + hexSchema, + Hex, + u8, + u53, + u8Schema, + U8, + u53Schema, + U53, + nonzeroU53Schema, + JsonConfigSchema, + JsonSchema, + Json, + JsonConfig, + modeSupported, + KnownMode, + ModeSchema, + Mode, + RelativeBroadcastSchema, + RelativeBroadcast, + EpochSchema, + ReferenceEpoch, + PRIORITY, + checkRenditions, + encode, + checkResolvable, + watch, + VERSION, + UnsupportedVersion, + RootSchema, + Root, + MAX_RENDITIONS, + TooManyRenditions, + DuplicateRendition, + EscapingBroadcast, + StatsSchema, + Stats_2 as Stats, + TextFormatSchema, + TextRoleSchema, + TextConfigSchema, + TextSchema, + Text_2 as Text, + TextConfig, + TextRole, + track, + TrackSchema, + Track + } +} + +declare namespace Catalog_2 { + export { + Audio_2 as Audio, + Video, + AudioConfig, + AudioConfigSchema, + AudioSchema, + Color, + Projection, + VideoConfig, + ColorSchema, + ProjectionSchema, + VideoConfigSchema, + VideoSchema, + MOQ_EPOCH_UNIX_MILLIS, + ARCHIVE_VERSION, + ArchiveSchema, + Archive, + BinaryConfigSchema, + BinarySchema, + Binary, + BinaryConfig, + wallClockTime, + ClockSchema, + Clock, + compressionSupported, + KnownCompression, + CompressionSchema, + Compression, + containerSupported, + UnknownContainerSchema, + ContainerSchema, + Container_2 as Container, + CmafContainer, + EchoSchema, + Echo_2 as Echo, + detectFormat, + TRACK, + TRACK_COMPRESSED, + FORMATS, + Format, + DEFAULT_FORMAT, + hexSchema, + Hex, + u8, + u53, + u8Schema, + U8, + u53Schema, + U53, + nonzeroU53Schema, + JsonConfigSchema, + JsonSchema, + Json, + JsonConfig, + modeSupported, + KnownMode, + ModeSchema, + Mode, + RelativeBroadcastSchema, + RelativeBroadcast, + EpochSchema, + ReferenceEpoch, + PRIORITY, + checkRenditions, + encode, + checkResolvable, + watch, + VERSION, + UnsupportedVersion, + RootSchema, + Root, + MAX_RENDITIONS, + TooManyRenditions, + DuplicateRendition, + EscapingBroadcast, + StatsSchema, + Stats_2 as Stats, + TextFormatSchema, + TextRoleSchema, + TextConfigSchema, + TextSchema, + Text_2 as Text, + TextConfig, + TextRole, + track, + TrackSchema, + Track + } +} + +function checkRenditions(root: Root): Root; + +function checkResolvable(root: Root, base: Net.Path.Valid): Root; + +type Clock = z.infer; + +const ClockSchema: z.ZodMiniObject<{ + wall: z.core.$ZodBranded, "u53", "out">; + timescale: z.ZodMiniDefault>; +}, z.core.$strip>; + +type CmafContainer = Extract; + +type Color = z.infer; + +const ColorSchema: z.ZodMiniObject<{ + primaries: z.ZodMiniOptional, "u8", "out">>; + transfer: z.ZodMiniOptional, "u8", "out">>; + matrix: z.ZodMiniOptional, "u8", "out">>; + range: z.ZodMiniOptional>; + mastering: z.ZodMiniOptional; + y: z.ZodMiniNumber; + }, z.core.$strip>; + green: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + blue: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + white: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + maxLuminance: z.ZodMiniNumber; + minLuminance: z.ZodMiniNumber; + }, z.core.$strip>>; + contentLight: z.ZodMiniOptional; + maxFall: z.ZodMiniNumber; + }, z.core.$strip>>; +}, z.core.$strip>; + +type Compression = z_2.infer; + +const CompressionSchema: z_2.ZodMiniString; + +function compressionSupported(compression: Compression): compression is KnownCompression; + +interface Connection { + evidence: Evidence[]; + lostBytes?: number; + lostPackets?: number; + stale?: true; + verdict: Verdict; +} + +class Consumer { + constructor(track: Net.Track.Subscriber, props: ConsumerProps); + readonly buffered: Getter; + close(): void; + next(): Promise; + readonly spread: Getter; +} + +class Consumer_2 implements AsyncIterable { + [Symbol.asyncIterator](): AsyncIterator; + close(): void; + next(): Promise; + static subscribe(broadcast: Net.Broadcast.Consumer, archive: Catalog_2.Archive, track: string): Consumer_2; +} + +interface ConsumerProps { + format: Format_2; + maxDelay?: GetterInit; + predecessor?: Consumer; +} + +declare namespace Container { + export { + Loc, + Consumer, + ConsumerProps, + Read, + Format_2 as Format, + Legacy, + TrackInfoOptions, + trackInfo, + mergeBufferedRanges, + Frame, + ReceivedFrame, + BufferedRange, + BufferedRanges + } +} + +type Container_2 = z.infer; + +const ContainerSchema: z.ZodMiniDefault; +}, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"cmaf">; + init: z.ZodMiniBase64; +}, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"loc">; +}, z.core.$strip>], "kind">, z.ZodMiniPipe; +}, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; +}, { + [x: string]: unknown; + kind: string; +}>>]>>; + +function containerSupported(container: Container_2): boolean; + +const DEFAULT_FORMAT: Format; + +function defaultThresholds(): Thresholds; + +function detectFormat(name: string): Format | undefined; + +class DuplicateRendition extends Error { + constructor(id: string); + readonly id: string; +} + +declare namespace Echo { + export { + isEcho, + ArrivalSchema, + Arrival, + RenditionSchema, + Rendition, + SnapshotSchema, + Snapshot, + SUFFIX, + TRACK_2 as TRACK + } +} + +type Echo_2 = z.infer; + +declare namespace Echo_3 { + export { + isEcho, + ArrivalSchema, + Arrival, + RenditionSchema, + Rendition, + SnapshotSchema, + Snapshot, + SUFFIX, + TRACK_2 as TRACK + } +} + +const EchoSchema: z.ZodMiniObject<{ + path: z.ZodMiniType>; +}, z.core.$strip>; + +function encode(root: Root): Root; + +function encodeFrame(source: Uint8Array | Source, timestamp: Micro): Uint8Array; + +type Entry = Omit & { + pts: Micro; + duration: Micro; +}; + +const EpochSchema: z.ZodMiniType; + +class EscapingBroadcast extends Error { + constructor(broadcast: RelativeBroadcast); + readonly broadcast: RelativeBroadcast; +} + +type Event_2 = { + push: { + index: number; + entry: Entry; + }; +} | { + pop: Json_2.Window.Span; +} | { + skip: Json_2.Window.Span; +}; + +interface Evidence { + input: Input; + value?: number; + verdict: Verdict; +} + +type Format = (typeof FORMATS)[number]; + +interface Format_2 { + decode(payload: Uint8Array, timestamp: Time.Timestamp | undefined): Frame[]; + end?(frame: Frame): Micro | undefined; + readonly kind?: "audio" | "video" | "data"; +} + +class Format_3 implements Format_2 { + constructor(config: AudioConfig | VideoConfig | "audio" | "video" | "data"); + decode(frame: Uint8Array): Frame[]; + end(frame: Frame): Micro | undefined; + finishGroup(group: Net.Group.Producer, end?: Micro): void; + readonly kind: "audio" | "video" | "data"; +} + +const FORMATS: readonly ["hang", "msf"]; + +interface Frame { + duration?: Micro; + keyframe: boolean; + payload: Uint8Array; + timestamp: Micro; +} + +declare namespace Health { + export { + defaultThresholds, + publisher, + viewer, + Verdict, + Role, + Observer, + Report_2 as Report, + Sample, + Limits, + Thresholds, + Reset, + Input, + Evidence, + Connection, + Rendition_3 as Rendition, + Health_2 as Health + } +} + +interface Health_2 { + interval?: number; + observer: Observer; + renditions: Record; + reset?: Reset; + role: Role; + stale?: true; + transport: Connection; + verdict: Verdict; +} + +type Hex = z.infer; + +const hexSchema: z.ZodMiniString; + +type Input = "rtt" | "loss" | "headroom" | "skipped" | "late" | "errors" | "stalled"; + +function isEcho(path: Path.Valid): boolean; + +type Json = z_2.infer; + +type JsonConfig = z_2.infer; + +const JsonConfigSchema: z_2.ZodMiniObject<{ + broadcast: z_2.ZodMiniOptional>>; + epoch: z_2.ZodMiniOptional>>; + track: z_2.ZodMiniOptional>; + mode: z_2.ZodMiniString; + compression: z_2.ZodMiniOptional>; + schema: z_2.ZodMiniOptional>; + bitrate: z_2.ZodMiniOptional, "u53", "out">>; + jitter: z_2.ZodMiniOptional, "u53", "out">, z_2.ZodMiniTransform<(number & z_2.$brand<"u53">) | undefined, number & z_2.$brand<"u53">>>>; + delay: z_2.ZodMiniOptional, "u53", "out">, z_2.ZodMiniTransform<(number & z_2.$brand<"u53">) | undefined, number & z_2.$brand<"u53">>>>; +}, z_2.core.$loose>; + +const JsonSchema: z_2.ZodMiniObject<{ + tracks: z_2.ZodMiniRecord, z_2.ZodMiniObject<{ + broadcast: z_2.ZodMiniOptional>>; + epoch: z_2.ZodMiniOptional>>; + track: z_2.ZodMiniOptional>; + mode: z_2.ZodMiniString; + compression: z_2.ZodMiniOptional>; + schema: z_2.ZodMiniOptional>; + bitrate: z_2.ZodMiniOptional, "u53", "out">>; + jitter: z_2.ZodMiniOptional, "u53", "out">, z_2.ZodMiniTransform<(number & z_2.$brand<"u53">) | undefined, number & z_2.$brand<"u53">>>>; + delay: z_2.ZodMiniOptional, "u53", "out">, z_2.ZodMiniTransform<(number & z_2.$brand<"u53">) | undefined, number & z_2.$brand<"u53">>>>; + }, z_2.core.$loose>>; +}, z_2.core.$strip>; + +type KnownCompression = "deflate"; + +type KnownMode = "snapshot" | "stream"; + +declare namespace Legacy { + export { + encodeFrame, + BufferedRange, + BufferedRanges, + Frame, + Format_3 as Format, + Source, + Producer + } +} + +interface Limits { + degraded: number; + unhealthy: number; +} + +const MAX_RENDITIONS = 64; + +function mergeBufferedRanges(a: BufferedRanges, b: BufferedRanges): BufferedRanges; + +type Mode = z_2.infer; + +const ModeSchema: z_2.ZodMiniString; + +function modeSupported(mode: Mode): mode is KnownMode; + +const MOQ_EPOCH_UNIX_MILLIS = 1577836800000; + +export { Net } + +const nonzeroU53Schema: z.core.$ZodBranded, "u53", "out">; + +interface Observer { + epoch?: Epoch.Valid; + path: Path.Valid; +} + +interface Position_2 { + frame?: number; + group: number; +} + +const PRIORITY: { + readonly catalog: 100; + readonly text: 90; + readonly audio: 80; + readonly video: 60; +}; + +class Producer { + constructor(track: Net.Track.Producer, format: Format_3); + close(err?: Error): void; + discontinuity(end?: Micro): void; + encode(data: Uint8Array | Source, timestamp: Micro, keyframe: boolean): void; +} + +type Projection = z.infer; + +const ProjectionSchema: z.ZodMiniUnion; +}, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"equirectangular">; + fov: z.ZodMiniOptional>; +}, z.core.$strip>], "kind">, z.ZodMiniPipe; +}, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; +}, { + [x: string]: unknown; + kind: string; +}>>]>; + +function publisher(sample: Sample, thresholds?: Thresholds): Health_2; + +function ranked(renditions: Record): [string, AudioConfig][]; + +function ranked_2(renditions: Record): [string, VideoConfig][]; + +type Read = +/** A media frame from `group`. Only group equality means anything: numbers may skip. */ + { + kind: "frame"; + group: number; + frame: ReceivedFrame; +} +/** +* Media after an item already read will never reach this reader: a group was skipped, evicted, +* truncated, or never arrived. A decoder resumes without the references or state that media +* built. Joining mid-track is not a gap: nothing was read before it. +* +* The span is an upper bound. `timestamp` is the furthest point already read; without a +* per-frame duration that is the last frame's timestamp, one frame early. `duration` runs to +* where the next item resumes, so it also covers any declared pause in between. +*/ +| { + kind: "gap"; + timestamp: Micro; + duration: Micro; +} +/** +* The publisher declared that its media stops at `end`: it paused, switched source, or finished. +* Frames that follow from the same `group` are the stopped encoder's final packets (an audio +* codec's drain), whose output at or past `end` is padding. The next group starts fresh. +*/ +| { + kind: "end"; + group: number; + end: Micro; +}; + +interface ReceivedFrame extends Frame { + arrival: Milli; +} + +interface Record_2 { + duration?: number; + end: Position_2; + keyframe?: boolean; + pts?: number; + sequence: number; + start: Position_2; +} + +type ReferenceEpoch = string & { + readonly _brand: "epoch"; +}; + +type RelativeBroadcast = string & { + __brand: "Relative"; +}; + +const RelativeBroadcastSchema: z.ZodMiniType; + +type Rendition = z.infer; + +type Rendition_2 = z.infer; + +interface Rendition_3 { + bitrate?: number; + bytes?: number; + evidence: Evidence[]; + frames?: number; + verdict: Verdict; +} + +const RenditionSchema: z.ZodMiniObject<{ + frames: z.ZodMiniOptional, "u53", "out">>; + bytes: z.ZodMiniOptional, "u53", "out">>; + decoded: z.ZodMiniOptional, "u53", "out">>; + late: z.ZodMiniOptional, "u53", "out">>; + errors: z.ZodMiniOptional, "u53", "out">>; + stalls: z.ZodMiniOptional, "u53", "out">>; + stalled: z.ZodMiniOptional, "u53", "out">>; + underruns: z.ZodMiniOptional, "u53", "out">>; + arrival: z.ZodMiniOptional, "u53", "out">; + wall: z.core.$ZodBranded, "u53", "out">; + }, z.core.$strip>>, z.ZodMiniTransform<{ + timestamp: number & z.$brand<"u53">; + wall: number & z.$brand<"u53">; + } | undefined, { + timestamp: number & z.$brand<"u53">; + wall: number & z.$brand<"u53">; + } | null>>>; + latency: z.ZodMiniOptional, "u53", "out">>, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, (number & z.$brand<"u53">) | null>>>; +}, z.core.$strip>; + +const RenditionSchema_2: z.ZodMiniObject<{ + frames: z.ZodMiniOptional, "u53", "out">>; + bytes: z.ZodMiniOptional, "u53", "out">>; + keyframes: z.ZodMiniOptional, "u53", "out">>; + skipped: z.ZodMiniOptional, "u53", "out">>; + bitrate: z.ZodMiniOptional, "u53", "out">>, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, (number & z.$brand<"u53">) | null>>>; +}, z.core.$strip>; + +interface Report_2 { + observer: Observer; + snapshot: S; +} + +type Reset = "decrease" | "replaced"; + +type Role = "publisher" | "viewer"; + +type Root = z.infer; + +const RootSchema: z.ZodMiniObject<{ + version: z.ZodMiniOptional>; + video: z.ZodMiniOptional, z.ZodMiniObject<{ + broadcast: z.ZodMiniOptional>>; + epoch: z.ZodMiniOptional>>; + track: z.ZodMiniOptional>; + label: z.ZodMiniOptional>; + codec: z.ZodMiniString; + container: z.ZodMiniDefault; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"cmaf">; + init: z.ZodMiniBase64; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"loc">; + }, z.core.$strip>], "kind">, z.ZodMiniPipe; + }, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + description: z.ZodMiniOptional>; + codedWidth: z.ZodMiniOptional, "u53", "out">>; + codedHeight: z.ZodMiniOptional, "u53", "out">>; + displayAspectWidth: z.ZodMiniOptional, "u53", "out">>; + displayAspectHeight: z.ZodMiniOptional, "u53", "out">>; + color: z.ZodMiniOptional, "u8", "out">>; + transfer: z.ZodMiniOptional, "u8", "out">>; + matrix: z.ZodMiniOptional, "u8", "out">>; + range: z.ZodMiniOptional>; + mastering: z.ZodMiniOptional; + y: z.ZodMiniNumber; + }, z.core.$strip>; + green: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + blue: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + white: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + maxLuminance: z.ZodMiniNumber; + minLuminance: z.ZodMiniNumber; + }, z.core.$strip>>; + contentLight: z.ZodMiniOptional; + maxFall: z.ZodMiniNumber; + }, z.core.$strip>>; + }, z.core.$strip>>; + projection: z.ZodMiniOptional; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"equirectangular">; + fov: z.ZodMiniOptional>; + }, z.core.$strip>], "kind">, z.ZodMiniPipe; + }, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + stereo: z.ZodMiniOptional>; + interlaced: z.ZodMiniOptional>; + framerate: z.ZodMiniOptional>; + reorder: z.ZodMiniOptional, "u8", "out">>; + bitrate: z.ZodMiniOptional, "u53", "out">>; + enabled: z.ZodMiniOptional>; + preference: z.ZodMiniOptional; + optimizeForLatency: z.ZodMiniOptional>; + jitter: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + warmup: z.ZodMiniOptional, "u53", "out">>; + delay: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + }, z.core.$strip>>; + display: z.ZodMiniOptional, "u53", "out">; + height: z.core.$ZodBranded, "u53", "out">; + }, z.core.$strip>>; + rotation: z.ZodMiniOptional>; + flip: z.ZodMiniOptional>; + }, z.core.$strip>, z.ZodMiniPipe; + }, z.core.$strip>; + config: z.ZodMiniObject<{ + broadcast: z.ZodMiniOptional>>; + epoch: z.ZodMiniOptional>>; + track: z.ZodMiniOptional>; + label: z.ZodMiniOptional>; + codec: z.ZodMiniString; + container: z.ZodMiniDefault; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"cmaf">; + init: z.ZodMiniBase64; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"loc">; + }, z.core.$strip>], "kind">, z.ZodMiniPipe; + }, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + description: z.ZodMiniOptional>; + codedWidth: z.ZodMiniOptional, "u53", "out">>; + codedHeight: z.ZodMiniOptional, "u53", "out">>; + displayAspectWidth: z.ZodMiniOptional, "u53", "out">>; + displayAspectHeight: z.ZodMiniOptional, "u53", "out">>; + color: z.ZodMiniOptional, "u8", "out">>; + transfer: z.ZodMiniOptional, "u8", "out">>; + matrix: z.ZodMiniOptional, "u8", "out">>; + range: z.ZodMiniOptional>; + mastering: z.ZodMiniOptional; + y: z.ZodMiniNumber; + }, z.core.$strip>; + green: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + blue: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + white: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + maxLuminance: z.ZodMiniNumber; + minLuminance: z.ZodMiniNumber; + }, z.core.$strip>>; + contentLight: z.ZodMiniOptional; + maxFall: z.ZodMiniNumber; + }, z.core.$strip>>; + }, z.core.$strip>>; + projection: z.ZodMiniOptional; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"equirectangular">; + fov: z.ZodMiniOptional>; + }, z.core.$strip>], "kind">, z.ZodMiniPipe; + }, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + stereo: z.ZodMiniOptional>; + interlaced: z.ZodMiniOptional>; + framerate: z.ZodMiniOptional>; + reorder: z.ZodMiniOptional, "u8", "out">>; + bitrate: z.ZodMiniOptional, "u53", "out">>; + enabled: z.ZodMiniOptional>; + preference: z.ZodMiniOptional; + optimizeForLatency: z.ZodMiniOptional>; + jitter: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + warmup: z.ZodMiniOptional, "u53", "out">>; + delay: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + }, z.core.$strip>; + }, z.core.$strip>>, z.ZodMiniTransform<{ + renditions: { + [k: string]: { + broadcast?: RelativeBroadcast | undefined; + epoch?: ReferenceEpoch | undefined; + track?: string | undefined; + label?: string | undefined; + codec: string; + container: { + kind: "legacy"; + } | { + kind: "cmaf"; + init: string; + } | { + kind: "loc"; + } | { + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }; + description?: string | undefined; + codedWidth?: (number & z.$brand<"u53">) | undefined; + codedHeight?: (number & z.$brand<"u53">) | undefined; + displayAspectWidth?: (number & z.$brand<"u53">) | undefined; + displayAspectHeight?: (number & z.$brand<"u53">) | undefined; + color?: { + primaries?: (number & z.$brand<"u8">) | undefined; + transfer?: (number & z.$brand<"u8">) | undefined; + matrix?: (number & z.$brand<"u8">) | undefined; + range?: "full" | "limited" | undefined; + mastering?: { + red: { + x: number; + y: number; + }; + green: { + x: number; + y: number; + }; + blue: { + x: number; + y: number; + }; + white: { + x: number; + y: number; + }; + maxLuminance: number; + minLuminance: number; + } | undefined; + contentLight?: { + maxCll: number; + maxFall: number; + } | undefined; + } | undefined; + projection?: { + kind: "rectilinear"; + } | { + kind: "equirectangular"; + fov?: number | undefined; + } | { + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + } | undefined; + stereo?: string | undefined; + interlaced?: boolean | undefined; + framerate?: number | undefined; + reorder?: (number & z.$brand<"u8">) | undefined; + bitrate?: (number & z.$brand<"u53">) | undefined; + enabled?: boolean | undefined; + preference?: number | undefined; + optimizeForLatency?: boolean | undefined; + jitter?: (number & z.$brand<"u53">) | undefined; + warmup?: (number & z.$brand<"u53">) | undefined; + delay?: (number & z.$brand<"u53">) | undefined; + }; + }; + display: { + width: number & z.$brand<"u53">; + height: number & z.$brand<"u53">; + } | undefined; + rotation: undefined; + flip: undefined; + }, { + track: { + name: string; + }; + config: { + broadcast?: RelativeBroadcast | undefined; + epoch?: ReferenceEpoch | undefined; + track?: string | undefined; + label?: string | undefined; + codec: string; + container: { + kind: "legacy"; + } | { + kind: "cmaf"; + init: string; + } | { + kind: "loc"; + } | { + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }; + description?: string | undefined; + codedWidth?: (number & z.$brand<"u53">) | undefined; + codedHeight?: (number & z.$brand<"u53">) | undefined; + displayAspectWidth?: (number & z.$brand<"u53">) | undefined; + displayAspectHeight?: (number & z.$brand<"u53">) | undefined; + color?: { + primaries?: (number & z.$brand<"u8">) | undefined; + transfer?: (number & z.$brand<"u8">) | undefined; + matrix?: (number & z.$brand<"u8">) | undefined; + range?: "full" | "limited" | undefined; + mastering?: { + red: { + x: number; + y: number; + }; + green: { + x: number; + y: number; + }; + blue: { + x: number; + y: number; + }; + white: { + x: number; + y: number; + }; + maxLuminance: number; + minLuminance: number; + } | undefined; + contentLight?: { + maxCll: number; + maxFall: number; + } | undefined; + } | undefined; + projection?: { + kind: "rectilinear"; + } | { + kind: "equirectangular"; + fov?: number | undefined; + } | { + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + } | undefined; + stereo?: string | undefined; + interlaced?: boolean | undefined; + framerate?: number | undefined; + reorder?: (number & z.$brand<"u8">) | undefined; + bitrate?: (number & z.$brand<"u53">) | undefined; + enabled?: boolean | undefined; + preference?: number | undefined; + optimizeForLatency?: boolean | undefined; + jitter?: (number & z.$brand<"u53">) | undefined; + warmup?: (number & z.$brand<"u53">) | undefined; + delay?: (number & z.$brand<"u53">) | undefined; + }; + }[]>>]>>; + audio: z.ZodMiniOptional, z.ZodMiniObject<{ + broadcast: z.ZodMiniOptional>>; + epoch: z.ZodMiniOptional>>; + track: z.ZodMiniOptional>; + label: z.ZodMiniOptional>; + codec: z.ZodMiniString; + container: z.ZodMiniDefault; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"cmaf">; + init: z.ZodMiniBase64; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"loc">; + }, z.core.$strip>], "kind">, z.ZodMiniPipe; + }, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + description: z.ZodMiniOptional>; + sampleRate: z.core.$ZodBranded, "u53", "out">; + numberOfChannels: z.core.$ZodBranded, "u53", "out">; + layout: z.ZodMiniOptional>; + bitrate: z.ZodMiniOptional, "u53", "out">>; + enabled: z.ZodMiniOptional>; + jitter: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + warmup: z.ZodMiniOptional, "u53", "out">>; + delay: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + }, z.core.$strip>>; + }, z.core.$strip>, z.ZodMiniPipe; + }, z.core.$strip>; + config: z.ZodMiniObject<{ + broadcast: z.ZodMiniOptional>>; + epoch: z.ZodMiniOptional>>; + track: z.ZodMiniOptional>; + label: z.ZodMiniOptional>; + codec: z.ZodMiniString; + container: z.ZodMiniDefault; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"cmaf">; + init: z.ZodMiniBase64; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"loc">; + }, z.core.$strip>], "kind">, z.ZodMiniPipe; + }, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + description: z.ZodMiniOptional>; + sampleRate: z.core.$ZodBranded, "u53", "out">; + numberOfChannels: z.core.$ZodBranded, "u53", "out">; + layout: z.ZodMiniOptional>; + bitrate: z.ZodMiniOptional, "u53", "out">>; + enabled: z.ZodMiniOptional>; + jitter: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + warmup: z.ZodMiniOptional, "u53", "out">>; + delay: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + }, z.core.$strip>; + }, z.core.$strip>, z.ZodMiniTransform<{ + renditions: { + [x: string]: { + broadcast?: RelativeBroadcast | undefined; + epoch?: ReferenceEpoch | undefined; + track?: string | undefined; + label?: string | undefined; + codec: string; + container: { + kind: "legacy"; + } | { + kind: "cmaf"; + init: string; + } | { + kind: "loc"; + } | { + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }; + description?: string | undefined; + sampleRate: number & z.$brand<"u53">; + numberOfChannels: number & z.$brand<"u53">; + layout?: string | undefined; + bitrate?: (number & z.$brand<"u53">) | undefined; + enabled?: boolean | undefined; + jitter?: (number & z.$brand<"u53">) | undefined; + warmup?: (number & z.$brand<"u53">) | undefined; + delay?: (number & z.$brand<"u53">) | undefined; + }; + }; + }, { + track: { + name: string; + }; + config: { + broadcast?: RelativeBroadcast | undefined; + epoch?: ReferenceEpoch | undefined; + track?: string | undefined; + label?: string | undefined; + codec: string; + container: { + kind: "legacy"; + } | { + kind: "cmaf"; + init: string; + } | { + kind: "loc"; + } | { + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }; + description?: string | undefined; + sampleRate: number & z.$brand<"u53">; + numberOfChannels: number & z.$brand<"u53">; + layout?: string | undefined; + bitrate?: (number & z.$brand<"u53">) | undefined; + enabled?: boolean | undefined; + jitter?: (number & z.$brand<"u53">) | undefined; + warmup?: (number & z.$brand<"u53">) | undefined; + delay?: (number & z.$brand<"u53">) | undefined; + }; + }>>]>>; + archive: z.ZodMiniCatch, z.ZodMiniObject<{ + track: z.ZodMiniString; + duration: z.ZodMiniOptional, "u53", "out">>; + }, z.core.$strip>>; + timescale: z.ZodMiniDefault, "u53", "out">>; + replay: z.ZodMiniOptional>>; + replayEpoch: z.ZodMiniOptional>>; + store: z.ZodMiniOptional; + version: z.ZodMiniOptional, "u53", "out">>; + }, z.core.$strip>>>; + clock: z.ZodMiniOptional, "u53", "out">; + timescale: z.ZodMiniDefault>; + }, z.core.$strip>>; + stats: z.ZodMiniOptional; + }, z.core.$strip>, z.ZodMiniPipe, z.ZodMiniTransform>]>>; + echo: z.ZodMiniOptional>; + }, z.core.$strip>, z.ZodMiniPipe, z.ZodMiniTransform>]>>; + text: z.ZodMiniOptional, z.ZodMiniObject<{ + broadcast: z.ZodMiniOptional>>; + epoch: z.ZodMiniOptional>>; + track: z.ZodMiniOptional>; + format: z.ZodMiniString; + role: z.ZodMiniDefault>; + lang: z.ZodMiniOptional>; + label: z.ZodMiniOptional>; + container: z.ZodMiniDefault; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"cmaf">; + init: z.ZodMiniBase64; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"loc">; + }, z.core.$strip>], "kind">, z.ZodMiniPipe; + }, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + jitter: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + delay: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + }, z.core.$strip>>; + }, z.core.$strip>, z.ZodMiniPipe, z.ZodMiniTransform>]>>; + json: z.ZodMiniOptional, z.ZodMiniObject<{ + broadcast: z.ZodMiniOptional>>; + epoch: z.ZodMiniOptional>>; + track: z.ZodMiniOptional>; + mode: z.ZodMiniString; + compression: z.ZodMiniOptional>; + schema: z.ZodMiniOptional>; + bitrate: z.ZodMiniOptional, "u53", "out">>; + jitter: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + delay: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + }, z.core.$loose>>; + }, z.core.$strip>, z.ZodMiniPipe, z.ZodMiniTransform>]>>; + binary: z.ZodMiniOptional, z.ZodMiniObject<{ + broadcast: z.ZodMiniOptional>>; + epoch: z.ZodMiniOptional>>; + track: z.ZodMiniOptional>; + mode: z.ZodMiniString; + compression: z.ZodMiniOptional>; + mime: z.ZodMiniOptional>; + bitrate: z.ZodMiniOptional, "u53", "out">>; + jitter: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + delay: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + }, z.core.$loose>>; + }, z.core.$strip>, z.ZodMiniPipe, z.ZodMiniTransform>]>>; +}, z.core.$loose>; + +interface Sample { + age: number; + current: Report_2; + interval: number; + previous?: Report_2; +} + +export { Signals } + +type Snapshot = z.infer; + +type Snapshot_2 = z.infer; + +const SnapshotSchema: z.ZodMiniObject<{ + transport: z.ZodMiniOptional, "u53", "out">>, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, (number & z.$brand<"u53">) | null>>>; + rate: z.ZodMiniOptional, "u53", "out">>, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, (number & z.$brand<"u53">) | null>>>; + lostBytes: z.ZodMiniOptional, "u53", "out">>, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, (number & z.$brand<"u53">) | null>>>; + lostPackets: z.ZodMiniOptional, "u53", "out">>, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, (number & z.$brand<"u53">) | null>>>; + age: z.ZodMiniOptional, "u53", "out">>, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, (number & z.$brand<"u53">) | null>>>; + }, z.core.$strip>>; + renditions: z.ZodMiniOptional, z.ZodMiniObject<{ + frames: z.ZodMiniOptional, "u53", "out">>; + bytes: z.ZodMiniOptional, "u53", "out">>; + decoded: z.ZodMiniOptional, "u53", "out">>; + late: z.ZodMiniOptional, "u53", "out">>; + errors: z.ZodMiniOptional, "u53", "out">>; + stalls: z.ZodMiniOptional, "u53", "out">>; + stalled: z.ZodMiniOptional, "u53", "out">>; + underruns: z.ZodMiniOptional, "u53", "out">>; + arrival: z.ZodMiniOptional, "u53", "out">; + wall: z.core.$ZodBranded, "u53", "out">; + }, z.core.$strip>>, z.ZodMiniTransform<{ + timestamp: number & z.$brand<"u53">; + wall: number & z.$brand<"u53">; + } | undefined, { + timestamp: number & z.$brand<"u53">; + wall: number & z.$brand<"u53">; + } | null>>>; + latency: z.ZodMiniOptional, "u53", "out">>, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, (number & z.$brand<"u53">) | null>>>; + }, z.core.$strip>>>; +}, z.core.$loose>; + +const SnapshotSchema_2: z.ZodMiniObject<{ + transport: z.ZodMiniOptional, "u53", "out">>, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, (number & z.$brand<"u53">) | null>>>; + rate: z.ZodMiniOptional, "u53", "out">>, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, (number & z.$brand<"u53">) | null>>>; + lostBytes: z.ZodMiniOptional, "u53", "out">>, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, (number & z.$brand<"u53">) | null>>>; + lostPackets: z.ZodMiniOptional, "u53", "out">>, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, (number & z.$brand<"u53">) | null>>>; + age: z.ZodMiniOptional, "u53", "out">>, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, (number & z.$brand<"u53">) | null>>>; + }, z.core.$strip>>; + renditions: z.ZodMiniOptional, z.ZodMiniObject<{ + frames: z.ZodMiniOptional, "u53", "out">>; + bytes: z.ZodMiniOptional, "u53", "out">>; + keyframes: z.ZodMiniOptional, "u53", "out">>; + skipped: z.ZodMiniOptional, "u53", "out">>; + bitrate: z.ZodMiniOptional, "u53", "out">>, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, (number & z.$brand<"u53">) | null>>>; + }, z.core.$strip>>>; +}, z.core.$loose>; + +interface Source { + byteLength: number; + copyTo(buffer: Uint8Array): void; +} + +declare namespace Stats { + export { + TransportSchema, + Transport, + RenditionSchema_2 as RenditionSchema, + Rendition_2 as Rendition, + SnapshotSchema_2 as SnapshotSchema, + Snapshot_2 as Snapshot + } +} + +type Stats_2 = z.infer; + +declare namespace Stats_3 { + export { + TransportSchema, + Transport, + RenditionSchema_2 as RenditionSchema, + Rendition_2 as Rendition, + SnapshotSchema_2 as SnapshotSchema, + Snapshot_2 as Snapshot + } +} + +const StatsSchema: z.ZodMiniObject<{ + track: z.ZodMiniString; +}, z.core.$strip>; + +const SUFFIX = ".echo"; + +const SUFFIX_2 = ".timeline.z"; + +type Text_2 = z_2.infer; + +type TextConfig = z_2.infer; + +const TextConfigSchema: z_2.ZodMiniObject<{ + broadcast: z_2.ZodMiniOptional>>; + epoch: z_2.ZodMiniOptional>>; + track: z_2.ZodMiniOptional>; + format: z_2.ZodMiniString; + role: z_2.ZodMiniDefault>; + lang: z_2.ZodMiniOptional>; + label: z_2.ZodMiniOptional>; + container: z_2.ZodMiniDefault; + }, z_2.core.$strip>, z_2.ZodMiniObject<{ + kind: z_2.ZodMiniLiteral<"cmaf">; + init: z_2.ZodMiniBase64; + }, z_2.core.$strip>, z_2.ZodMiniObject<{ + kind: z_2.ZodMiniLiteral<"loc">; + }, z_2.core.$strip>], "kind">, z_2.ZodMiniPipe; + }, z_2.core.$loose>, z_2.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + jitter: z_2.ZodMiniOptional, "u53", "out">, z_2.ZodMiniTransform<(number & z_2.$brand<"u53">) | undefined, number & z_2.$brand<"u53">>>>; + delay: z_2.ZodMiniOptional, "u53", "out">, z_2.ZodMiniTransform<(number & z_2.$brand<"u53">) | undefined, number & z_2.$brand<"u53">>>>; +}, z_2.core.$strip>; + +const TextFormatSchema: z_2.ZodMiniString; + +type TextRole = z_2.infer; + +const TextRoleSchema: z_2.ZodMiniString; + +const TextSchema: z_2.ZodMiniObject<{ + renditions: z_2.ZodMiniRecord, z_2.ZodMiniObject<{ + broadcast: z_2.ZodMiniOptional>>; + epoch: z_2.ZodMiniOptional>>; + track: z_2.ZodMiniOptional>; + format: z_2.ZodMiniString; + role: z_2.ZodMiniDefault>; + lang: z_2.ZodMiniOptional>; + label: z_2.ZodMiniOptional>; + container: z_2.ZodMiniDefault; + }, z_2.core.$strip>, z_2.ZodMiniObject<{ + kind: z_2.ZodMiniLiteral<"cmaf">; + init: z_2.ZodMiniBase64; + }, z_2.core.$strip>, z_2.ZodMiniObject<{ + kind: z_2.ZodMiniLiteral<"loc">; + }, z_2.core.$strip>], "kind">, z_2.ZodMiniPipe; + }, z_2.core.$loose>, z_2.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + jitter: z_2.ZodMiniOptional, "u53", "out">, z_2.ZodMiniTransform<(number & z_2.$brand<"u53">) | undefined, number & z_2.$brand<"u53">>>>; + delay: z_2.ZodMiniOptional, "u53", "out">, z_2.ZodMiniTransform<(number & z_2.$brand<"u53">) | undefined, number & z_2.$brand<"u53">>>>; + }, z_2.core.$strip>>; +}, z_2.core.$strip>; + +interface Thresholds { + publisher: { + skipped: Limits; + }; + stale: number; + transport: { + rtt: Limits; + loss: Limits; + headroom: Limits; + }; + viewer: { + late: Limits; + errors: Limits; + stalled: Limits; + }; +} + +declare namespace Timeline { + export { + Position_2 as Position, + Record_2 as Record, + SUFFIX_2 as SUFFIX, + Entry, + Event_2 as Event, + Consumer_2 as Consumer + } +} + +class TooManyRenditions extends Error { + constructor(count: number); + readonly count: number; +} + +const TRACK = "catalog.json"; + +type Track = z.infer; + +function track(id: string, config: { + track?: string; +}): string; + +const TRACK_2 = "feedback.json"; + +const TRACK_COMPRESSED = "catalog.json.z"; + +function trackInfo(options: TrackInfoOptions): Partial; + +type TrackInfoOptions = { + priority: number; + maxAge?: Milli; +}; + +const TrackSchema: z.ZodMiniObject<{ + name: z.ZodMiniString; +}, z.core.$strip>; + +type Transport = z.infer; + +const TransportSchema: z.ZodMiniObject<{ + rtt: z.ZodMiniOptional, "u53", "out">>, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, (number & z.$brand<"u53">) | null>>>; + rate: z.ZodMiniOptional, "u53", "out">>, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, (number & z.$brand<"u53">) | null>>>; + lostBytes: z.ZodMiniOptional, "u53", "out">>, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, (number & z.$brand<"u53">) | null>>>; + lostPackets: z.ZodMiniOptional, "u53", "out">>, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, (number & z.$brand<"u53">) | null>>>; + age: z.ZodMiniOptional, "u53", "out">>, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, (number & z.$brand<"u53">) | null>>>; +}, z.core.$strip>; + +type U53 = z.infer; + +function u53(value: number): U53; + +const u53Schema: z.core.$ZodBranded, "u53", "out">; + +type U8 = z.infer; + +function u8(value: number): U8; + +const u8Schema: z.core.$ZodBranded, "u8", "out">; + +const UnknownContainerSchema: z.ZodMiniPipe; +}, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; +}, { + [x: string]: unknown; + kind: string; +}>>; + +class UnsupportedVersion extends Error { + constructor(version: number); + readonly version: number; +} + +type Verdict = "unknown" | "healthy" | "degraded" | "unhealthy"; + +const VERSION = 4; + +const Video: typeof video; + +type Video = video.Video; + +declare namespace video { + export { + ranked_2 as ranked, + ColorSchema, + Color, + ProjectionSchema, + Projection, + VideoConfigSchema, + VideoSchema, + Video_2 as Video, + VideoConfig + } +} + +type Video_2 = z.infer; + +type VideoConfig = z.infer; + +const VideoConfigSchema: z.ZodMiniObject<{ + broadcast: z.ZodMiniOptional>>; + epoch: z.ZodMiniOptional>>; + track: z.ZodMiniOptional>; + label: z.ZodMiniOptional>; + codec: z.ZodMiniString; + container: z.ZodMiniDefault; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"cmaf">; + init: z.ZodMiniBase64; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"loc">; + }, z.core.$strip>], "kind">, z.ZodMiniPipe; + }, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + description: z.ZodMiniOptional>; + codedWidth: z.ZodMiniOptional, "u53", "out">>; + codedHeight: z.ZodMiniOptional, "u53", "out">>; + displayAspectWidth: z.ZodMiniOptional, "u53", "out">>; + displayAspectHeight: z.ZodMiniOptional, "u53", "out">>; + color: z.ZodMiniOptional, "u8", "out">>; + transfer: z.ZodMiniOptional, "u8", "out">>; + matrix: z.ZodMiniOptional, "u8", "out">>; + range: z.ZodMiniOptional>; + mastering: z.ZodMiniOptional; + y: z.ZodMiniNumber; + }, z.core.$strip>; + green: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + blue: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + white: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + maxLuminance: z.ZodMiniNumber; + minLuminance: z.ZodMiniNumber; + }, z.core.$strip>>; + contentLight: z.ZodMiniOptional; + maxFall: z.ZodMiniNumber; + }, z.core.$strip>>; + }, z.core.$strip>>; + projection: z.ZodMiniOptional; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"equirectangular">; + fov: z.ZodMiniOptional>; + }, z.core.$strip>], "kind">, z.ZodMiniPipe; + }, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + stereo: z.ZodMiniOptional>; + interlaced: z.ZodMiniOptional>; + framerate: z.ZodMiniOptional>; + reorder: z.ZodMiniOptional, "u8", "out">>; + bitrate: z.ZodMiniOptional, "u53", "out">>; + enabled: z.ZodMiniOptional>; + preference: z.ZodMiniOptional; + optimizeForLatency: z.ZodMiniOptional>; + jitter: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + warmup: z.ZodMiniOptional, "u53", "out">>; + delay: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; +}, z.core.$strip>; + +const VideoSchema: z.ZodMiniUnion, z.ZodMiniObject<{ + broadcast: z.ZodMiniOptional>>; + epoch: z.ZodMiniOptional>>; + track: z.ZodMiniOptional>; + label: z.ZodMiniOptional>; + codec: z.ZodMiniString; + container: z.ZodMiniDefault; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"cmaf">; + init: z.ZodMiniBase64; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"loc">; + }, z.core.$strip>], "kind">, z.ZodMiniPipe; + }, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + description: z.ZodMiniOptional>; + codedWidth: z.ZodMiniOptional, "u53", "out">>; + codedHeight: z.ZodMiniOptional, "u53", "out">>; + displayAspectWidth: z.ZodMiniOptional, "u53", "out">>; + displayAspectHeight: z.ZodMiniOptional, "u53", "out">>; + color: z.ZodMiniOptional, "u8", "out">>; + transfer: z.ZodMiniOptional, "u8", "out">>; + matrix: z.ZodMiniOptional, "u8", "out">>; + range: z.ZodMiniOptional>; + mastering: z.ZodMiniOptional; + y: z.ZodMiniNumber; + }, z.core.$strip>; + green: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + blue: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + white: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + maxLuminance: z.ZodMiniNumber; + minLuminance: z.ZodMiniNumber; + }, z.core.$strip>>; + contentLight: z.ZodMiniOptional; + maxFall: z.ZodMiniNumber; + }, z.core.$strip>>; + }, z.core.$strip>>; + projection: z.ZodMiniOptional; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"equirectangular">; + fov: z.ZodMiniOptional>; + }, z.core.$strip>], "kind">, z.ZodMiniPipe; + }, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + stereo: z.ZodMiniOptional>; + interlaced: z.ZodMiniOptional>; + framerate: z.ZodMiniOptional>; + reorder: z.ZodMiniOptional, "u8", "out">>; + bitrate: z.ZodMiniOptional, "u53", "out">>; + enabled: z.ZodMiniOptional>; + preference: z.ZodMiniOptional; + optimizeForLatency: z.ZodMiniOptional>; + jitter: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + warmup: z.ZodMiniOptional, "u53", "out">>; + delay: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + }, z.core.$strip>>; + display: z.ZodMiniOptional, "u53", "out">; + height: z.core.$ZodBranded, "u53", "out">; + }, z.core.$strip>>; + rotation: z.ZodMiniOptional>; + flip: z.ZodMiniOptional>; +}, z.core.$strip>, z.ZodMiniPipe; + }, z.core.$strip>; + config: z.ZodMiniObject<{ + broadcast: z.ZodMiniOptional>>; + epoch: z.ZodMiniOptional>>; + track: z.ZodMiniOptional>; + label: z.ZodMiniOptional>; + codec: z.ZodMiniString; + container: z.ZodMiniDefault; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"cmaf">; + init: z.ZodMiniBase64; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"loc">; + }, z.core.$strip>], "kind">, z.ZodMiniPipe; + }, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + description: z.ZodMiniOptional>; + codedWidth: z.ZodMiniOptional, "u53", "out">>; + codedHeight: z.ZodMiniOptional, "u53", "out">>; + displayAspectWidth: z.ZodMiniOptional, "u53", "out">>; + displayAspectHeight: z.ZodMiniOptional, "u53", "out">>; + color: z.ZodMiniOptional, "u8", "out">>; + transfer: z.ZodMiniOptional, "u8", "out">>; + matrix: z.ZodMiniOptional, "u8", "out">>; + range: z.ZodMiniOptional>; + mastering: z.ZodMiniOptional; + y: z.ZodMiniNumber; + }, z.core.$strip>; + green: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + blue: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + white: z.ZodMiniObject<{ + x: z.ZodMiniNumber; + y: z.ZodMiniNumber; + }, z.core.$strip>; + maxLuminance: z.ZodMiniNumber; + minLuminance: z.ZodMiniNumber; + }, z.core.$strip>>; + contentLight: z.ZodMiniOptional; + maxFall: z.ZodMiniNumber; + }, z.core.$strip>>; + }, z.core.$strip>>; + projection: z.ZodMiniOptional; + }, z.core.$strip>, z.ZodMiniObject<{ + kind: z.ZodMiniLiteral<"equirectangular">; + fov: z.ZodMiniOptional>; + }, z.core.$strip>], "kind">, z.ZodMiniPipe; + }, z.core.$loose>, z.ZodMiniTransform<{ + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }, { + [x: string]: unknown; + kind: string; + }>>]>>; + stereo: z.ZodMiniOptional>; + interlaced: z.ZodMiniOptional>; + framerate: z.ZodMiniOptional>; + reorder: z.ZodMiniOptional, "u8", "out">>; + bitrate: z.ZodMiniOptional, "u53", "out">>; + enabled: z.ZodMiniOptional>; + preference: z.ZodMiniOptional; + optimizeForLatency: z.ZodMiniOptional>; + jitter: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + warmup: z.ZodMiniOptional, "u53", "out">>; + delay: z.ZodMiniOptional, "u53", "out">, z.ZodMiniTransform<(number & z.$brand<"u53">) | undefined, number & z.$brand<"u53">>>>; + }, z.core.$strip>; +}, z.core.$strip>>, z.ZodMiniTransform<{ + renditions: { + [k: string]: { + broadcast?: RelativeBroadcast | undefined; + epoch?: ReferenceEpoch | undefined; + track?: string | undefined; + label?: string | undefined; + codec: string; + container: { + kind: "legacy"; + } | { + kind: "cmaf"; + init: string; + } | { + kind: "loc"; + } | { + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }; + description?: string | undefined; + codedWidth?: (number & z.$brand<"u53">) | undefined; + codedHeight?: (number & z.$brand<"u53">) | undefined; + displayAspectWidth?: (number & z.$brand<"u53">) | undefined; + displayAspectHeight?: (number & z.$brand<"u53">) | undefined; + color?: { + primaries?: (number & z.$brand<"u8">) | undefined; + transfer?: (number & z.$brand<"u8">) | undefined; + matrix?: (number & z.$brand<"u8">) | undefined; + range?: "full" | "limited" | undefined; + mastering?: { + red: { + x: number; + y: number; + }; + green: { + x: number; + y: number; + }; + blue: { + x: number; + y: number; + }; + white: { + x: number; + y: number; + }; + maxLuminance: number; + minLuminance: number; + } | undefined; + contentLight?: { + maxCll: number; + maxFall: number; + } | undefined; + } | undefined; + projection?: { + kind: "rectilinear"; + } | { + kind: "equirectangular"; + fov?: number | undefined; + } | { + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + } | undefined; + stereo?: string | undefined; + interlaced?: boolean | undefined; + framerate?: number | undefined; + reorder?: (number & z.$brand<"u8">) | undefined; + bitrate?: (number & z.$brand<"u53">) | undefined; + enabled?: boolean | undefined; + preference?: number | undefined; + optimizeForLatency?: boolean | undefined; + jitter?: (number & z.$brand<"u53">) | undefined; + warmup?: (number & z.$brand<"u53">) | undefined; + delay?: (number & z.$brand<"u53">) | undefined; + }; + }; + display: { + width: number & z.$brand<"u53">; + height: number & z.$brand<"u53">; + } | undefined; + rotation: undefined; + flip: undefined; +}, { + track: { + name: string; + }; + config: { + broadcast?: RelativeBroadcast | undefined; + epoch?: ReferenceEpoch | undefined; + track?: string | undefined; + label?: string | undefined; + codec: string; + container: { + kind: "legacy"; + } | { + kind: "cmaf"; + init: string; + } | { + kind: "loc"; + } | { + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + }; + description?: string | undefined; + codedWidth?: (number & z.$brand<"u53">) | undefined; + codedHeight?: (number & z.$brand<"u53">) | undefined; + displayAspectWidth?: (number & z.$brand<"u53">) | undefined; + displayAspectHeight?: (number & z.$brand<"u53">) | undefined; + color?: { + primaries?: (number & z.$brand<"u8">) | undefined; + transfer?: (number & z.$brand<"u8">) | undefined; + matrix?: (number & z.$brand<"u8">) | undefined; + range?: "full" | "limited" | undefined; + mastering?: { + red: { + x: number; + y: number; + }; + green: { + x: number; + y: number; + }; + blue: { + x: number; + y: number; + }; + white: { + x: number; + y: number; + }; + maxLuminance: number; + minLuminance: number; + } | undefined; + contentLight?: { + maxCll: number; + maxFall: number; + } | undefined; + } | undefined; + projection?: { + kind: "rectilinear"; + } | { + kind: "equirectangular"; + fov?: number | undefined; + } | { + kind: "unknown"; + raw: { + [x: string]: unknown; + kind: string; + }; + } | undefined; + stereo?: string | undefined; + interlaced?: boolean | undefined; + framerate?: number | undefined; + reorder?: (number & z.$brand<"u8">) | undefined; + bitrate?: (number & z.$brand<"u53">) | undefined; + enabled?: boolean | undefined; + preference?: number | undefined; + optimizeForLatency?: boolean | undefined; + jitter?: (number & z.$brand<"u53">) | undefined; + warmup?: (number & z.$brand<"u53">) | undefined; + delay?: (number & z.$brand<"u53">) | undefined; + }; +}[]>>]>; + +function viewer(sample: Sample, thresholds?: Thresholds): Health_2; + +function wallClockTime(clock: Clock, pts: number, ptsTimescale: number): Date; + +function watch(broadcast: Net.Broadcast.Consumer): AsyncIterable; + + +``` diff --git a/js/hang/api/util.api.md b/js/hang/api/util.api.md new file mode 100644 index 00000000000..329df704696 --- /dev/null +++ b/js/hang/api/util.api.md @@ -0,0 +1,101 @@ +## API Report File for "@moq/hang" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { Effect } from '@moq/signals'; +import { Getter } from '@moq/signals'; + +declare namespace Aac { + export { + supportsRate, + pickRate, + objectType, + audioSpecificConfig, + SAMPLE_RATES + } +} + +function audioSpecificConfig(sampleRate: number, channelCount: number): Uint8Array; + +const DEFAULT_SAMPLE_RATE = 48000; + +function fromBytes(bytes: Uint8Array): string; + +declare namespace Gesture { + export { + unlock + } +} + +declare namespace Hacks { + export { + isChrome, + isFirefox, + isSafari + } +} + +declare namespace Hex { + export { + toBytes, + fromBytes + } +} + +const isChrome: boolean; + +const isFirefox: boolean; + +const isSafari: boolean; + +declare namespace Libav { + export { + polyfill + } +} + +function objectType(codec: string): 2 | 5 | 29 | undefined; + +declare namespace Opus { + export { + supportsRate_2 as supportsRate, + pickRate_2 as pickRate, + preSkip, + toDOps, + packetSamples, + WARMUP, + DEFAULT_SAMPLE_RATE, + SAMPLE_RATES_2 as SAMPLE_RATES + } +} + +function packetSamples(packet: Uint8Array): number | undefined; + +function pickRate(rate: number): number; + +function pickRate_2(rate: number): number; + +function polyfill(): Promise; + +function preSkip(description: Uint8Array): number; + +const SAMPLE_RATES: readonly number[]; + +const SAMPLE_RATES_2: readonly number[]; + +function supportsRate(rate: number): boolean; + +function supportsRate_2(rate: number): boolean; + +function toBytes(hex: string): Uint8Array; + +function toDOps(description: Uint8Array): Uint8Array; + +function unlock(effect: Effect, context: AudioContext): Getter; + +const WARMUP = 80; + + +``` diff --git a/js/json/api/index.api.md b/js/json/api/index.api.md new file mode 100644 index 00000000000..d1ec1d315e6 --- /dev/null +++ b/js/json/api/index.api.md @@ -0,0 +1,272 @@ +## API Report File for "@moq/json" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import * as Moq from '@moq/net'; +import type { Time } from '@moq/net'; +import { Timed } from '@moq/net'; +import type * as z from '@zod/mini'; + +export type Compression = "none" | "deflate"; + +interface Config { + compression?: Compression; + deltas?: boolean; + initial?: T; + schema?: z.ZodMiniType; +} + +interface Config_2 { + compression?: Compression; + schema?: z.ZodMiniType; +} + +interface Config_3 { + checkpointRecords?: number; + compression?: boolean; + ops?: boolean; +} + +class Consumer { + [Symbol.asyncIterator](): AsyncIterator>; + constructor(config: Consumer.Config); + latest(): Promise | undefined>; + next(): Promise | undefined>; +} + +namespace Consumer { + type Config = Pick, "schema" | "compression"> & { + track: Moq.Track.Subscriber; + }; +} + +class Consumer_2 { + [Symbol.asyncIterator](): AsyncIterator>; + constructor(config: Consumer_2.Config); + next(): Promise | undefined>; +} + +namespace Consumer_2 { + type Config = Config_2 & { + track: Moq.Track.Subscriber; + }; +} + +class Consumer_3 { + [Symbol.asyncIterator](): AsyncIterator>>; + constructor(config: ConsumerConfig); + next(): Promise> | undefined>; + get offset(): number; +} + +type ConsumerConfig = ConsumerConfig_2 & { + track: Moq.Track.Subscriber; +}; + +interface ConsumerConfig_2 { + compression?: boolean; +} + +class Decoder { + constructor(config?: Pick, "schema" | "compression">); + decode(): T | undefined; + delta(payload: Uint8Array): void; + snapshot(payload: Uint8Array): void; + get value(): unknown; +} + +class Decoder_2 { + constructor(config?: Config_2); + decode(payload: Uint8Array): T; + reset(): void; +} + +class Decoder_3 { + constructor(config?: ConsumerConfig_2); + group(): Group; + next(): Event_2 | undefined; + get offset(): number; +} + +export function deepEqual(a: unknown, b: unknown): boolean; + +export class Desync extends Error { + constructor(); +} + +export interface Diff { + forcedSnapshot: boolean; + patch: unknown; +} + +export function diff(oldVal: unknown, newVal: unknown): Diff; + +export class DuplicateKey extends Error { + constructor(); +} + +interface Encoded { + keyframe: boolean; + payload: Uint8Array; +} + +interface Encoded_2 { + keyframe: boolean; + payload: Uint8Array; +} + +class Encoder { + constructor(config?: Config); + reset(): void; + snapshot(): Pending | undefined; + update(value: T): Pending | undefined; + get value(): T | undefined; +} + +class Encoder_2 { + constructor(config?: Config_2); + encode(value: T): Pending_2; + reset(): void; +} + +class Encoder_3 { + constructor(config?: Config_3); + get end(): number; + get offset(): number; + pop(count: number): Pending_3 | undefined; + push(value: T): Pending_3; + reset(): void; + snapshot(): Pending_3; + get window(): T[]; +} + +type Event_2 = { + push: { + index: number; + value: T; + }; +} | { + pop: Span; +} | { + skip: Span; +}; + +interface Group { + decode(payload: Uint8Array): void; +} + +export function merge(target: unknown, patch: unknown): unknown; + +export class MissingSnapshot extends Error { + constructor(); +} + +interface Pending extends Encoded { + commit(): void; +} + +interface Pending_2 { + commit(): void; + payload: Uint8Array; +} + +interface Pending_3 extends Encoded_2 { + commit(): void; +} + +class Producer { + constructor(config: Producer.Config); + cut(): void; + finish(): void; + mutate(fn: (value: T) => void, at?: Time.Timestamp): void; + update(input: Timed): void; +} + +namespace Producer { + type Config = Config & { + track: Moq.Track.Producer; + }; +} + +class Producer_2 { + constructor(config: Producer_2.Config); + append(input: Timed): void; + finish(): void; +} + +namespace Producer_2 { + type Config = Config_2 & { + track: Moq.Track.Producer; + }; +} + +class Producer_3 { + constructor(config: ProducerConfig); + cut(): void; + finish(): void; + get offset(): number; + pop(count: number, at?: Time.Timestamp): void; + push(input: Timed): void; + get window(): T[]; +} + +type ProducerConfig = Config_3 & { + track: Moq.Track.Producer; +}; + +class Rolled extends Error { + constructor(); +} + +declare namespace Snapshot { + export { + MissingSnapshot, + Consumer, + Decoder, + Config, + Encoded, + Encoder, + Pending, + Producer + } +} + +interface Span { + end: number; + start: number; +} + +declare namespace Stream { + export { + Desync, + Consumer_2 as Consumer, + Rolled, + Decoder_2 as Decoder, + Config_2 as Config, + Encoder_2 as Encoder, + Pending_2 as Pending, + Producer_2 as Producer + } +} + +declare namespace Window_2 { + export { + Consumer_3 as Consumer, + ConsumerConfig, + Decoder_3 as Decoder, + Event_2 as Event, + Group, + Span, + Config_3 as Config, + Encoded_2 as Encoded, + Encoder_3 as Encoder, + Pending_3 as Pending, + Producer_3 as Producer, + ProducerConfig + } +} + + +``` diff --git a/js/justfile b/js/justfile index fa79629f667..50c527b12b3 100644 --- a/js/justfile +++ b/js/justfile @@ -38,10 +38,12 @@ workers: audit: bash ../sh/js/audit.sh -# Auto-fix lint and formatting issues in workspaces, harnesses, docs and demos. -fix: +# Auto-fix lint and formatting issues in workspaces, harnesses, docs and demos, then rebuild +# the changed packages (or `--all`) to regenerate their committed API reports. +fix list="--all": bun install bun biome check --write . ../bench/browser ../test ../doc ../demo + MOQ_API_REPORT=update python3 ../sh/js/workspace.py build '{{ list }}' # Run all unit tests. test: diff --git a/js/libav/api/index.api.md b/js/libav/api/index.api.md new file mode 100644 index 00000000000..6ccbb25d355 --- /dev/null +++ b/js/libav/api/index.api.md @@ -0,0 +1,13 @@ +## API Report File for "@moq/libav" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import type { LibAVWrapper } from '@libav.js/types'; + +const LibAV: LibAVWrapper; +export default LibAV; + + +``` diff --git a/js/libav/build.ts b/js/libav/build.ts index 5671040b2d5..66d457766e6 100644 --- a/js/libav/build.ts +++ b/js/libav/build.ts @@ -6,6 +6,7 @@ // which lags package.nix until the next release. import { chmodSync, cpSync, readdirSync, rmSync } from "node:fs"; import { join, resolve, sep } from "node:path"; +import { checkReports } from "../common/api.ts"; const dir = import.meta.dir; const dist = join(dir, "dist"); @@ -57,3 +58,6 @@ if (Bun.which("nix")) { } console.log(`unpacked ${name}@${version} from npm into dist/; Nix is not on PATH`); } + +// Its API is the hand-written index.d.ts, reported like every other package's. +checkReports(dir); diff --git a/js/loc/api/index.api.md b/js/loc/api/index.api.md new file mode 100644 index 00000000000..df59fa2c3f3 --- /dev/null +++ b/js/loc/api/index.api.md @@ -0,0 +1,23 @@ +## API Report File for "@moq/loc" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import type { Micro } from '@moq/clock'; + +export class Format { + constructor(kind?: "audio" | "video" | "data"); + decode(frame: Uint8Array): Frame[]; + end(frame: Frame): Micro | undefined; + readonly kind: "audio" | "video" | "data"; +} + +export interface Frame { + keyframe: boolean; + payload: Uint8Array; + timestamp: Micro; +} + + +``` diff --git a/js/moq-boy/api/element.api.md b/js/moq-boy/api/element.api.md new file mode 100644 index 00000000000..bba24fd091e --- /dev/null +++ b/js/moq-boy/api/element.api.md @@ -0,0 +1,84 @@ +## API Report File for "@moq/boy" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import * as Moq from '@moq/net'; +import * as Watch from '@moq/watch'; + +class Game { + constructor(config: GameConfig); + readonly active: Moq.Signals.Signal; + readonly audioDecoder: Watch.Audio.Decoder; + readonly audioEmitter: Watch.Audio.Emitter; + readonly audioSource: Watch.Audio.Source; + readonly broadcast: Watch.Broadcast; + readonly canvas: Moq.Signals.Signal; + close(): void; + readonly delay: Moq.Signals.Signal; + readonly expanded: Moq.Signals.Signal; + readonly heldButtons: Set; + readonly hovered: Moq.Signals.Signal; + sendButtons(): void; + sendCommand(cmd: Record): void; + readonly sessionId: string; + readonly status: Moq.Signals.Signal<{ + buttons: string[]; + latency: Record; + location?: string | undefined; + stats?: { + video_secs: number; + audio_secs: number; + emulation_secs: number; + wall_secs: number; + } | undefined; + } | undefined>; + readonly sync: Watch.Sync; + readonly userMuted: Moq.Signals.Signal; + readonly videoDecoder: Watch.Video.Decoder; + readonly videoRenderer: Watch.Video.Renderer; + readonly videoSource: Watch.Video.Source; + readonly viewerId: Moq.Signals.Signal; + readonly volume: Moq.Signals.Signal; +} + +interface GameConfig { + connection: Moq.Connection; + expanded: Moq.Signals.Signal; + gamePrefix: string; + origin: Moq.Origin.Producer; + sessionId: string; + viewerPrefix: string; +} + +class MoqBoy extends HTMLElement { + constructor(); + attributeChangedCallback(name: Observed, _oldValue: string | null, newValue: string | null): void; + connectedCallback(): void; + readonly connection: Moq.Connection; + disconnectedCallback(): void; + readonly expanded: Moq.Signals.Signal; + readonly games: Moq.Signals.Signal>; + static observedAttributes: readonly ["url", "prefix", "prefix-game", "prefix-viewer"]; + readonly origin: Moq.Origin.Producer; + get prefixGame(): string; + set prefixGame(value: string); + get prefixPath(): string; + set prefixPath(value: string); + get prefixViewer(): string; + set prefixViewer(value: string); + get url(): URL | undefined; + set url(value: string | URL | undefined); +} +export default MoqBoy; + +const OBSERVED: readonly ["url", "prefix", "prefix-game", "prefix-viewer"]; + +type Observed = (typeof OBSERVED)[number]; + + +``` diff --git a/js/moq-boy/api/index.api.md b/js/moq-boy/api/index.api.md new file mode 100644 index 00000000000..9df06dc8115 --- /dev/null +++ b/js/moq-boy/api/index.api.md @@ -0,0 +1,116 @@ +## API Report File for "@moq/boy" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import * as Moq from '@moq/net'; +import * as Watch from '@moq/watch'; +import { z } from '@zod/mini'; + +export class Game { + constructor(config: GameConfig); + readonly active: Moq.Signals.Signal; + readonly audioDecoder: Watch.Audio.Decoder; + readonly audioEmitter: Watch.Audio.Emitter; + readonly audioSource: Watch.Audio.Source; + readonly broadcast: Watch.Broadcast; + readonly canvas: Moq.Signals.Signal; + close(): void; + readonly delay: Moq.Signals.Signal; + readonly expanded: Moq.Signals.Signal; + readonly heldButtons: Set; + readonly hovered: Moq.Signals.Signal; + sendButtons(): void; + sendCommand(cmd: Record): void; + readonly sessionId: string; + readonly status: Moq.Signals.Signal<{ + buttons: string[]; + latency: Record; + location?: string | undefined; + stats?: { + video_secs: number; + audio_secs: number; + emulation_secs: number; + wall_secs: number; + } | undefined; + } | undefined>; + readonly sync: Watch.Sync; + readonly userMuted: Moq.Signals.Signal; + readonly videoDecoder: Watch.Video.Decoder; + readonly videoRenderer: Watch.Video.Renderer; + readonly videoSource: Watch.Video.Source; + readonly viewerId: Moq.Signals.Signal; + readonly volume: Moq.Signals.Signal; +} + +export interface GameConfig { + connection: Moq.Connection; + expanded: Moq.Signals.Signal; + gamePrefix: string; + origin: Moq.Origin.Producer; + sessionId: string; + viewerPrefix: string; +} + +export type GameStats = z.infer; + +export const GameStatsSchema: z.ZodMiniObject<{ + video_secs: z.ZodMiniNumber; + audio_secs: z.ZodMiniNumber; + emulation_secs: z.ZodMiniNumber; + wall_secs: z.ZodMiniNumber; +}, z.core.$strip>; + +export type GameStatus = z.infer; + +export const GameStatusSchema: z.ZodMiniObject<{ + buttons: z.ZodMiniArray>; + latency: z.ZodMiniRecord, z.ZodMiniArray; + ms: z.ZodMiniNumber; + }, z.core.$strip>>>; + location: z.ZodMiniOptional>; + stats: z.ZodMiniOptional; + audio_secs: z.ZodMiniNumber; + emulation_secs: z.ZodMiniNumber; + wall_secs: z.ZodMiniNumber; + }, z.core.$strip>>; +}, z.core.$strip>; + +export const KEY_MAP: Record; + +export { Moq } + +export class MoqBoy extends HTMLElement { + constructor(); + attributeChangedCallback(name: Observed, _oldValue: string | null, newValue: string | null): void; + connectedCallback(): void; + readonly connection: Moq.Connection; + disconnectedCallback(): void; + readonly expanded: Moq.Signals.Signal; + readonly games: Moq.Signals.Signal>; + static observedAttributes: readonly ["url", "prefix", "prefix-game", "prefix-viewer"]; + readonly origin: Moq.Origin.Producer; + get prefixGame(): string; + set prefixGame(value: string); + get prefixPath(): string; + set prefixPath(value: string); + get prefixViewer(): string; + set prefixViewer(value: string); + get url(): URL | undefined; + set url(value: string | URL | undefined); +} + +const OBSERVED: readonly ["url", "prefix", "prefix-game", "prefix-viewer"]; + +type Observed = (typeof OBSERVED)[number]; + +export { Watch } + + +``` diff --git a/js/msf/api/index.api.md b/js/msf/api/index.api.md new file mode 100644 index 00000000000..3c7e93f22ac --- /dev/null +++ b/js/msf/api/index.api.md @@ -0,0 +1,122 @@ +## API Report File for "@moq/msf" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import type * as Moq from '@moq/net'; +import * as z from '@zod/mini'; + +export type Catalog = z.infer; + +export const CatalogSchema: z.ZodMiniObject<{ + tracks: z.ZodMiniArray; + namespace: z.ZodMiniOptional>; + packaging: z.ZodMiniUnion, z.ZodMiniString]>; + isLive: z.ZodMiniOptional>; + role: z.ZodMiniOptional, z.ZodMiniString]>>; + label: z.ZodMiniOptional>; + lang: z.ZodMiniOptional>; + codec: z.ZodMiniOptional>; + width: z.ZodMiniOptional>; + height: z.ZodMiniOptional>; + framerate: z.ZodMiniOptional>; + samplerate: z.ZodMiniOptional>; + channelConfig: z.ZodMiniOptional>; + bitrate: z.ZodMiniOptional>; + initData: z.ZodMiniOptional>; + renderGroup: z.ZodMiniOptional>; + altGroup: z.ZodMiniOptional>; + maxGrpSapStartingType: z.ZodMiniOptional>; + maxObjSapStartingType: z.ZodMiniOptional>; + jitter: z.ZodMiniOptional>; + delay: z.ZodMiniOptional>; + }, z.core.$strip>>; + ext: z.ZodMiniOptional, z.ZodMiniUnknown>>; +}, z.core.$strip>; + +export function decode(raw: Uint8Array): Catalog; + +export function encode(catalog: Catalog): Uint8Array; + +function fetch_2(track: Moq.Track.Ordered): Promise; +export { fetch_2 as fetch } + +export type Packaging = z.infer; + +export const PackagingSchema: z.ZodMiniUnion, z.ZodMiniString]>; + +export type Role = z.infer; + +export const RoleSchema: z.ZodMiniUnion, z.ZodMiniString]>; + +export type Track = z.infer; + +export const TrackSchema: z.ZodMiniObject<{ + name: z.ZodMiniString; + namespace: z.ZodMiniOptional>; + packaging: z.ZodMiniUnion, z.ZodMiniString]>; + isLive: z.ZodMiniOptional>; + role: z.ZodMiniOptional, z.ZodMiniString]>>; + label: z.ZodMiniOptional>; + lang: z.ZodMiniOptional>; + codec: z.ZodMiniOptional>; + width: z.ZodMiniOptional>; + height: z.ZodMiniOptional>; + framerate: z.ZodMiniOptional>; + samplerate: z.ZodMiniOptional>; + channelConfig: z.ZodMiniOptional>; + bitrate: z.ZodMiniOptional>; + initData: z.ZodMiniOptional>; + renderGroup: z.ZodMiniOptional>; + altGroup: z.ZodMiniOptional>; + maxGrpSapStartingType: z.ZodMiniOptional>; + maxObjSapStartingType: z.ZodMiniOptional>; + jitter: z.ZodMiniOptional>; + delay: z.ZodMiniOptional>; +}, z.core.$strip>; + +export const VERSION = "draft-01"; + + +``` diff --git a/js/net/api/index.api.md b/js/net/api/index.api.md new file mode 100644 index 00000000000..dcb352605a4 --- /dev/null +++ b/js/net/api/index.api.md @@ -0,0 +1,1335 @@ +## API Report File for "@moq/net" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { compareSpecificity } from '@moq/pattern'; +import { GetPromise } from '@moq/signals'; +import { Getter } from '@moq/signals'; +import { InvalidPattern } from '@moq/pattern'; +import { Milli } from '@moq/clock'; +import { Pattern } from '@moq/pattern'; +import { Patterns } from '@moq/pattern'; +import { Segment } from '@moq/pattern'; +import { Signal } from '@moq/signals'; +import * as Signals from '@moq/signals'; +import { Specificity } from '@moq/pattern'; +import * as z from 'zod/mini'; + +function accept(input: AcceptProps): Promise; + +interface AcceptProps { + consume?: Producer_5; + extensions?: Extensions.Extensions; + implementation?: string; + publish?: Consumer_5; + transport: WebTransport; + url: URL; + version?: number; +} + +class Allocator implements Handle_2 { + constructor(estimate?: Getter); + close(): void; + reserve(track: Demand, max: number): Reservation; + static unlimited(): Allocator; +} + +const ALPN: { + readonly DRAFT_14: "moq-00"; + readonly DRAFT_15: "moqt-15"; + readonly DRAFT_16: "moqt-16"; + readonly DRAFT_17: "moqt-17"; + readonly DRAFT_18: "moqt-18"; + readonly DRAFT_19: "moqt-19"; + readonly DRAFT_20: "moqt-20"; + readonly DRAFT_21: "moqt-21"; + readonly DRAFT_22: "moqt-22"; +}; + +declare namespace Announce { + export { + Announce_2 as Announce, + Consumer, + Event_2 as Event + } +} + +interface Announce_2 { + captures: Path_2.Pattern[] | undefined; + prefix: Path_2.Valid; + route: Route; +} + +declare namespace Announce_3 { + export { + Announce_2 as Announce, + Event_2 as Event, + Options, + Producer_4 as Producer, + Consumer + } +} + +declare namespace Auth { + export { + Duplicate, + Handle, + Unsupported, + Grant, + Auth_2 as Auth + } +} + +interface Auth_2 { + close(): void; + readonly closed: PromiseLike; + readonly grant: Getter; +} + +declare namespace Auth_3 { + export { + + } +} + +declare namespace Auth_4 { + export { + Duplicate, + Handle, + Unsupported, + Grant, + Auth_2 as Auth + } +} + +declare namespace Bandwidth { + export { + Allocator, + Handle_2 as Handle, + Reservation + } +} + +type Bound = { + included: number; + excluded?: never; +} | { + excluded: number; + included?: never; +}; + +declare namespace Broadcast { + export { + Tracks, + TracksEvent, + Producer_3 as Producer, + Consumer_4 as Consumer + } +} + +declare namespace Broadcast_2 { + export { + Tracks, + TracksEvent, + Producer_3 as Producer, + Consumer_4 as Consumer + } +} + +interface CertificateHash { + algorithm?: "sha-256"; + value: BufferSource | string; +} + +function certificateHash(cert: string | BufferSource): Promise>; + +class ClientSetup { + constructor(input: { + versions: number[]; + parameters?: SetupOptions; + }); + static decode(r: Reader, version: IetfVersion): Promise; + encode(w: Writer, version: IetfVersion): Promise; + static id: number; + parameters: SetupOptions; + versions: number[]; +} + +declare namespace Cluster { + export { + + } +} + +function connect(input: ConnectProps): Promise; + +export class Connection { + constructor(props?: ConnectionProps); + static readonly accept: typeof accept; + announced(scope?: Path_2.Pattern, options?: Announce_3.Options): Announce_3.Consumer; + readonly auth: Getter; + readonly bandwidth: Getter; + static readonly certificateHash: typeof certificateHash; + close(abort?: Error): void; + get closed(): GetPromise; + static readonly connect: typeof connect; + enabled: Signal; + readonly error: Getter; + static readonly isWebTransportSupported: typeof isWebTransportSupported; + readonly origin: Getter; + readonly probe: Getter; + stats(): Promise; + readonly status: Getter; + readonly transport: Getter; + url: Signal; + versions: Signal; +} + +export namespace Connection { + export type AcceptProps = AcceptProps; + export type Backoff = ReloadDelay; + export type CertificateHash = CertificateHash; + export type ConnectProps = ConnectProps; + export type Established = Established; + export type Extensions = Extensions_2; + export type Goaway = GoawayProps; + export type Probe = Probe; + export type Props = ConnectionProps; + export type Redirect = Redirect; + export type Stats = Stats; + export type Status = ReloadStatus; + export type Transport = Transport; + export type WebSocketProps = WebSocketProps; + export type WebTransportProps = WebTransportProps; +} + +interface ConnectionProps { + consume?: Origin_3.Producer; + delay?: ReloadDelay; + enabled?: boolean | Signal; + goaway?: GoawayProps; + publish?: Origin_3.Consumer; + share?: boolean; + signal?: never; + timeout?: Milli; + transport?: never; + url?: URL | Signal; + versions?: readonly string[] | Signal; + websocket?: WebSocketProps; + webtransport?: WebTransportProps; +} + +interface ConnectProps { + auth?: Auth_4.Handle; + consume?: Producer_5; + extensions?: Extensions.Extensions; + implementation?: string; + publish?: Consumer_5; + signal?: AbortSignal; + timeout?: Milli; + transport?: WebTransport; + url: URL; + versions?: readonly string[]; + websocket?: WebSocketProps; + webtransport?: WebTransportProps; +} + +class ConnectTimeout extends Error { + constructor(timeout: Milli); + readonly timeout: Milli; +} + +class Consumer { + [Symbol.asyncIterator](): AsyncGenerator; + close(abort?: Error): void; + get closed(): GetPromise; + next(): Promise; + get synced(): Getter; +} + +class Consumer_2 { + close(abort?: Error): void; + get closed(): GetPromise; + get done(): boolean; + get frameCount(): number; + get isClosed(): boolean; + readable(): Promise; + readBool(): Promise; + readFrame(): Promise; + readFrameSequence(options?: ReadOptions): Promise<({ + sequence: number; + } & Frame) | undefined>; + readJson(): Promise; + readString(): Promise; + readonly sequence: number; + tryReadFrame(): Frame | undefined; + tryReadFrameSequence(): ({ + sequence: number; + } & Frame) | undefined; +} + +class Consumer_3 { + fetchGroup(sequence: number, options?: FetchGroupOptions): Promise; + info(): Promise; + readonly name: string; + subscribe(options?: Subscription): Subscriber; +} + +class Consumer_4 { + protected constructor(shared?: never); + clone(): Consumer_4; + close(): void; + get closed(): GetPromise; + get epoch(): Epoch_2.Valid | undefined; + get path(): Path_2.Valid; + protected shareState(): never; + track(name: string): track.Consumer; + tracks(): Tracks; +} + +class Consumer_5 { + announced(scope?: Path_2.Pattern, options?: Announce_3.Options): Announce_3.Consumer; + get closed(): GetPromise; + get discovery(): Getter; + request(path: Path_2.Valid, options?: RequestOptions): Requesting; +} + +type Cost = bigint; + +const Cost: { + zero: bigint; +}; + +class Cursor { + constructor(buffer: Uint8Array, version: StreamVersion); + bool(): boolean; + exact(size: number, decode: (c: Cursor) => T): T; + get offset(): number; + read(size: number): Uint8Array; + get remaining(): number; + string(): string; + u16(): number; + u53(): number; + u62(): bigint; + u8(): number; + varint(): U64; + readonly version: StreamVersion; +} + +interface Datagram { + payload: Uint8Array; + sequence: number; + timestamp?: Timestamp; +} + +function decode(raw: string): Valid; + +function decode_2(buf: Uint8Array): [number, Uint8Array]; + +function decodeBigInt(buf: Uint8Array): [bigint, Uint8Array]; + +function decodeLeadingOnes(buf: Uint8Array): [bigint, Uint8Array]; + +class Demand { + get closed(): GetPromise; + readonly name: string; + get wanted(): Getter; +} + +class Demand_2 { + get closed(): GetPromise; + readonly sequence: number; + unused(): Promise; + get used(): Getter; +} + +class Duplicate extends Error { + constructor(message?: string); +} + +class Dynamic { + close(): void; + readonly prefix: Path_2.Valid; + requested(): AsyncIterableIterator; + get route(): Route; +} + +function empty(): Valid; + +function encode(path: Valid): Valid; + +function encode_2(v: number | bigint): Uint8Array; + +function encodeLeadingOnes(v: number | bigint): Uint8Array; + +function encodeLeadingOnesTo(dst: ArrayBuffer, v: number | bigint): Uint8Array; + +function encodeTo(dst: ArrayBuffer, v: number | bigint): Uint8Array; + +declare namespace Epoch { + export { + parse, + mint, + time, + Valid_2 as Valid + } +} + +declare namespace Epoch_2 { + export { + parse, + mint, + time, + Valid_2 as Valid + } +} + +declare namespace Epoch_3 { + export { + + } +} + +declare namespace Error_2 { + export { + ConnectTimeout, + FrameTooLarge, + GroupTooLarge, + NoStreamCredit, + NotFound, + ProtocolViolation, + RefusedRedirect, + Session, + Stream, + StreamOptions, + TimestampMismatch, + TooFarBehind + } +} + +interface Established { + abort(): void; + announced(scope?: Path_2.Pattern, options?: Announce_3.Options): Announce_3.Consumer; + readonly auth: Auth_4.Handle; + close(): Promise; + closed: Promise; + readonly peerImplementation: Promise; + readonly probe: Getter; + stats(): Promise; + readonly transport: Transport; + readonly url: URL; + readonly version: string; +} + +type Event_2 = { + kind: "start" | "update" | "restart" | "end"; +} & Announce_2; + +declare namespace Extensions { + export { + offered, + intoSetup, + Extensions_2 as Extensions, + Offered + } +} + +interface Extensions_2 { + auth?: boolean; + epoch?: boolean; + solicit?: boolean; +} + +interface FetchGroupOptions { + maxDelay?: Milli; + priority?: number; + signal?: AbortSignal; +} + +interface Frame { + payload: Uint8Array; + timestamp?: Timestamp; +} + +class FrameTooLarge extends Stream { + constructor(options?: { + cause?: unknown; + }); +} + +function from(...paths: string[]): Valid; + +interface GoawayProps { + handover?: Milli; + redirect?: Redirect; +} + +interface Grant { + expires?: number; + publish: Path_2.Patterns; + subscribe: Path_2.Patterns; +} + +declare namespace Group { + export { + MAX_GROUP_CACHE_BYTES, + MAX_GROUP_FRAMES, + Frame, + ReadOptions, + Info_2 as Info, + Demand_2 as Demand, + Producer_2 as Producer, + Consumer_2 as Consumer + } +} + +interface Groups { + end?: Bound; + start?: Bound; +} + +class GroupTooLarge extends Stream { + constructor(options?: { + cause?: unknown; + }); +} + +class Handle { + constructor(); + abort(err?: Error): void; + add(token: string | Uint8Array): Promise; + get grant(): Getter; +} + +interface Handle_2 { + reserve(track: Demand, max: number): Reservation; +} + +function hasPrefix(prefix: Valid, path: Valid): boolean; + +type Hop = z.infer; + +const HopSchema: z.core.$ZodBranded, "Hop", "out">; + +declare namespace Ietf { + export { + Auth_3 as Auth, + Cluster, + Epoch_3 as Epoch, + Setup, + ClientSetup, + ServerSetup, + initialMaxRequestId, + SetupOption, + REQUEST_WINDOW, + SetupOptions, + versionName, + Version, + ALPN, + IetfVersion + } +} + +type IetfVersion = typeof Version.DRAFT_14 | typeof Version.DRAFT_15 | typeof Version.DRAFT_16 | typeof Version.DRAFT_17 | typeof Version.DRAFT_18 | typeof Version.DRAFT_19 | typeof Version.DRAFT_20 | typeof Version.DRAFT_21 | typeof Version.DRAFT_22; + +export const IMPLEMENTATION: string; + +interface Info { + compress?: boolean; + maxAge?: Milli; + priority: number; + refresh?: number; + timescale?: Timescale | null; +} + +interface Info_2 { + sequence: number; +} + +function infoDefaults(info?: Partial): Info; + +function initialMaxRequestId(peerClient: boolean, window?: bigint): bigint; + +function intoSetup(params: Ietf.SetupOptions, extensions: Offered, version: Ietf.IetfVersion): void; + +function isAnonymous(route: Route): boolean; + +function isWebTransportSupported(): boolean; + +function join(path: Valid, other: Valid): Valid; + +const MAX_GROUP_CACHE_BYTES: number; + +const MAX_GROUP_FRAMES = 8192; + +const MAX_PARTS = 32; + +const MAX_U14: number; + +const MAX_U30: number; + +const MAX_U53: number; + +const MAX_U6: number; + +function mint(): Valid_2; + +function normalizeRelative(rel: string): Relative; + +class NoStreamCredit extends Error { + constructor(options?: ErrorOptions); +} + +class NotFound extends Stream { + constructor(what: string, options?: { + cause?: unknown; + }); +} + +type Offered = Required; + +function offered(extensions?: Extensions_2): Offered; + +interface OpenOptions { + sendOrder?: number; + timeout?: number | null; + version: StreamVersion; + waitUntilAvailable?: boolean; +} + +interface Options { + hidden?: boolean; +} + +type Order = "ascending" | "descending"; + +class Ordered { + close(abort?: Error): void; + get closed(): GetPromise; + end(): Position_2 | undefined; + finished(): Promise; + info(): Promise; + largest(): Promise; + readonly name: string; + nextGroup(): Promise; + readBool(): Promise; + readFrame(): Promise<({ + group: number; + frame: number; + } & Frame) | undefined>; + readJson(): Promise; + readString(): Promise; + recvDatagram(): Promise; + get subscription(): Getter; + tryNextGroup(): Consumer_2 | undefined; + update(options: Subscription): void; + withRange(groups: Groups): this; +} + +declare namespace Origin_2 { + export { + Cost, + Hop, + Route, + isAnonymous, + Table, + RequestOptions, + Producer_5 as Producer, + Requesting, + Consumer_5 as Consumer, + Dynamic, + Request_3 as Request, + Prepared + } +} + +declare namespace Origin_3 { + export { + Cost, + Hop, + Route, + isAnonymous, + Table, + RequestOptions, + Producer_5 as Producer, + Requesting, + Consumer_5 as Consumer, + Dynamic, + Request_3 as Request, + Prepared + } +} + +function parse(text: string): Valid_2; + +function parts(path: Valid): string[]; + +declare namespace Path { + export { + from, + parts, + decode, + encode, + hasPrefix, + stripPrefix, + join, + empty, + normalizeRelative, + resolve, + tryResolve, + relative, + Valid, + Relative, + MAX_PARTS, + compareSpecificity, + InvalidPattern, + Pattern, + Patterns, + Segment, + Specificity + } +} + +declare namespace Path_2 { + export { + from, + parts, + decode, + encode, + hasPrefix, + stripPrefix, + join, + empty, + normalizeRelative, + resolve, + tryResolve, + relative, + Valid, + Relative, + MAX_PARTS, + compareSpecificity, + InvalidPattern, + Pattern, + Patterns, + Segment, + Specificity + } +} + +interface Position_2 { + frame: number; + group: number; +} + +class Prepared { + [Symbol.dispose](): void; + readonly broadcast: Broadcast_2.Producer; + close(): void; + publish(): Broadcast_2.Producer; +} + +interface Probe { + estimatedRecvRate?: number; + rtt?: Milli; +} + +class Producer { + constructor(name: string); + accept(info?: Partial): this; + appendDatagram(timestamp: Timestamp | undefined, payload: Uint8Array): number; + appendGroup(): Producer_2; + close(abort?: Error): void; + get closed(): GetPromise; + demand(): Demand; + dropGroups(start: number, end: number, error: Error): void; + finishAt(end: Position_2): void; + info(): Promise; + insertDatagram(sequence: number, timestamp: Timestamp | undefined, payload: Uint8Array): void; + largest(): Position_2 | undefined; + readonly name: string; + get priority(): number; + subscribe(options?: Subscription): Subscriber; + get subscription(): Getter; + writeFrame(frame: Frame): void; + writeGroup(group: Producer_2): void; +} + +class Producer_2 { + constructor(sequence: number); + close(abort?: Error): void; + get closed(): GetPromise; + consume(): Consumer_2; + demand(): Demand_2; + get isClosed(): boolean; + readonly sequence: number; + writeFrame(frame: Frame): void; +} + +class Producer_3 { + constructor(); + announce(route?: Route | { + epoch?: Route["epoch"]; + hops?: Route["hops"]; + cost?: Route["cost"]; + auth?: Route["auth"]; + }): void; + close(): void; + get closed(): GetPromise; + consume(): Consumer_4; + createTrack(name: string, info?: Partial): track.Producer; + removeTrack(name: string): void; + get route(): Route | undefined; + track(name: string): track.Consumer; + unannounce(): void; +} + +class Producer_4 { + append(event: Event_2): void; + close(abort?: Error): void; + get closed(): GetPromise; + consume(): Consumer; +} + +class Producer_5 implements Table { + constructor(); + announced(scope?: Path_2.Pattern, options?: Announce_3.Options): Announce_3.Consumer; + close(abort?: Error): void; + get closed(): GetPromise; + consume(): Consumer_5; + createBroadcast(path: Path_2.Valid): Broadcast_2.Producer; + get discovery(): Getter; + dynamic(prefix: Path_2.Valid): Dynamic; + request(path: Path_2.Valid, options?: RequestOptions): Requesting; + scope(root: Path_2.Valid, patterns: Path_2.Patterns): Producer_5; +} + +class ProtocolViolation extends Error { + constructor(message: string, options?: { + cause?: unknown; + code?: SessionCode; + }); + readonly code: SessionCode; +} + +class Reader { + constructor(stream: ReadableStream, buffer: Uint8Array | undefined, version: StreamVersion); + constructor(stream: undefined, buffer: Uint8Array, version: StreamVersion); + bool(): Promise; + get closed(): Promise; + decode(decode: (c: Cursor) => T): Promise; + decodeMaybe(decode: (c: Cursor) => T): Promise; + discard(): Promise; + done(): Promise; + peekU62(): Promise; + read(size: number): Promise; + readAll(): Promise; + stop(reason: unknown): void; + string(): Promise; + tryDecode>(decode: (c: Cursor) => T): T | undefined; + u16(): Promise; + u53(): Promise; + u62(): Promise; + u8(): Promise; + varint(): Promise; + version: StreamVersion; +} + +interface ReadOptions { + from?: number; +} + +type Redirect = "follow" | "same-host" | "ignore"; + +class RefusedRedirect extends Error { + constructor(reason: string); +} + +type Relative = string & { + __brand: "Relative"; +}; + +function relative(target: Valid, base: Valid): Relative | undefined; + +type ReloadDelay = { + initial?: Milli; + multiplier?: number; + max?: Milli; + timeout?: Milli; +}; + +type ReloadStatus = "connecting" | "connected" | "disconnected"; + +class Request_2 { + accept(info?: Partial): Producer; + demand(): Demand; + readonly name: string; + get priority(): number; + reject(err?: Error): void; + stage(info?: Partial): Staged; + get subscription(): Readonly; +} + +class Request_3 { + readonly path: Path_2.Valid; + prepare(epoch: Epoch_2.Valid): Prepared; + reject(err: Error): void; +} + +const REQUEST_WINDOW = 240000n; + +class Requesting { + readonly active: Getter; + close(): void; + readonly closed: GetPromise; + readonly path: Path_2.Valid; +} + +interface RequestOptions { + announced?: boolean; + epoch?: Epoch_2.Valid; +} + +class Reservation implements Disposable { + [Symbol.dispose](): void; + close(): void; + get grant(): Getter; + peek(): number | undefined; + update(max: number): void; +} + +function resolve(base: Valid, rel: Relative): Valid; + +interface Route { + auth?: Auth_2; + cost: Cost; + epoch?: Epoch_2.Valid; + hops: Hop[]; +} + +const Route: { + default: Route; + normalize(route?: Route | { + epoch?: Epoch_2.Valid; + hops?: readonly Hop[]; + cost?: Cost; + auth?: Auth_2; + }): Route; +}; + +class ServerSetup { + constructor(input: { + version: number; + parameters?: SetupOptions; + }); + static decode(r: Reader, version: IetfVersion): Promise; + encode(w: Writer, version: IetfVersion): Promise; + static id: number; + parameters: SetupOptions; + version: number; +} + +class Session extends Error { + constructor(code: SessionCode, options?: { + cause?: unknown; + reason?: string; + }); + readonly code: SessionCode; +} + +const SESSION_CODE: unique symbol; + +export type SessionCode = number & { + readonly [SESSION_CODE]: true; +}; + +export const SessionCode: ((code: number) => SessionCode) & { + readonly Cancel: SessionCode; + readonly Internal: SessionCode; + readonly Unauthorized: SessionCode; + readonly Expired: SessionCode; + readonly ProtocolViolation: SessionCode; + readonly InvalidRequestId: SessionCode; + readonly KeyValueFormatting: SessionCode; + readonly TooManyRequests: SessionCode; + readonly InvalidPath: SessionCode; + readonly GoawayTimeout: SessionCode; + readonly Timeout: SessionCode; + readonly AuthTokenCacheOverflow: SessionCode; + readonly Version: SessionCode; + readonly MalformedAuthToken: SessionCode; + readonly UnknownAuthTokenAlias: SessionCode; + readonly InvalidAuthority: SessionCode; + readonly Unsupported: SessionCode; + readonly TooManyRequestUpdates: SessionCode; +}; + +class Setup { + constructor(input?: { + parameters?: SetupOptions; + }); + static decode(r: Reader, version: IetfVersion): Promise; + encode(w: Writer, version: IetfVersion): Promise; + static id: number; + parameters: SetupOptions; +} + +const SetupOption: { + readonly Path: 1n; + readonly MaxRequestId: 2n; + readonly AuthorizationToken: 3n; + readonly MaxAuthTokenCacheSize: 4n; + readonly Authority: 5n; + readonly Implementation: 7n; + readonly HopId: 0x40b54n; + readonly RelayCost: 0x40b56n; + readonly Solicit: 0x40b5an; + readonly Hidden: 0x40b5cn; + readonly MaxAge: 0x915c4n; + readonly Auth: 0x40b70n; + readonly ActiveCount: 0x40b64n; + readonly Epoch: 0x40b68n; +}; + +class SetupOptions { + constructor(); + bytes: Map; + static decode(r: Reader, version: IetfVersion): Promise; + encode(w: Writer, version: IetfVersion): Promise; + getBytes(id: bigint): Uint8Array | undefined; + getVarint(id: bigint): bigint | undefined; + removeBytes(id: bigint): boolean; + removeVarint(id: bigint): boolean; + setBytes(id: bigint, value: Uint8Array): void; + setVarint(id: bigint, value: bigint): void; + get size(): number; + vars: Map; +} + +export { Signals } + +function size(v: number): number; + +function sizeLeadingOnes(v: number | bigint): number; + +class Staged { + [Symbol.dispose](): void; + commit(): Producer; + readonly producer: Producer; +} + +interface Stats { + bytesLost?: number; + bytesReceived?: number; + bytesSent?: number; + estimatedSendRate?: number; + packetsLost?: number; + packetsReceived?: number; + packetsSent?: number; + rtt?: Milli; +} + +class Stream extends Error { + constructor(code: StreamCode, options?: StreamOptions); + readonly code: StreamCode; +} + +const STREAM_CODE: unique symbol; + +export type StreamCode = number & { + readonly [STREAM_CODE]: true; +}; + +export const StreamCode: ((code: number) => StreamCode) & { + readonly Internal: StreamCode; + readonly Cancel: StreamCode; + readonly DeliveryTimeout: StreamCode; + readonly SessionClosed: StreamCode; + readonly GoingAway: StreamCode; + readonly TooFarBehind: StreamCode; + readonly MalformedTrack: StreamCode; + readonly ControlTimeout: StreamCode; + readonly NotFound: StreamCode; + readonly Old: StreamCode; + readonly Evicted: StreamCode; + readonly FrameTooLarge: StreamCode; + readonly Unroutable: StreamCode; + readonly Unauthorized: StreamCode; + readonly GroupTooLarge: StreamCode; + readonly TimestampMismatch: StreamCode; +}; + +interface StreamOptions { + cause?: unknown; + message?: string; + reason?: string; +} + +type StreamVersion = IetfVersion | Version_2; + +function stripPrefix(prefix: Valid, path: Valid): Valid | null; + +class Subscriber { + close(abort?: Error): void; + get closed(): GetPromise; + end(): Position_2 | undefined; + finished(): Promise; + info(): Promise; + largest(): Promise; + readonly name: string; + ordered(): Ordered; + recvDatagram(): Promise; + recvGroup(): Promise; + get subscription(): Getter; + tryRecvGroup(): Consumer_2 | undefined; + update(options: Subscription): void; + withRange(groups: Groups): this; +} + +interface Subscription { + groups?: Groups; + maxDelay?: Milli; + order?: Order; + priority?: number; +} + +interface Table { + announced(scope?: Path_2.Pattern, options?: Announce_3.Options): Announce_3.Consumer; + readonly closed: GetPromise; + createBroadcast(path: Path_2.Valid): Broadcast_2.Producer; + readonly discovery: Getter; + dynamic(prefix: Path_2.Valid): Dynamic; + request(path: Path_2.Valid, options?: RequestOptions): Requesting; +} + +declare namespace Time { + export { + Timescale, + Timestamp + } +} + +function time(epoch: Valid_2): Date; + +export interface Timed { + at?: Timestamp; + value: T; +} + +type Timescale = number & { + readonly _brand: "timescale"; +}; + +const Timescale: ((unitsPerSecond: number) => Timescale) & { + SECOND: Timescale; + MILLI: Timescale; + MICRO: Timescale; + NANO: Timescale; +}; + +class Timestamp { + constructor(value: number, scale: Timescale); + as(scale: Timescale): number; + asMicros(): number; + asMillis(): number; + static fromMicros(us: number): Timestamp; + static fromMillis(ms: number): Timestamp; + isBefore(other: Timestamp): boolean; + static now(): Timestamp; + readonly scale: Timescale; + readonly value: number; +} + +class TimestampMismatch extends Stream { + constructor(options?: { + cause?: unknown; + }); +} + +class TooFarBehind extends Stream { + constructor(options?: { + cause?: unknown; + }); +} + +declare namespace Track { + export { + infoDefaults, + Datagram, + Position_2 as Position, + Info, + Bound, + Groups, + Subscription, + Order, + Request_2 as Request, + Staged, + FetchGroupOptions, + Consumer_3 as Consumer, + Demand, + Producer, + Subscriber, + Ordered + } +} + +declare namespace track { + export { + infoDefaults, + Datagram, + Position_2 as Position, + Info, + Bound, + Groups, + Subscription, + Order, + Request_2 as Request, + Staged, + FetchGroupOptions, + Consumer_3 as Consumer, + Demand, + Producer, + Subscriber, + Ordered + } +} + +class Tracks { + [Symbol.asyncIterator](): AsyncGenerator; + close(): void; + next(): Promise; +} + +type TracksEvent = { + kind: "added"; + name: string; + info: track.Info; +} | { + kind: "synced"; +} | { + kind: "removed"; + name: string; +} | { + kind: "finished"; + name: string; +}; + +type Transport = "webtransport" | "websocket" | "webrtc"; + +interface TryOpenOptions extends OpenOptions { + cancel: Promise; +} + +function tryResolve(base: Valid, rel: Relative): Valid | undefined; + +class U64 { + constructor(hi: number, lo: number); + add(delta: number): U64; + compare(other: U64): number; + equals(other: U64): boolean; + static fromBigInt(v: bigint): U64; + static fromNumber(v: number): U64; + readonly hi: number; + readonly lo: number; + static readonly MAX: U64; + toBigInt(): bigint; + toNumber(): number; + toString(): string; + static readonly ZERO: U64; +} + +class Unsupported extends Error { + constructor(message?: string); + readonly code: SessionCode; +} + +type Valid = string & { + __brand: "Name"; +}; + +type Valid_2 = string & { + readonly _brand: "epoch"; +}; + +declare namespace Varint { + export { + sizeLeadingOnes, + encodeLeadingOnesTo, + encodeLeadingOnes, + decodeLeadingOnes, + size, + encodeTo, + encode_2 as encode, + decodeBigInt, + decode_2 as decode, + MAX_U6, + MAX_U14, + MAX_U30, + MAX_U53 + } +} + +const Version: { + readonly DRAFT_07: 4278190087; + readonly DRAFT_14: 4278190094; + readonly DRAFT_15: 4278190095; + readonly DRAFT_16: 4278190096; + readonly DRAFT_17: 4278190097; + readonly DRAFT_18: 4278190098; + readonly DRAFT_19: 4278190099; + readonly DRAFT_20: 4278190100; + readonly DRAFT_21: 4278190101; + readonly DRAFT_22: 4278190102; +}; + +type Version = (typeof Version)[keyof typeof Version]; + +const Version_2: { + readonly DRAFT_01: 4279086337; + readonly DRAFT_02: 4279086338; + readonly DRAFT_03: 4279086339; + readonly DRAFT_04: 4279086340; + readonly DRAFT_05: 4279086341; + readonly DRAFT_06: 4279086342; + readonly DRAFT_07: 4279086343; +}; + +type Version_2 = (typeof Version_2)[keyof typeof Version_2]; + +function versionName(v: Version): string; + +interface WebSocketProps { + delay?: Milli; + enabled?: boolean; + url?: URL; +} + +interface WebTransportProps extends Omit { + serverCertificate?: string | BufferSource; + serverCertificateHashes?: CertificateHash[]; +} + +class Writer { + constructor(stream: WritableStream, version: StreamVersion); + bool(v: boolean): Promise; + close(): void; + get closed(): Promise; + static collect(version: StreamVersion, f: (w: Writer) => Promise): Promise; + i32(v: number): Promise; + static open(quic: WebTransport, options: OpenOptions): Promise; + reset(reason: unknown): void; + setPriority(sendOrder: number): void; + string(str: string): Promise; + static tryOpen(quic: WebTransport, options: TryOpenOptions): Promise; + u16(v: number): Promise; + u53(v: number): Promise; + u62(v: bigint): Promise; + u8(v: number): Promise; + varint(v: U64): Promise; + version: StreamVersion; + write(v: Uint8Array): Promise; +} + + +``` diff --git a/js/net/api/zod.api.md b/js/net/api/zod.api.md new file mode 100644 index 00000000000..953b970143b --- /dev/null +++ b/js/net/api/zod.api.md @@ -0,0 +1,268 @@ +## API Report File for "@moq/net" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { GetPromise } from '@moq/signals'; +import { Getter } from '@moq/signals'; +import { Milli } from '@moq/clock'; +import type * as z from '@zod/mini'; + +type Bound = { + included: number; + excluded?: never; +} | { + excluded: number; + included?: never; +}; + +class Consumer { + close(abort?: Error): void; + get closed(): GetPromise; + get done(): boolean; + get frameCount(): number; + get isClosed(): boolean; + readable(): Promise; + readBool(): Promise; + readFrame(): Promise; + readFrameSequence(options?: ReadOptions): Promise<({ + sequence: number; + } & Frame) | undefined>; + readJson(): Promise; + readString(): Promise; + readonly sequence: number; + tryReadFrame(): Frame | undefined; + tryReadFrameSequence(): ({ + sequence: number; + } & Frame) | undefined; +} + +class Consumer_2 { + fetchGroup(sequence: number, options?: FetchGroupOptions): Promise; + info(): Promise; + readonly name: string; + subscribe(options?: Subscription): Subscriber; +} + +interface Datagram { + payload: Uint8Array; + sequence: number; + timestamp?: Timestamp; +} + +class Demand { + get closed(): GetPromise; + readonly name: string; + get wanted(): Getter; +} + +class Demand_2 { + get closed(): GetPromise; + readonly sequence: number; + unused(): Promise; + get used(): Getter; +} + +interface FetchGroupOptions { + maxDelay?: Milli; + priority?: number; + signal?: AbortSignal; +} + +interface Frame { + payload: Uint8Array; + timestamp?: Timestamp; +} + +declare namespace group { + export { + MAX_GROUP_CACHE_BYTES, + MAX_GROUP_FRAMES, + Frame, + ReadOptions, + Info_2 as Info, + Demand_2 as Demand, + Producer_2 as Producer, + Consumer + } +} + +interface Groups { + end?: Bound; + start?: Bound; +} + +interface Info { + compress?: boolean; + maxAge?: Milli; + priority: number; + refresh?: number; + timescale?: Timescale | null; +} + +interface Info_2 { + sequence: number; +} + +function infoDefaults(info?: Partial): Info; + +const MAX_GROUP_CACHE_BYTES: number; + +const MAX_GROUP_FRAMES = 8192; + +type Order = "ascending" | "descending"; + +class Ordered { + close(abort?: Error): void; + get closed(): GetPromise; + end(): Position_2 | undefined; + finished(): Promise; + info(): Promise; + largest(): Promise; + readonly name: string; + nextGroup(): Promise; + readBool(): Promise; + readFrame(): Promise<({ + group: number; + frame: number; + } & Frame) | undefined>; + readJson(): Promise; + readString(): Promise; + recvDatagram(): Promise; + get subscription(): Getter; + tryNextGroup(): Consumer | undefined; + update(options: Subscription): void; + withRange(groups: Groups): this; +} + +interface Position_2 { + frame: number; + group: number; +} + +class Producer { + constructor(name: string); + accept(info?: Partial): this; + appendDatagram(timestamp: Timestamp | undefined, payload: Uint8Array): number; + appendGroup(): Producer_2; + close(abort?: Error): void; + get closed(): GetPromise; + demand(): Demand; + dropGroups(start: number, end: number, error: Error): void; + finishAt(end: Position_2): void; + info(): Promise; + insertDatagram(sequence: number, timestamp: Timestamp | undefined, payload: Uint8Array): void; + largest(): Position_2 | undefined; + readonly name: string; + get priority(): number; + subscribe(options?: Subscription): Subscriber; + get subscription(): Getter; + writeFrame(frame: Frame): void; + writeGroup(group: Producer_2): void; +} + +class Producer_2 { + constructor(sequence: number); + close(abort?: Error): void; + get closed(): GetPromise; + consume(): Consumer; + demand(): Demand_2; + get isClosed(): boolean; + readonly sequence: number; + writeFrame(frame: Frame): void; +} + +export function read(source: track.Ordered | group.Consumer, schema: z.ZodMiniType): Promise; + +interface ReadOptions { + from?: number; +} + +class Request_2 { + accept(info?: Partial): Producer; + demand(): Demand; + readonly name: string; + get priority(): number; + reject(err?: Error): void; + stage(info?: Partial): Staged; + get subscription(): Readonly; +} + +class Staged { + [Symbol.dispose](): void; + commit(): Producer; + readonly producer: Producer; +} + +class Subscriber { + close(abort?: Error): void; + get closed(): GetPromise; + end(): Position_2 | undefined; + finished(): Promise; + info(): Promise; + largest(): Promise; + readonly name: string; + ordered(): Ordered; + recvDatagram(): Promise; + recvGroup(): Promise; + get subscription(): Getter; + tryRecvGroup(): Consumer | undefined; + update(options: Subscription): void; + withRange(groups: Groups): this; +} + +interface Subscription { + groups?: Groups; + maxDelay?: Milli; + order?: Order; + priority?: number; +} + +type Timescale = number & { + readonly _brand: "timescale"; +}; + +const Timescale: ((unitsPerSecond: number) => Timescale) & { + SECOND: Timescale; + MILLI: Timescale; + MICRO: Timescale; + NANO: Timescale; +}; + +class Timestamp { + constructor(value: number, scale: Timescale); + as(scale: Timescale): number; + asMicros(): number; + asMillis(): number; + static fromMicros(us: number): Timestamp; + static fromMillis(ms: number): Timestamp; + isBefore(other: Timestamp): boolean; + static now(): Timestamp; + readonly scale: Timescale; + readonly value: number; +} + +declare namespace track { + export { + infoDefaults, + Datagram, + Position_2 as Position, + Info, + Bound, + Groups, + Subscription, + Order, + Request_2 as Request, + Staged, + FetchGroupOptions, + Consumer_2 as Consumer, + Demand, + Producer, + Subscriber, + Ordered + } +} + + +``` diff --git a/js/net/src/ietf/request_stream.ts b/js/net/src/ietf/request_stream.ts index 7fe11930944..b2f477b4cb9 100644 --- a/js/net/src/ietf/request_stream.ts +++ b/js/net/src/ietf/request_stream.ts @@ -78,7 +78,11 @@ export async function refuseUpdate( if (version !== Version.DRAFT_14) await writeRefusal(w, version, kind, refusal); } -/** Refuse an unrecognized reserved namespace before it reaches the application. */ +/** + * Refuse an unrecognized reserved namespace before it reaches the application. + * + * @internal + */ export async function refuseReserved(request: RequestStream): Promise { await request.refuse("subscribe", { condition: "does_not_exist", diff --git a/js/net/src/listing.ts b/js/net/src/listing.ts index 2ca070e1ba7..736f742cdb0 100644 --- a/js/net/src/listing.ts +++ b/js/net/src/listing.ts @@ -418,6 +418,7 @@ export class Lister { #listing: Listing; #closed = false; + /** @internal */ constructor(listing: Listing) { listing.attach(); this.#listing = listing; diff --git a/js/p2p/api/index.api.md b/js/p2p/api/index.api.md new file mode 100644 index 00000000000..4902d82344d --- /dev/null +++ b/js/p2p/api/index.api.md @@ -0,0 +1,35 @@ +## API Report File for "@moq/p2p" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +export interface AcceptProps extends ConnectProps { + channel: RTCDataChannel; +} + +export interface ConnectProps { + peer: RTCPeerConnection; + protocol: string; +} + +export class Transport implements WebTransport { + static accept(props: AcceptProps): Transport; + close(info?: WebTransportCloseInfo): void; + readonly closed: Promise; + readonly congestionControl = "default"; + static connect(input: ConnectProps): Transport; + createBidirectionalStream(options?: WebTransportSendStreamOptions): Promise; + createUnidirectionalStream(options?: WebTransportSendStreamOptions): Promise>; + readonly datagrams: WebTransportDatagramDuplexStream; + getStats(): Promise; + readonly incomingBidirectionalStreams: ReadableStream; + readonly incomingUnidirectionalStreams: ReadableStream>; + readonly protocol: string; + readonly ready: Promise; + readonly reliability = "reliable-only"; + readonly transport = "webrtc"; +} + + +``` diff --git a/js/pattern/api/index.api.md b/js/pattern/api/index.api.md new file mode 100644 index 00000000000..0b82ad97195 --- /dev/null +++ b/js/pattern/api/index.api.md @@ -0,0 +1,99 @@ +## API Report File for "@moq/pattern" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +export function compareSpecificity(a: Specificity, b: Specificity): number; + +export class IntersectionError extends Error { + constructor(); +} + +export class InvalidPattern extends Error { + constructor(code: InvalidPattern.Code, message: string); + readonly code: InvalidPattern.Code; +} + +export namespace InvalidPattern { + export type Code = + /** A segment is empty: a leading, trailing, or doubled `/`. */ + "empty-segment" + /** A segment's kind, fields, or wildcard syntax is invalid. */ + | "invalid-segment" + /** More than one `**`. */ + | "multiple-globstars" + /** More than {@link Pattern.MAX_SEGMENTS} segments. */ + | "too-many-segments"; +} + +export class Pattern { + static all(): Pattern; + asPrefix(): string | undefined; + captures(matched: Pattern): Pattern[] | undefined; + static compare(a: Pattern, b: Pattern): number; + contains(other: Pattern): boolean; + static empty(): Pattern; + equals(other: Pattern): boolean; + static from(segments: Iterable): Pattern; + get hasGlobstar(): boolean; + get head(): string; + intersect(other: Pattern): Patterns; + get isLiteral(): boolean; + static literal(path: string): Pattern; + matches(path: string): boolean; + static get MAX_INTERSECTIONS(): number; + static get MAX_SEGMENTS(): number; + overlaps(other: Pattern): boolean; + static parse(text: string): Pattern; + rebase(root: string): Patterns; + rooted(root: string): Pattern; + readonly segments: readonly Segment[]; + specificity(): Specificity; + static subtree(path: string): Pattern; + readonly text: string; + toJSON(): string; + toString(): string; +} + +export class Patterns implements Iterable { + [Symbol.iterator](): Iterator; + constructor(patterns?: Iterable); + contains(pattern: Pattern): boolean; + covers(other: Patterns): boolean; + equals(other: Patterns): boolean; + insert(pattern: Pattern): boolean; + intersect(other: Patterns): Patterns; + matches(path: string): boolean; + overlaps(pattern: Pattern): boolean; + rebase(root: string): Patterns; + rooted(root: string): Patterns; + get size(): number; + toArray(): Pattern[]; + toJSON(): string[]; +} + +export type Segment = { + readonly kind: "literal"; + readonly value: string; +} | { + readonly kind: "wildcard"; +} | { + readonly kind: "partial"; + readonly prefix: string; + readonly suffix: string; +} | { + readonly kind: "globstar"; +}; + +export interface Specificity { + readonly exact: boolean; + readonly head: number; + readonly literals: number; + readonly partials: number; + readonly pinned: number; + readonly wildcards: number; +} + + +``` diff --git a/js/publish/api/element.api.md b/js/publish/api/element.api.md new file mode 100644 index 00000000000..eaf1a59e8cc --- /dev/null +++ b/js/publish/api/element.api.md @@ -0,0 +1,625 @@ +## API Report File for "@moq/publish" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { Backend } from '@moq/video'; +import * as Catalog from '@moq/hang/catalog'; +import { Dispose } from '@moq/signals'; +import { Effect } from '@moq/signals'; +import { Getter } from '@moq/signals'; +import { Inputs } from '@moq/signals'; +import { Micro } from '@moq/clock'; +import { Milli } from '@moq/clock'; +import * as Moq from '@moq/net'; +import { Readonlys } from '@moq/signals'; +import { Signal } from '@moq/signals'; +import * as Video_2 from '@moq/video'; + +type Aac = "aac" | AacConfig; + +type AacConfig = { + mime: "aac"; + bitrate?: number; +}; + +export type AnnounceMode = "always" | "source" | "never"; + +declare namespace Audio_2 { + export { + Aac, + AacConfig, + Codec, + Encoder_2 as Encoder, + EncoderInput_2 as EncoderInput, + EncoderProps_2 as EncoderProps, + Opus, + OpusConfig, + Stats_2 as Stats, + Rendition_3 as Rendition, + AudioFrame, + Format, + CaptureInput_2 as CaptureInput, + CaptureProps, + Capture_2 as Capture, + isSampleSource, + sourceKind, + normalizeSource_2 as normalizeSource, + Kind_2 as Kind, + CodecMime, + Source_2 as Source, + SourceConfig_2 as SourceConfig, + SampleSource, + Constraints_2 as Constraints, + StreamTrack_2 as StreamTrack, + TrackSettings_2 as TrackSettings + } +} + +interface AudioFrame { + channels: Float32Array[]; + timestamp: Micro; +} + +class Broadcast { + constructor(props?: Inputs); + audio(name: string): Rendition_2; + readonly catalog: CatalogProducer; + static readonly CATALOG_TRACK = "catalog.json"; + static readonly CATALOG_TRACK_COMPRESSED = "catalog.json.z"; + close(): void; + readonly in: Readonlys; + readonly net: Getter; + text(name: string): Rendition_2; + video(name: string): Rendition_2; +} + +type BroadcastInput = { + origin: Getter; + enabled: Getter; + announce: Getter; + name: Getter; + display: Getter<{ + width: number; + height: number; + } | undefined>; + flip: Getter; + rotation: Getter; + maxAge: Getter; +}; + +class Camera { + constructor(props?: CameraProps); + close(): void; + constraints: Signal; + static readonly DEFAULT_CONSTRAINTS: Video.Constraints; + readonly device: Device<"video">; + readonly in: Readonlys; + readonly out: Readonlys; +} + +type CameraInput = { + enabled: Getter; +}; + +type CameraOutput = { + source: Signal; + orientation: Signal; + error: Signal; +}; + +interface CameraProps extends Inputs { + constraints?: Video.Constraints | Signal; + device?: DeviceProps; +} + +class Capture { + constructor(props?: Inputs); + close(): void; + readonly in: Readonlys; + readonly out: Readonlys; +} + +class Capture_2 { + constructor(props?: CaptureProps); + channelCount: Signal; + close(): void; + readonly in: Readonlys; + readonly out: Readonlys; + sampleRate: Signal; +} + +type CaptureInput = { + source: Getter; + orientation: Getter; +}; + +type CaptureInput_2 = { + source: Getter; + enabled: Getter; +}; + +type CaptureOutput = { + frames: Signal | undefined>; + display: Signal<{ + width: number; + height: number; + scale?: number; + } | undefined>; + rotation: Signal; +}; + +type CaptureOutput_2 = { + frames: Signal | undefined>; + format: Signal; + root: Signal; +}; + +type CaptureProps = Inputs & { + sampleRate?: number | Signal; + channelCount?: number | Signal; +}; + +class CatalogProducer { + mutate(fn: (catalog: Catalog.Root) => void): void; + serve(track: Moq.Track.Producer, effect: Effect, opts?: { + compression?: boolean; + }): void; +} + +type Codec = Opus | Aac; + +type CodecMime = "opus" | "aac"; + +interface Config { + bitrateScale?: number; + codec?: string; + frameRate?: number; + keyframeInterval?: Milli; + maxBitrate?: number; + maxPixels?: number; + maxScale?: number; +} + +type Constraints = Omit & { + resizeMode?: "none" | "crop-and-scale"; +}; + +type Constraints_2 = Omit; + +class Device { + constructor(kind: Kind, props?: DeviceProps); + capture(deviceId: string | undefined): Dispose; + close(): void; + readonly kind: Kind; + readonly out: Readonlys; + preferred: Signal; + requestPermission(): void; +} + +type DeviceOutput = { + available: Signal; + default: Signal; + requested: Signal; + active: Signal; + permission: Signal; +}; + +interface DeviceProps { + preferred?: string | Signal; +} + +class Encoder { + constructor(name: string, props?: EncoderProps); + get capture(): Capture | undefined; + close(): void; + config: Signal; + cut(): void; + readonly in: Readonlys; + readonly name: string; + readonly out: Readonlys; +} + +class Encoder_2 { + constructor(name: string, props?: EncoderProps_2); + get capture(): Capture_2 | undefined; + close(): void; + codec: Signal; + groupDuration: Signal; + readonly in: Readonlys; + readonly name: string; + readonly out: Readonlys; + volume: Signal; +} + +type EncoderInput = { + enabled: Getter; + broadcast: Getter; + capture: Getter; + bandwidth: Getter; +}; + +type EncoderInput_2 = { + enabled: Getter; + broadcast: Getter; + capture: Getter; + bandwidth: Getter; +}; + +type EncoderOutput = { + error: Signal; + catalog: Signal; + resolved: Signal; + active: Signal; + stats: Signal; +}; + +type EncoderOutput_2 = { + error: Signal; + catalog: Signal; + root: Signal; + active: Signal; + stats: Signal; +}; + +type EncoderProps = Inputs & { + config?: Config | Signal; +}; + +type EncoderProps_2 = Inputs & { + volume?: number | Signal; + codec?: Codec | Signal; + groupDuration?: Milli | Signal; +}; + +class Fanout { + constructor(source: ReadableStream, props?: FanoutProps); + close(): void; + subscribe(effect: Effect, queue?: number): ReadableStream; +} + +interface FanoutProps { + clone?: (value: T) => T; + queue?: number; + release?: (value: T) => void; +} + +class File_2 { + constructor(props?: FileProps); + close(): void; + file: Signal; + readonly in: Readonlys; + readonly out: Readonlys; + prompt(): void; +} + +type FileInput = { + enabled: Getter; +}; + +type FileOutput = { + source: Signal; +}; + +interface FileProps extends Inputs { + file?: globalThis.File | Signal; +} + +interface Format { + channelCount: number; + sampleRate: number; +} + +interface FrameSource { + frameRate?: number; + frames: ReadableStream; +} + +function isSampleSource(source: Source_2): source is SampleSource; + +function isStreamTrack(source: Source): source is StreamTrack; + +type Kind = "video" | "audio" | "text"; + +type Kind_2 = "voice" | "music" | "auto"; + +type Media = { + video?: Video.Source; + audio?: Audio_2.Source; +}; + +class Microphone { + constructor(props?: MicrophoneProps); + close(): void; + constraints: Signal; + readonly device: Device<"audio">; + readonly in: Readonlys; + readonly out: Readonlys; +} + +type MicrophoneInput = { + enabled: Getter; +}; + +type MicrophoneOutput = { + source: Signal; + error: Signal; +}; + +interface MicrophoneProps extends Inputs { + constraints?: Audio_2.Constraints | Signal; + device?: DeviceProps; +} + +type Mode = "none" | "source" | "encoded"; + +class MoqPublish extends HTMLElement { + constructor(); + get announce(): AnnounceMode; + set announce(value: AnnounceMode); + attributeChangedCallback(name: Observed, oldValue: string | null, newValue: string | null): void; + audio: Audio_2.Encoder; + get backend(): Preview.Backend; + set backend(value: Preview.Backend); + broadcast: Broadcast; + connectedCallback(): void; + connection: Moq.Connection; + readonly controls: { + source: Signal; + muted: Signal; + invisible: Signal; + preview: Signal; + backend: Signal; + announce: Signal; + }; + disconnectedCallback(): void; + get invisible(): boolean; + set invisible(value: boolean); + get muted(): boolean; + set muted(value: boolean); + get name(): Moq.Path.Valid; + set name(value: string | Moq.Path.Valid); + static observedAttributes: readonly ["url", "versions", "name", "muted", "invisible", "source", "preview", "backend", "announce"]; + get preview(): Preview.Mode; + set preview(value: Preview.Mode); + readonly signals: Effect; + get source(): SourceType | File | undefined; + set source(value: SourceType | File | undefined); + readonly sources: Moq.Signals.Readonlys<{ + video: Signal; + audio: Signal; + file: Signal; + }>; + get url(): URL | undefined; + set url(value: string | URL | undefined); + get versions(): readonly string[] | undefined; + set versions(value: readonly string[] | undefined); + video: Video.Encoder; +} +export default MoqPublish; + +function normalizeSource(source: StreamTrack | SourceConfig): SourceConfig; + +function normalizeSource_2(source: StreamTrack_2 | SourceConfig_2): SourceConfig_2; + +const OBSERVED: readonly ["url", "versions", "name", "muted", "invisible", "source", "preview", "backend", "announce"]; + +type Observed = (typeof OBSERVED)[number]; + +type Opus = "opus" | OpusConfig; + +type OpusConfig = { + mime: "opus"; + bitrate?: number; + frameDuration?: Milli; + complexity?: number; + packetlossperc?: number; + useinbandfec?: boolean; +}; + +declare namespace Preview { + export { + Backend, + Mode, + RendererInput, + RendererProps, + Renderer, + TranscodeInput, + TranscodeProps, + Transcode + } +} + +class Renderer { + constructor(props?: RendererProps); + close(): void; + readonly in: Readonlys; + readonly out: Readonlys<{ + error: Getter; + }>; +} + +type RendererInput = { + canvas: Getter; + frames: Getter | undefined>; + display: Getter<{ + width: number; + height: number; + } | undefined>; + flip: Getter; + rotation: Getter; + encoder: Getter; + mode: Getter; + enabled: Getter; + backend: Getter; +}; + +type RendererProps = Inputs; + +type Rendition = Rendition_2; + +class Rendition_2 { + close(): void; + readonly config: Signal; + readonly kind: Kind; + readonly name: string; + readonly track: Getter; +} + +type Rendition_3 = Rendition_2; + +interface SampleSource { + channelCount: number; + kind: Kind_2; + sampleRate: number; + samples: ReadableStream; +} + +class Screen_2 { + constructor(props?: ScreenProps); + audio: Signal; + close(): void; + readonly in: Readonlys; + readonly out: Readonlys; + video: Signal; +} + +type ScreenInput = { + enabled: Getter; +}; + +type ScreenOutput = { + source: Signal; +}; + +interface ScreenProps extends Inputs { + audio?: Audio_2.Constraints | boolean | Signal; + video?: Video.Constraints | boolean | Signal; +} + +type Source = StreamTrack | SourceConfig | FrameSource; + +type Source_2 = StreamTrack_2 | SourceConfig_2 | SampleSource; + +declare namespace Source_3 { + export { + CameraInput, + CameraProps, + Camera, + DeviceProps, + Device, + FileInput, + FileProps, + File_2 as File, + MicrophoneInput, + MicrophoneProps, + Microphone, + ScreenInput, + ScreenProps, + Screen_2 as Screen, + Media + } +} + +interface SourceConfig { + scale?: number; + track: StreamTrack; +} + +interface SourceConfig_2 { + kind: Kind_2; + track: StreamTrack_2; +} + +function sourceKind(source: Source_2): Kind_2; + +export type SourceType = "camera" | "screen" | "file"; + +interface Stats { + bytes: number; + frames: number; + keyframes: number; +} + +interface Stats_2 { + bytes: number; + frames: number; +} + +interface StreamTrack extends MediaStreamTrack { + clone(): StreamTrack; + getSettings(): TrackSettings; + kind: "video"; +} + +interface StreamTrack_2 extends MediaStreamTrack { + clone(): StreamTrack_2; + getSettings(): TrackSettings_2; + kind: "audio"; +} + +interface TrackSettings { + aspectRatio: number; + deviceId: string; + facingMode: "user" | "environment" | "left" | "right"; + frameRate?: number; + groupId: string; + height: number; + resizeMode: "none" | "crop-and-scale"; + width: number; +} + +interface TrackSettings_2 { + autoGainControl?: boolean; + channelCount?: number; + deviceId: string; + echoCancellation?: boolean; + groupId: string; + noiseSuppression?: boolean; + sampleRate: number; + sampleSize?: number; +} + +class Transcode { + constructor(props?: TranscodeProps); + close(): void; + readonly in: Readonlys; + readonly out: Readonlys; +} + +type TranscodeInput = { + source: Getter | undefined>; + config: Getter; + settings: Getter; +}; + +type TranscodeOutput = { + frame: Signal; +}; + +type TranscodeProps = Inputs; + +declare namespace Video { + export { + Rendition, + CaptureInput, + Capture, + Stats, + Config, + EncoderInput, + EncoderProps, + Encoder, + normalizeSource, + isStreamTrack, + Source, + SourceConfig, + FrameSource, + StreamTrack, + TrackSettings, + Constraints + } +} + + +``` diff --git a/js/publish/api/index.api.md b/js/publish/api/index.api.md new file mode 100644 index 00000000000..43d1cad25f5 --- /dev/null +++ b/js/publish/api/index.api.md @@ -0,0 +1,637 @@ +## API Report File for "@moq/publish" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { Backend } from '@moq/video'; +import * as Catalog from '@moq/hang/catalog'; +import * as Clock from '@moq/clock'; +import { Dispose } from '@moq/signals'; +import { Effect } from '@moq/signals'; +import { Getter } from '@moq/signals'; +import * as Hang from '@moq/hang'; +import { Inputs } from '@moq/signals'; +import { Micro } from '@moq/clock'; +import { Milli } from '@moq/clock'; +import * as Net from '@moq/net'; +import { Readonlys } from '@moq/signals'; +import { Signal } from '@moq/signals'; +import * as Signals from '@moq/signals'; +import * as Video_2 from '@moq/video'; + +type Aac = "aac" | AacConfig; + +type AacConfig = { + mime: "aac"; + bitrate?: number; +}; + +export function assets(url: string | URL): void; + +declare namespace Audio_2 { + export { + Aac, + AacConfig, + Codec, + Encoder, + EncoderInput, + EncoderProps, + Opus, + OpusConfig, + Stats, + Rendition_2 as Rendition, + AudioFrame, + Format, + CaptureInput, + CaptureProps, + Capture, + isSampleSource, + sourceKind, + normalizeSource, + Kind_2 as Kind, + CodecMime, + Source_2 as Source, + SourceConfig, + SampleSource, + Constraints, + StreamTrack, + TrackSettings + } +} + +declare namespace Audio_3 { + export { + Aac, + AacConfig, + Codec, + Encoder, + EncoderInput, + EncoderProps, + Opus, + OpusConfig, + Stats, + Rendition_2 as Rendition, + AudioFrame, + Format, + CaptureInput, + CaptureProps, + Capture, + isSampleSource, + sourceKind, + normalizeSource, + Kind_2 as Kind, + CodecMime, + Source_2 as Source, + SourceConfig, + SampleSource, + Constraints, + StreamTrack, + TrackSettings + } +} + +interface AudioFrame { + channels: Float32Array[]; + timestamp: Micro; +} + +export class Broadcast { + constructor(props?: Inputs); + audio(name: string): Rendition; + readonly catalog: CatalogProducer; + static readonly CATALOG_TRACK = "catalog.json"; + static readonly CATALOG_TRACK_COMPRESSED = "catalog.json.z"; + close(): void; + readonly in: Readonlys; + readonly net: Getter; + text(name: string): Rendition; + video(name: string): Rendition; +} + +export type BroadcastInput = { + origin: Getter; + enabled: Getter; + announce: Getter; + name: Getter; + display: Getter<{ + width: number; + height: number; + } | undefined>; + flip: Getter; + rotation: Getter; + maxAge: Getter; +}; + +class Camera { + constructor(props?: CameraProps); + close(): void; + constraints: Signal; + static readonly DEFAULT_CONSTRAINTS: Encoder_2.Constraints; + readonly device: Device<"video">; + readonly in: Readonlys; + readonly out: Readonlys; +} + +type CameraInput = { + enabled: Getter; +}; + +type CameraOutput = { + source: Signal; + orientation: Signal; + error: Signal; +}; + +interface CameraProps extends Inputs { + constraints?: Encoder_2.Constraints | Signal; + device?: DeviceProps; +} + +class Capture { + constructor(props?: CaptureProps); + channelCount: Signal; + close(): void; + readonly in: Readonlys; + readonly out: Readonlys; + sampleRate: Signal; +} + +class Capture_2 { + constructor(props?: Inputs); + close(): void; + readonly in: Readonlys; + readonly out: Readonlys; +} + +type CaptureInput = { + source: Getter; + enabled: Getter; +}; + +type CaptureInput_2 = { + source: Getter; + orientation: Getter; +}; + +type CaptureOutput = { + frames: Signal | undefined>; + format: Signal; + root: Signal; +}; + +type CaptureOutput_2 = { + frames: Signal | undefined>; + display: Signal<{ + width: number; + height: number; + scale?: number; + } | undefined>; + rotation: Signal; +}; + +type CaptureProps = Inputs & { + sampleRate?: number | Signal; + channelCount?: number | Signal; +}; + +export class CatalogProducer { + mutate(fn: (catalog: Catalog.Root) => void): void; + serve(track: Net.Track.Producer, effect: Effect, opts?: { + compression?: boolean; + }): void; +} + +export { Clock } + +type Codec = Opus | Aac; + +type CodecMime = "opus" | "aac"; + +interface Config { + bitrateScale?: number; + codec?: string; + frameRate?: number; + keyframeInterval?: Milli; + maxBitrate?: number; + maxPixels?: number; + maxScale?: number; +} + +type Constraints = Omit; + +type Constraints_2 = Omit & { + resizeMode?: "none" | "crop-and-scale"; +}; + +class Device { + constructor(kind: Kind, props?: DeviceProps); + capture(deviceId: string | undefined): Dispose; + close(): void; + readonly kind: Kind; + readonly out: Readonlys; + preferred: Signal; + requestPermission(): void; +} + +type DeviceOutput = { + available: Signal; + default: Signal; + requested: Signal; + active: Signal; + permission: Signal; +}; + +interface DeviceProps { + preferred?: string | Signal; +} + +class Encoder { + constructor(name: string, props?: EncoderProps); + get capture(): Capture | undefined; + close(): void; + codec: Signal; + groupDuration: Signal; + readonly in: Readonlys; + readonly name: string; + readonly out: Readonlys; + volume: Signal; +} + +declare namespace Encoder_2 { + export { + Rendition_3 as Rendition, + CaptureInput_2 as CaptureInput, + Capture_2 as Capture, + Stats_2 as Stats, + Config, + EncoderInput_2 as EncoderInput, + EncoderProps_2 as EncoderProps, + Encoder_3 as Encoder, + normalizeSource_2 as normalizeSource, + isStreamTrack, + Source_3 as Source, + SourceConfig_2 as SourceConfig, + FrameSource, + StreamTrack_2 as StreamTrack, + TrackSettings_2 as TrackSettings, + Constraints_2 as Constraints + } +} + +class Encoder_3 { + constructor(name: string, props?: EncoderProps_2); + get capture(): Capture_2 | undefined; + close(): void; + config: Signal; + cut(): void; + readonly in: Readonlys; + readonly name: string; + readonly out: Readonlys; +} + +type EncoderInput = { + enabled: Getter; + broadcast: Getter; + capture: Getter; + bandwidth: Getter; +}; + +type EncoderInput_2 = { + enabled: Getter; + broadcast: Getter; + capture: Getter; + bandwidth: Getter; +}; + +type EncoderOutput = { + error: Signal; + catalog: Signal; + root: Signal; + active: Signal; + stats: Signal; +}; + +type EncoderOutput_2 = { + error: Signal; + catalog: Signal; + resolved: Signal; + active: Signal; + stats: Signal; +}; + +type EncoderProps = Inputs & { + volume?: number | Signal; + codec?: Codec | Signal; + groupDuration?: Milli | Signal; +}; + +type EncoderProps_2 = Inputs & { + config?: Config | Signal; +}; + +class Fanout { + constructor(source: ReadableStream, props?: FanoutProps); + close(): void; + subscribe(effect: Effect, queue?: number): ReadableStream; +} + +interface FanoutProps { + clone?: (value: T) => T; + queue?: number; + release?: (value: T) => void; +} + +class File_2 { + constructor(props?: FileProps); + close(): void; + file: Signal; + readonly in: Readonlys; + readonly out: Readonlys; + prompt(): void; +} + +type FileInput = { + enabled: Getter; +}; + +type FileOutput = { + source: Signal; +}; + +interface FileProps extends Inputs { + file?: globalThis.File | Signal; +} + +interface Format { + channelCount: number; + sampleRate: number; +} + +interface FrameSource { + frameRate?: number; + frames: ReadableStream; +} + +export { Hang } + +function isSampleSource(source: Source_2): source is SampleSource; + +function isStreamTrack(source: Source_3): source is StreamTrack_2; + +export type Kind = "video" | "audio" | "text"; + +type Kind_2 = "voice" | "music" | "auto"; + +type Media = { + video?: Encoder_2.Source; + audio?: Audio_3.Source; +}; + +class Microphone { + constructor(props?: MicrophoneProps); + close(): void; + constraints: Signal; + readonly device: Device<"audio">; + readonly in: Readonlys; + readonly out: Readonlys; +} + +type MicrophoneInput = { + enabled: Getter; +}; + +type MicrophoneOutput = { + source: Signal; + error: Signal; +}; + +interface MicrophoneProps extends Inputs { + constraints?: Audio_3.Constraints | Signal; + device?: DeviceProps; +} + +type Mode = "none" | "source" | "encoded"; + +export { Net } + +function normalizeSource(source: StreamTrack | SourceConfig): SourceConfig; + +function normalizeSource_2(source: StreamTrack_2 | SourceConfig_2): SourceConfig_2; + +type Opus = "opus" | OpusConfig; + +type OpusConfig = { + mime: "opus"; + bitrate?: number; + frameDuration?: Milli; + complexity?: number; + packetlossperc?: number; + useinbandfec?: boolean; +}; + +declare namespace Preview { + export { + Backend, + Mode, + RendererInput, + RendererProps, + Renderer, + TranscodeInput, + TranscodeProps, + Transcode + } +} + +class Renderer { + constructor(props?: RendererProps); + close(): void; + readonly in: Readonlys; + readonly out: Readonlys<{ + error: Getter; + }>; +} + +type RendererInput = { + canvas: Getter; + frames: Getter | undefined>; + display: Getter<{ + width: number; + height: number; + } | undefined>; + flip: Getter; + rotation: Getter; + encoder: Getter; + mode: Getter; + enabled: Getter; + backend: Getter; +}; + +type RendererProps = Inputs; + +export class Rendition { + close(): void; + readonly config: Signal; + readonly kind: Kind; + readonly name: string; + readonly track: Getter; +} + +type Rendition_2 = Rendition; + +type Rendition_3 = Rendition; + +interface SampleSource { + channelCount: number; + kind: Kind_2; + sampleRate: number; + samples: ReadableStream; +} + +class Screen_2 { + constructor(props?: ScreenProps); + audio: Signal; + close(): void; + readonly in: Readonlys; + readonly out: Readonlys; + video: Signal; +} + +type ScreenInput = { + enabled: Getter; +}; + +type ScreenOutput = { + source: Signal; +}; + +interface ScreenProps extends Inputs { + audio?: Audio_3.Constraints | boolean | Signal; + video?: Encoder_2.Constraints | boolean | Signal; +} + +export { Signals } + +declare namespace Source { + export { + CameraInput, + CameraProps, + Camera, + DeviceProps, + Device, + FileInput, + FileProps, + File_2 as File, + MicrophoneInput, + MicrophoneProps, + Microphone, + ScreenInput, + ScreenProps, + Screen_2 as Screen, + Media + } +} + +type Source_2 = StreamTrack | SourceConfig | SampleSource; + +type Source_3 = StreamTrack_2 | SourceConfig_2 | FrameSource; + +interface SourceConfig { + kind: Kind_2; + track: StreamTrack; +} + +interface SourceConfig_2 { + scale?: number; + track: StreamTrack_2; +} + +function sourceKind(source: Source_2): Kind_2; + +interface Stats { + bytes: number; + frames: number; +} + +interface Stats_2 { + bytes: number; + frames: number; + keyframes: number; +} + +interface StreamTrack extends MediaStreamTrack { + clone(): StreamTrack; + getSettings(): TrackSettings; + kind: "audio"; +} + +interface StreamTrack_2 extends MediaStreamTrack { + clone(): StreamTrack_2; + getSettings(): TrackSettings_2; + kind: "video"; +} + +interface TrackSettings { + autoGainControl?: boolean; + channelCount?: number; + deviceId: string; + echoCancellation?: boolean; + groupId: string; + noiseSuppression?: boolean; + sampleRate: number; + sampleSize?: number; +} + +interface TrackSettings_2 { + aspectRatio: number; + deviceId: string; + facingMode: "user" | "environment" | "left" | "right"; + frameRate?: number; + groupId: string; + height: number; + resizeMode: "none" | "crop-and-scale"; + width: number; +} + +class Transcode { + constructor(props?: TranscodeProps); + close(): void; + readonly in: Readonlys; + readonly out: Readonlys; +} + +type TranscodeInput = { + source: Getter | undefined>; + config: Getter; + settings: Getter; +}; + +type TranscodeOutput = { + frame: Signal; +}; + +type TranscodeProps = Inputs; + +declare namespace Video { + export { + Rendition_3 as Rendition, + CaptureInput_2 as CaptureInput, + Capture_2 as Capture, + Stats_2 as Stats, + Config, + EncoderInput_2 as EncoderInput, + EncoderProps_2 as EncoderProps, + Encoder_3 as Encoder, + normalizeSource_2 as normalizeSource, + isStreamTrack, + Source_3 as Source, + SourceConfig_2 as SourceConfig, + FrameSource, + StreamTrack_2 as StreamTrack, + TrackSettings_2 as TrackSettings, + Constraints_2 as Constraints + } +} + + +``` diff --git a/js/publish/api/support-element.api.md b/js/publish/api/support-element.api.md new file mode 100644 index 00000000000..d391cbdab1a --- /dev/null +++ b/js/publish/api/support-element.api.md @@ -0,0 +1,19 @@ +## API Report File for "@moq/publish" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { Report as Report_2 } from '@moq/ui'; +import { Show } from '@moq/ui'; +import { Support } from '@moq/ui'; + +class MoqPublishSupport extends Support { + protected detect(): Promise; +} +export default MoqPublishSupport; + +export { Show } + + +``` diff --git a/js/publish/api/support.api.md b/js/publish/api/support.api.md new file mode 100644 index 00000000000..fed8c64abbe --- /dev/null +++ b/js/publish/api/support.api.md @@ -0,0 +1,43 @@ +## API Report File for "@moq/publish" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +type Audio_2 = { + aac: Level; + opus: Level; +}; +export { Audio_2 as Audio } + +export type Codec = { + hardware?: boolean; + software: boolean; +}; + +export type Full = { + webtransport: Level; + audio: { + capture: boolean; + encoding: Audio_2; + }; + video: { + capture: Level; + encoding: Video | undefined; + }; +}; + +export function isSupported(): Promise; + +export type Level = "full" | "partial" | "none"; + +export type Video = { + h264: Codec; + h265: Codec; + vp8: Codec; + vp9: Codec; + av1: Codec; +}; + + +``` diff --git a/js/publish/api/ui.api.md b/js/publish/api/ui.api.md new file mode 100644 index 00000000000..788ca2b3e62 --- /dev/null +++ b/js/publish/api/ui.api.md @@ -0,0 +1,15 @@ +## API Report File for "@moq/publish" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +class MoqPublishUi extends HTMLElement { + constructor(); + connectedCallback(): void; + disconnectedCallback(): void; +} +export default MoqPublishUi; + + +``` diff --git a/js/qmux/api/index.api.md b/js/qmux/api/index.api.md new file mode 100644 index 00000000000..8bb5d55ccc9 --- /dev/null +++ b/js/qmux/api/index.api.md @@ -0,0 +1,146 @@ +## API Report File for "@moq/qmux" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +export interface AcceptOptions extends Pick { + protocol?: string; +} + +export interface Config { + idleTimeout?: number | null; + maxDatagramFrameSize?: bigint | null; + maxRecordSize?: bigint; + maxStreamsBidi?: bigint; + maxStreamsUni?: bigint; + receiveWindow?: bigint; + streamReceiveWindow?: bigint; +} + +class Datagrams implements WebTransportDatagramDuplexStream { + constructor(send: (data: Uint8Array) => void); + close(err?: Error): void; + incomingHighWaterMark: number; + incomingMaxAge: number | null; + get maxDatagramSize(): number; + outgoingHighWaterMark: number; + outgoingMaxAge: number | null; + push(data: Uint8Array): void; + readonly readable: ReadableStream; + setMaxDatagramSize(size: number): void; + readonly writable: WritableStream; +} + +export function install(options?: InstallOptions): boolean; + +export interface InstallOptions { + requireProtocol?: boolean; + versions?: Record; +} + +export function selectSubprotocol(offered: string | readonly string[] | null | undefined, options?: Pick): string | undefined; + +type SendStreamOptions = WebTransportSendStreamOptions & { + waitUntilAvailable?: boolean; +}; + +class Session implements WebTransport { + constructor(source: string | URL | WebSocketLike | WebSocketStreamLike, options?: SessionOptions); + static accept(socket: WebSocketLike | WebSocketStreamLike, options?: AcceptOptions): Session; + close(info?: { + closeCode?: number; + reason?: string; + }): void; + readonly closed: Promise; + get congestionControl(): WebTransportCongestionControl; + createBidirectionalStream(options?: SendStreamOptions): Promise; + createUnidirectionalStream(options?: SendStreamOptions): Promise>; + readonly datagrams: Datagrams; + getStats(): Promise<{ + datagrams: {}; + }>; + readonly incomingBidirectionalStreams: ReadableStream; + readonly incomingUnidirectionalStreams: ReadableStream>; + get protocol(): string; + readonly ready: Promise; + get reliability(): "reliable-only"; + setSendBufferSize(bytes: number): void; +} +export default Session; + +export class SessionError extends Error implements Pick { + constructor(message: string, options?: { + cause?: unknown; + }); + readonly source: "session"; + readonly streamErrorCode: null; +} + +export interface SessionOptions extends WebTransportOptions { + config?: Config; + protocols?: string[]; + requireProtocol?: boolean; + sendBufferSize?: number; + versions?: Record; +} + +export class StreamError extends Error implements Pick { + constructor(code: number, message?: string); + readonly source: "stream"; + readonly streamErrorCode: number; +} + +export type Version = WireFormat; + +export interface WebSocketLike { + binaryType: string; + readonly bufferedAmount: number; + close(code?: number, reason?: string): void; + readonly extensions: string; + onclose: ((ev: { + code?: number; + reason?: string; + }) => void) | null; + onerror: ((ev: unknown) => void) | null; + onmessage: ((ev: { + data: unknown; + }) => void) | null; + onopen: ((ev: unknown) => void) | null; + readonly protocol: string; + readonly readyState: number; + send(data: string | ArrayBufferLike | ArrayBufferView): void; + readonly url?: string; +} + +interface WebSocketStreamCloseEvent { + closeCode: number; + reason: string; +} + +interface WebSocketStreamCloseInfo { + closeCode?: number; + reason?: string; +} + +type WebSocketStreamData = Uint8Array | string; + +export interface WebSocketStreamLike { + close(closeInfo?: WebSocketStreamCloseInfo): void; + readonly closed: Promise; + readonly opened: Promise; + setHighWaterMark?(bytes: number): void; + readonly url: string; +} + +interface WebSocketStreamOpenEvent { + extensions: string; + protocol: string; + readable: ReadableStream; + writable: WritableStream; +} + +type WireFormat = "qmux-00" | "qmux-01" | "qmux-02"; + + +``` diff --git a/js/room/api/index.api.md b/js/room/api/index.api.md new file mode 100644 index 00000000000..5838295c502 --- /dev/null +++ b/js/room/api/index.api.md @@ -0,0 +1,250 @@ +## API Report File for "@moq/room" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { Broadcast } from '@moq/net'; +import * as Clock from '@moq/clock'; +import { Effect } from '@moq/signals'; +import { Getter } from '@moq/signals'; +import { GetterInit } from '@moq/signals'; +import * as Json from '@moq/json'; +import * as Moq from '@moq/net'; +import { Nano } from '@moq/clock'; +import { Path } from '@moq/net'; +import * as Publish from '@moq/publish'; +import { Readonlys } from '@moq/signals'; +import type { Root } from '@moq/hang/catalog'; +import { Signal } from '@moq/signals'; +import { Timed } from '@moq/net'; +import { Track } from '@moq/net'; +import * as Watch from '@moq/watch'; + +export function broadcastPath(identity: Path.Valid, kind: Kind): Path.Valid; + +declare namespace Chat { + export { + info, + TRACK_2 as TRACK, + PRIORITY_2 as PRIORITY, + HISTORY, + Event_2 as Event, + Publisher, + Subscriber + } +} + +export type Claims = { + root: string; + subscribe: string[]; + publish: string[]; +}; + +export function claims(room: string, identity: string): Claims; + +export { Clock } + +export function consume(broadcast: Watch.Broadcast): Consumed; + +type Consumed = { + user: Readonlys; + preview: Getter; + close: () => void; +}; + +type Event_2 = Json.Window.Event; + +export type ExtendedCatalog = Root & { + hang?: HangCatalog; +}; + +export type HangCatalog = { + user?: TrackRef; + preview?: TrackRef; + chat?: TrackRef; + location?: TrackRef; +}; + +const HISTORY: Nano; + +function info(): Pick; + +export function isKind(value: string): value is Kind; + +export const KIND: { + readonly camera: "camera"; + readonly screen: "screen"; +}; + +export type Kind = (typeof KIND)[keyof typeof KIND]; + +export function kindFromSegment(segment: string): Kind | undefined; + +export class Local { + constructor(props: LocalProps); + readonly camera: Publish.Broadcast; + readonly cameraCapture: Publish.Video.Capture; + readonly cameraEnabled: Signal; + readonly chatting: Signal; + close(): void; + readonly enabled: Signal; + readonly identity: Getter; + readonly microphone: Publish.Source.Microphone; + readonly microphoneEnabled: Signal; + get preview(): Getter; + readonly screen: Publish.Broadcast; + readonly screenCapture: Publish.Video.Capture; + readonly screenEnabled: Signal; + readonly share: Publish.Source.Screen; + readonly typing: Signal; + readonly user: ReturnType; + readonly webcam: Publish.Source.Camera; +} + +export interface LocalProps { + cameraEnabled?: GetterInit; + connection: Moq.Connection; + enabled?: GetterInit; + identity: GetterInit; + microphoneEnabled?: GetterInit; + screenEnabled?: GetterInit; + user?: UserProps; +} + +export class Member { + constructor(kind: Kind, path: Moq.Path.Valid, connection: Moq.Connection); + readonly audio: Watch.Audio.Decoder; + readonly broadcast: Watch.Broadcast; + readonly canvas: Signal; + close(): void; + readonly emitter: Watch.Audio.Emitter; + readonly kind: Kind; + readonly muted: Signal; + readonly path: Moq.Path.Valid; + readonly player: Watch.Player; + readonly preview: Getter; + readonly renderer: Watch.Video.Renderer; + readonly user: Readonlys; + readonly video: Watch.Video.Decoder; + readonly volume: Signal; +} + +export function parse(path: Path.Valid): Parsed | undefined; + +export type Parsed = { + identity: Path.Valid; + kind: Kind; +}; + +export type Preview = { + audio?: boolean; + video?: boolean; + screen?: boolean; + name?: string; + avatar?: string; + chat?: boolean; + typing?: boolean; +}; + +export const PRIORITY = 90; + +const PRIORITY_2 = 10; + +class Publisher { + constructor(track: Track.Producer); + static create(broadcast: Broadcast.Producer): Publisher; + expire(): void; + finish(): void; + send(text: string): void; +} + +export class Remote { + constructor(props: RemoteProps); + attach(kind: Kind, path: Moq.Path.Valid): void; + readonly camera: Getter; + close(): void; + detach(kind: Kind): void; + empty(): boolean; + readonly identity: Moq.Path.Valid; + readonly preview: Getter; + readonly screen: Getter; + readonly user: Readonlys; +} + +export interface RemoteProps { + connection: Moq.Connection; + identity: Moq.Path.Valid; +} + +export class Room { + constructor(props: RoomProps); + close(): void; + readonly connection: Moq.Connection; + readonly enabled: Getter; + readonly identity: Getter; + readonly prefix: Getter; + get remotes(): Getter>; +} + +export interface RoomProps { + connection: Moq.Connection; + enabled?: GetterInit; + identity?: GetterInit; + prefix?: GetterInit; +} + +export function serve(broadcast: Publish.Broadcast, user: UserInput, preview: Getter, effect: Effect): void; + +class Subscriber { + constructor(track: Track.Subscriber); + close(): void; + recv(): Promise | undefined>; + static subscribe(broadcast: Broadcast.Consumer): Subscriber; +} + +export const TRACK: { + readonly user: "hang/user.json"; + readonly preview: "hang/preview.json"; + readonly chat: "hang/chat.json"; + readonly location: "hang/location.json"; +}; + +const TRACK_2 = "chat"; + +type TrackRef = { + track: string; +}; + +export type User = { + id?: string; + name?: string; + avatar?: string; + color?: string; +}; + +export type UserFields = { + id: Signal; + name: Signal; + avatar: Signal; + color: Signal; +}; + +export function userFields(props?: UserProps): UserFields; + +type UserInput = { + id: Getter; + name: Getter; + avatar: Getter; + color: Getter; +}; + +export type UserProps = { + id?: string | Signal; + name?: string | Signal; + avatar?: string | Signal; + color?: string | Signal; +}; + + +``` diff --git a/js/signals/api/dom.api.md b/js/signals/api/dom.api.md new file mode 100644 index 00000000000..d600ee7c9be --- /dev/null +++ b/js/signals/api/dom.api.md @@ -0,0 +1,100 @@ +## API Report File for "@moq/signals" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { Nano } from '@moq/clock'; + +interface ArrayElement extends Array { +} + +class Computed implements Getter { + readonly [GETTER_BRAND] = true; + constructor(fn: (effect: Effect) => T); + changed(): Promise; + changed(fn: Subscriber): Dispose; + close(): void; + peek(): T | undefined; + subscribe(fn: Subscriber): Dispose; +} + +export function create(tagName: K, options?: CreateOptions, ...children: (HTMLElement | string)[]): HTMLElementTagNameMap[K]; + +export type CreateOptions = { + style?: Partial; + className?: string; + classList?: string[]; + id?: string; + dataset?: Record; + attributes?: Record; +} & Partial>; + +type Dispose = () => void; + +class Effect { + constructor(fn?: (effect: Effect) => void); + get abort(): AbortSignal; + animate(fn: (now: DOMHighResTimeStamp) => void): void; + cleanup(fn: Dispose): void; + close(): void; + get closed(): Promise; + computed(fn: (effect: Effect) => T): Computed; + event(target: HTMLElement, type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => void, options?: boolean | AddEventListenerOptions): void; + event(target: SVGElement, type: K, listener: (this: SVGElement, ev: SVGElementEventMap[K]) => void, options?: boolean | AddEventListenerOptions): void; + event(target: Document, type: K, listener: (this: Document, ev: DocumentEventMap[K]) => void, options?: boolean | AddEventListenerOptions): void; + event(target: Window, type: K, listener: (this: Window, ev: WindowEventMap[K]) => void, options?: boolean | AddEventListenerOptions): void; + event(target: WebSocket, type: K, listener: (this: WebSocket, ev: WebSocketEventMap[K]) => void, options?: boolean | AddEventListenerOptions): void; + event(target: XMLHttpRequest, type: K, listener: (this: XMLHttpRequest, ev: XMLHttpRequestEventMap[K]) => void, options?: boolean | AddEventListenerOptions): void; + event(target: MediaQueryList, type: K, listener: (this: MediaQueryList, ev: MediaQueryListEventMap[K]) => void, options?: boolean | AddEventListenerOptions): void; + event(target: Animation, type: K, listener: (this: Animation, ev: AnimationEventMap[K]) => void, options?: boolean | AddEventListenerOptions): void; + event(target: EventSource, type: K, listener: (this: EventSource, ev: EventSourceEventMap[K]) => void, options?: boolean | AddEventListenerOptions): void; + event(target: EventTarget, type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + get(signal: Getter): T; + getAll[]>(signals: [...S]): { + [K in keyof S]: Truthy>; + } | undefined; + interval(fn: () => void, period: Nano): void; + proxy(dst: Setter, src: Getter): void; + race(...values: T): Promise | undefined>; + run(fn: (effect: Effect) => void): Dispose; + set>(signal: S, value: SetterType, ...args: undefined extends SetterType ? [cleanup?: SetterType] : [cleanup: SetterType]): void; + spawn(fn: () => Promise): void; + subscribe(signal: Getter, fn: (value: T) => void): void; + timeout(fn: (effect: Effect) => void, duration: Nano): void; + timer(fn: () => void, duration: Nano): void; +} + +type Element_2 = Node | ArrayElement | (string & {}) | number | boolean | null | undefined; +export { Element_2 as Element } + +type Falsy = false | 0 | "" | null | undefined; + +interface Getter { + changed(): Promise; + changed(fn: Subscriber): Dispose; + peek(): T; + subscribe(fn: Subscriber): Dispose; +} + +const GETTER_BRAND: unique symbol; + +type GetterType = G extends Getter ? T : never; + +export function render(effect: Effect, parent: Node, element: Element_2 | ((effect: Effect) => Element_2)): void; + +export function setClass(effect: Effect, element: HTMLElement, ...classNames: string[]): void; + +interface Setter { + set(value: T): void; + update(fn: (prev: T) => T): void; +} + +type SetterType = S extends Setter ? T : never; + +type Subscriber = (value: T) => void; + +type Truthy = Exclude; + + +``` diff --git a/js/signals/api/index.api.md b/js/signals/api/index.api.md new file mode 100644 index 00000000000..d850becfc4d --- /dev/null +++ b/js/signals/api/index.api.md @@ -0,0 +1,143 @@ +## API Report File for "@moq/signals" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { Nano } from '@moq/clock'; + +export class Computed implements Getter { + readonly [GETTER_BRAND] = true; + constructor(fn: (effect: Effect) => T); + changed(): Promise; + changed(fn: Subscriber): Dispose; + close(): void; + peek(): T | undefined; + subscribe(fn: Subscriber): Dispose; +} + +export class Derived[], T> implements Getter { + readonly [GETTER_BRAND] = true; + constructor(sources: S, fn: (...values: GetterValues) => T); + changed(): Promise; + changed(fn: Subscriber): Dispose; + peek(): T; + subscribe(fn: Subscriber): Dispose; +} + +export type Dispose = () => void; + +export class Effect { + constructor(fn?: (effect: Effect) => void); + get abort(): AbortSignal; + animate(fn: (now: DOMHighResTimeStamp) => void): void; + cleanup(fn: Dispose): void; + close(): void; + get closed(): Promise; + computed(fn: (effect: Effect) => T): Computed; + event(target: HTMLElement, type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => void, options?: boolean | AddEventListenerOptions): void; + event(target: SVGElement, type: K, listener: (this: SVGElement, ev: SVGElementEventMap[K]) => void, options?: boolean | AddEventListenerOptions): void; + event(target: Document, type: K, listener: (this: Document, ev: DocumentEventMap[K]) => void, options?: boolean | AddEventListenerOptions): void; + event(target: Window, type: K, listener: (this: Window, ev: WindowEventMap[K]) => void, options?: boolean | AddEventListenerOptions): void; + event(target: WebSocket, type: K, listener: (this: WebSocket, ev: WebSocketEventMap[K]) => void, options?: boolean | AddEventListenerOptions): void; + event(target: XMLHttpRequest, type: K, listener: (this: XMLHttpRequest, ev: XMLHttpRequestEventMap[K]) => void, options?: boolean | AddEventListenerOptions): void; + event(target: MediaQueryList, type: K, listener: (this: MediaQueryList, ev: MediaQueryListEventMap[K]) => void, options?: boolean | AddEventListenerOptions): void; + event(target: Animation, type: K, listener: (this: Animation, ev: AnimationEventMap[K]) => void, options?: boolean | AddEventListenerOptions): void; + event(target: EventSource, type: K, listener: (this: EventSource, ev: EventSourceEventMap[K]) => void, options?: boolean | AddEventListenerOptions): void; + event(target: EventTarget, type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + get(signal: Getter): T; + getAll[]>(signals: [...S]): { + [K in keyof S]: Truthy>; + } | undefined; + interval(fn: () => void, period: Nano): void; + proxy(dst: Setter, src: Getter): void; + race(...values: T): Promise | undefined>; + run(fn: (effect: Effect) => void): Dispose; + set>(signal: S, value: SetterType, ...args: undefined extends SetterType ? [cleanup?: SetterType] : [cleanup: SetterType]): void; + spawn(fn: () => Promise): void; + subscribe(signal: Getter, fn: (value: T) => void): void; + timeout(fn: (effect: Effect) => void, duration: Nano): void; + timer(fn: () => void, duration: Nano): void; +} + +type Falsy = false | 0 | "" | null | undefined; + +export interface GetPromise extends Getter, PromiseLike { +} + +export interface Getter { + changed(): Promise; + changed(fn: Subscriber): Dispose; + peek(): T; + subscribe(fn: Subscriber): Dispose; +} + +export function getter(value: GetterInit): Getter; + +const GETTER_BRAND: unique symbol; + +export type GetterInit = T | Getter; + +export type GetterType = G extends Getter ? T : never; + +export type GetterValues[]> = { + [K in keyof S]: GetterType; +}; + +export type Inputs = { + [K in keyof I]?: GetterInit>; +}; + +export class Once implements GetPromise { + readonly [GETTER_BRAND] = true; + changed(): Promise; + changed(fn: (value: T | undefined) => void): Dispose; + peek(): T | undefined; + set(value: T): void; + subscribe(fn: (value: T | undefined) => void): Dispose; + then(onFulfilled?: ((value: T) => R1 | PromiseLike) | null, onRejected?: ((reason: unknown) => R2 | PromiseLike) | null): PromiseLike; +} + +export function race(values: T): Promise>; + +export type Readonlys = { + readonly [K in keyof T]: Getter>; +}; + +export function readonlys(signals: T): Readonlys; + +export interface Setter { + set(value: T): void; + update(fn: (prev: T) => T): void; +} + +type SetterType = S extends Setter ? T : never; + +export class Signal implements Getter, Setter { + readonly [GETTER_BRAND] = true; + readonly [SIGNAL_BRAND] = true; + constructor(value: T); + changed(): Promise; + changed(fn: Subscriber): Dispose; + static from(value: T | Signal): Signal; + mutate(fn: (value: T) => R, notify?: boolean): R; + peek(): T; + static race(...sigs: { + [K in keyof T]: Getter; + }): GetPromise>; + set(value: T, notify?: boolean): void; + subscribe(fn: Subscriber): Dispose; + update(fn: (prev: T) => T, notify?: boolean): void; + watch(fn: Subscriber): Dispose; +} + +const SIGNAL_BRAND: unique symbol; + +export type SignalMap = Record>; + +type Subscriber = (value: T) => void; + +type Truthy = Exclude; + + +``` diff --git a/js/signals/api/react.api.md b/js/signals/api/react.api.md new file mode 100644 index 00000000000..701b56f31dd --- /dev/null +++ b/js/signals/api/react.api.md @@ -0,0 +1,53 @@ +## API Report File for "@moq/signals" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +type Dispose = () => void; + +interface GetPromise extends Getter, PromiseLike { +} + +interface Getter { + changed(): Promise; + changed(fn: Subscriber): Dispose; + peek(): T; + subscribe(fn: Subscriber): Dispose; +} + +const GETTER_BRAND: unique symbol; + +interface Setter { + set(value: T): void; + update(fn: (prev: T) => T): void; +} + +class Signal implements Getter, Setter { + readonly [GETTER_BRAND] = true; + readonly [SIGNAL_BRAND] = true; + constructor(value: T); + changed(): Promise; + changed(fn: Subscriber): Dispose; + static from(value: T | Signal): Signal; + mutate(fn: (value: T) => R, notify?: boolean): R; + peek(): T; + static race(...sigs: { + [K in keyof T]: Getter; + }): GetPromise>; + set(value: T, notify?: boolean): void; + subscribe(fn: Subscriber): Dispose; + update(fn: (prev: T) => T, notify?: boolean): void; + watch(fn: Subscriber): Dispose; +} + +const SIGNAL_BRAND: unique symbol; + +type Subscriber = (value: T) => void; + +export function useSignal(signal: Signal): [T, (value: T | ((prev: T) => T)) => void]; + +export function useValue(signal: Getter): T; + + +``` diff --git a/js/signals/api/solid.api.md b/js/signals/api/solid.api.md new file mode 100644 index 00000000000..9b9033213df --- /dev/null +++ b/js/signals/api/solid.api.md @@ -0,0 +1,59 @@ +## API Report File for "@moq/signals" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { Accessor } from 'solid-js'; +import { Setter as Setter_2 } from 'solid-js'; +import { Signal as Signal_2 } from 'solid-js'; + +export function createAccessor(signal: Getter): Accessor; + +export function createPair(signal: Signal): Signal_2; + +export function createSetter(signal: Signal): Setter_2; + +type Dispose = () => void; + +interface GetPromise extends Getter, PromiseLike { +} + +interface Getter { + changed(): Promise; + changed(fn: Subscriber): Dispose; + peek(): T; + subscribe(fn: Subscriber): Dispose; +} + +const GETTER_BRAND: unique symbol; + +interface Setter { + set(value: T): void; + update(fn: (prev: T) => T): void; +} + +class Signal implements Getter, Setter { + readonly [GETTER_BRAND] = true; + readonly [SIGNAL_BRAND] = true; + constructor(value: T); + changed(): Promise; + changed(fn: Subscriber): Dispose; + static from(value: T | Signal): Signal; + mutate(fn: (value: T) => R, notify?: boolean): R; + peek(): T; + static race(...sigs: { + [K in keyof T]: Getter; + }): GetPromise>; + set(value: T, notify?: boolean): void; + subscribe(fn: Subscriber): Dispose; + update(fn: (prev: T) => T, notify?: boolean): void; + watch(fn: Subscriber): Dispose; +} + +const SIGNAL_BRAND: unique symbol; + +type Subscriber = (value: T) => void; + + +``` diff --git a/js/ui/api/index.api.md b/js/ui/api/index.api.md new file mode 100644 index 00000000000..228206c9e39 --- /dev/null +++ b/js/ui/api/index.api.md @@ -0,0 +1,63 @@ +## API Report File for "@moq/ui" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import type { Effect } from '@moq/signals'; +import type { Signal } from '@moq/signals'; + +export function controlButton(svg: string, label: string): HTMLButtonElement; + +export interface Graph { + el: HTMLElement; + push(value: number | undefined): void; +} + +export function graph(parent: Effect, title: string, opts?: GraphOptions): Graph; + +export interface GraphOptions { + color?: string; + format?: (v: number) => string; + max?: number; + samples?: number; +} + +export function icon(svg: string): HTMLElement; + +export type Level = "full" | "partial" | "none"; + +const OBSERVED: readonly ["show", "details"]; + +type Observed = (typeof OBSERVED)[number]; + +interface Report_2 { + rows: [group: string, feature: string, status: Status][]; + summary: Level; +} +export { Report_2 as Report } + +export function settingsButton(parent: Effect, panel: Signal): HTMLButtonElement; + +export type Show = "always" | "warning" | "error" | "never"; + +export type Status = boolean | Level | { + hardware?: boolean; + software: boolean; +} | undefined; + +export abstract class Support extends HTMLElement { + constructor(); + attributeChangedCallback(name: Observed, _oldValue: string | null, newValue: string | null): void; + connectedCallback(): void; + get details(): boolean; + set details(details: boolean); + protected abstract detect(): Promise; + disconnectedCallback(): void; + static observedAttributes: readonly ["show", "details"]; + get show(): Show; + set show(show: Show); +} + + +``` diff --git a/js/video/api/index.api.md b/js/video/api/index.api.md new file mode 100644 index 00000000000..d452f5eb3c6 --- /dev/null +++ b/js/video/api/index.api.md @@ -0,0 +1,52 @@ +## API Report File for "@moq/video" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { Getter } from '@moq/signals'; +import { Inputs } from '@moq/signals'; +import { Readonlys } from '@moq/signals'; +import { Signal } from '@moq/signals'; + +export type Backend = "auto" | "webgpu" | "2d"; + +export type Canvas = HTMLCanvasElement | OffscreenCanvas; + +export type Dimensions = { + width: number; + height: number; +}; + +export type Presentation = { + rotation?: number; + flip?: boolean; + interlaced?: boolean; +}; + +export class Renderer { + constructor(props?: RendererProps); + close(): void; + readonly in: Readonlys; + readonly out: Readonlys; +} + +export type RendererInput = { + canvas: Getter; + frame: Getter; + display: Getter; + presentation: Getter; + backend: Getter; +}; + +export type RendererOutput = { + frame: Signal; + error: Signal; +}; + +export type RendererProps = Inputs; + +export function rotateVideoDimensions(dimensions: Dimensions, rotation?: number): Dimensions; + + +``` diff --git a/js/watch/api/element.api.md b/js/watch/api/element.api.md new file mode 100644 index 00000000000..a10db978ccb --- /dev/null +++ b/js/watch/api/element.api.md @@ -0,0 +1,490 @@ +## API Report File for "@moq/watch" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { Backend } from '@moq/video'; +import * as Catalog from '@moq/hang/catalog'; +import * as Container from '@moq/hang/container'; +import { Effect } from '@moq/signals'; +import { Getter } from '@moq/signals'; +import { Inputs } from '@moq/signals'; +import { Milli } from '@moq/clock'; +import * as Moq from '@moq/net'; +import { Readonlys } from '@moq/signals'; +import { Signal } from '@moq/signals'; +import * as Video_2 from '@moq/video'; + +type Arrival = { + kind: "frame"; + timestamp: Milli; + arrival: Milli; + late: boolean; +} +/** +* Media after an earlier frame never reached the decoder: a latency skip or a hole. The span is +* an upper bound, as on the container read's gap. +*/ +| { + kind: "gap"; + timestamp: Milli; + duration: Milli; +}; + +class Arrivals implements AsyncIterable { + [Symbol.asyncIterator](): AsyncIterator; + close(): void; + next(): Promise; +} + +declare namespace Audio_2 { + export { + DecoderInput_2 as DecoderInput, + DecoderProps_2 as DecoderProps, + Stats_2 as Stats, + Decoder_2 as Decoder, + EmitterInput, + EmitterProps, + Emitter, + Target_2 as Target, + Supported_2 as Supported, + SourceInput_2 as SourceInput, + Source_2 as Source + } +} + +class Broadcast { + constructor(props?: Inputs); + close(): void; + readonly in: Readonlys; + readonly out: Readonlys; +} + +type BroadcastInput = { + origin: Getter; + enabled: Getter; + name: Getter; + announced: Getter; + catalogFormat: Getter; + catalog: Getter; +}; + +type BroadcastOutput = { + status: Signal; + active: Signal; + error: Signal; + catalog: Signal; +}; + +const CATALOG_FORMATS: readonly ["hang", "msf", "hangz", "manual"]; + +type CatalogFormat = (typeof CATALOG_FORMATS)[number]; + +class Decoder { + constructor(props: DecoderProps); + close(): void; + readonly in: Readonlys; + readonly out: Readonlys; + readonly source: Source; + static supported: typeof supported; + readonly sync: Sync; +} + +class Decoder_2 { + constructor(props: DecoderProps_2); + arrivals(): Arrivals; + close(): void; + readonly in: Readonlys; + readonly out: Readonlys; + reset(): void; + readonly source: Source_2; + static supported: typeof supported_2; + readonly sync: Sync; +} + +type DecoderInput = { + enabled: Getter; +}; + +type DecoderInput_2 = { + enabled: Getter; +}; + +type DecoderOutput = { + error: Signal; + frame: Signal; + interlaced: Signal; + timestamp: Signal; + display: Signal<{ + width: number; + height: number; + } | undefined>; + stalled: Signal; + stats: Signal; + jitter: Signal; + buffered: Signal; +}; + +type DecoderOutput_2 = { + error: Signal; + context: Signal; + root: Signal; + sampleRate: Signal; + stats: Signal; + timestamp: Signal; + stalled: Signal; + buffered: Signal; +}; + +type DecoderProps = Inputs & { + source: Source; + sync: Sync; +}; + +type DecoderProps_2 = Inputs & { + source: Source_2; + sync: Sync; +}; + +type Delay = "instant" | "auto" | Milli; + +class Emitter { + constructor(props: EmitterProps); + close(): void; + readonly in: Readonlys; + readonly out: Readonlys; + readonly source: Decoder_2; +} + +type EmitterInput = { + volume: Getter; + muted: Getter; + paused: Getter; +}; + +type EmitterOutput = { + enabled: Signal; +}; + +type EmitterProps = Inputs & { + source: Decoder_2; +}; + +type Kind = "video" | "audio" | "text"; + +class MoqWatch extends HTMLElement { + constructor(); + get announced(): boolean; + set announced(value: boolean); + attributeChangedCallback(name: Observed, oldValue: string | null, newValue: string | null): void; + audio: Audio_2.Decoder; + get backend(): Video.Backend; + set backend(value: Video.Backend); + broadcast: Broadcast; + get buffer(): Milli; + set buffer(value: Milli); + get captions(): string | undefined; + set captions(value: string | undefined); + get catalog(): Catalog.Root | undefined; + set catalog(value: Catalog.Root | undefined); + get catalogFormat(): CatalogFormat | undefined; + set catalogFormat(value: CatalogFormat | undefined); + connectedCallback(): void; + connection: Moq.Connection; + readonly controls: { + paused: Signal; + delay: Signal; + buffer: Signal; + video: { + target: Signal; + visible: Signal; + backend: Signal; + }; + audio: { + target: Signal; + volume: Signal; + muted: Signal; + }; + text: { + target: Signal; + }; + }; + get delay(): Delay; + set delay(value: Delay); + disconnectedCallback(): void; + emitter: Audio_2.Emitter; + get muted(): boolean; + set muted(value: boolean); + get name(): Moq.Path.Valid; + set name(value: string | Moq.Path.Valid); + static observedAttributes: readonly ["url", "versions", "name", "paused", "volume", "muted", "visible", "backend", "announced", "delay", "buffer", "catalog-format", "captions"]; + get paused(): boolean; + set paused(value: boolean); + readonly player: Player; + renderer: Video.Renderer; + reset(): void; + readonly signals: Effect; + sync: Sync; + text: Text_2.Source; + textRenderer: Text_2.Renderer; + get url(): URL | undefined; + set url(value: string | URL | undefined); + get versions(): readonly string[] | undefined; + set versions(value: readonly string[] | undefined); + video: Video.Decoder; + get visible(): Video.Visible; + set visible(value: Video.Visible); + get volume(): number; + set volume(value: number); +} +export default MoqWatch; + +const OBSERVED: readonly ["url", "versions", "name", "paused", "volume", "muted", "visible", "backend", "announced", "delay", "buffer", "catalog-format", "captions"]; + +type Observed = (typeof OBSERVED)[number]; + +export function parseCatalogFormat(value: string | null): CatalogFormat | undefined; + +class Player { + constructor(props?: PlayerProps); + readonly audio: Audio_2.Decoder; + readonly broadcast: Broadcast; + close(): void; + readonly emitter: Audio_2.Emitter; + readonly in: Readonlys> & { + readonly [K in Kind]: Readonlys; + }; + readonly renderer: Video.Renderer; + reset(): void; + readonly sync: Sync; + readonly text: Text_2.Source; + readonly textRenderer: Text_2.Renderer; + readonly video: Video.Decoder; +} + +type PlayerInput = { + origin: Getter; + name: Getter; + enabled: Getter; + announced: Getter; + catalogFormat: Getter; + catalog: Getter; + probe: Getter; + paused: Getter; + delay: Getter; + buffer: Getter; + video: { + target: Getter; + canvas: Getter; + visible: Getter; + backend: Getter; + }; + audio: { + target: Getter; + volume: Getter; + muted: Getter; + }; + text: { + target: Getter; + container: Getter; + }; +}; + +type PlayerProps = Inputs> & { + [K in Kind]?: Inputs; +}; + +function renderable(config: Catalog.TextConfig): boolean; + +class Renderer { + constructor(props: RendererProps); + close(): void; + readonly decoder: Decoder; + readonly in: Readonlys; + readonly out: Readonlys<{ + frame: Getter; + timestamp: Getter; + visible: Getter; + error: Getter; + }>; +} + +class Renderer_2 { + constructor(props: RendererProps_2); + close(): void; + readonly in: Readonlys; + readonly source: Source_3; + readonly sync: Sync; +} + +type RendererInput = { + canvas: Getter; + visible: Getter; + backend: Getter; +}; + +type RendererInput_2 = { + container: Getter; + enabled: Getter; +}; + +type RendererProps = Inputs & { + decoder: Decoder; +}; + +type RendererProps_2 = Inputs & { + source: Source_3; + sync: Sync; +}; + +class Source { + constructor(props?: Inputs); + close(): void; + readonly in: Readonlys; + readonly out: Readonlys; +} + +class Source_2 { + constructor(props?: Inputs); + close(): void; + readonly in: Readonlys; + readonly out: Readonlys; +} + +class Source_3 { + constructor(props?: Inputs); + close(): void; + readonly in: Readonlys; + readonly out: Readonlys; +} + +type SourceInput = { + broadcast: Getter; + target: Getter; + supported: Getter; + probe: Getter; +}; + +type SourceInput_2 = { + broadcast: Getter; + target: Getter; + supported: Getter; +}; + +type SourceInput_3 = { + broadcast: Getter; + target: Getter; +}; + +type SourceOutput = { + catalog: Signal; + available: Signal>; + error: Signal; + track: Signal; + config: Signal; +}; + +type SourceOutput_2 = { + catalog: Signal; + available: Signal>; + track: Signal; + config: Signal; + jitter: Signal; +}; + +type SourceOutput_3 = { + catalog: Signal; + available: Signal>; + track: Signal; + config: Signal; +}; + +interface Stats { + bytesReceived: number; + frameCount: number; +} + +interface Stats_2 { + bytesReceived: number; + underruns: number; +} + +type Status = "offline" | "loading" | "live" | "error" | "unsupported"; + +type Supported = (config: Catalog.VideoConfig) => Promise; + +function supported(config: Catalog.VideoConfig): Promise; + +type Supported_2 = (config: Catalog.AudioConfig) => Promise; + +function supported_2(config: Catalog.AudioConfig): Promise; + +class Sync { + constructor(props?: Inputs); + close(): void; + readonly in: Readonlys; + now(): Milli | undefined; + readonly out: Readonlys; + reset(): void; +} + +type SyncInput = { + delay: Getter; + buffer: Getter; +}; + +type SyncOutput = { + instant: Signal; + reference: Signal; + delay: Signal; + timestamp: Signal; + buffered: Signal; + maxDelay: Signal; +}; + +type Target = { + name?: string; + pixels?: number; + width?: number; + height?: number; + bitrate?: number; +}; + +type Target_2 = { + name?: string; +}; + +declare namespace Text_2 { + export { + RendererInput_2 as RendererInput, + RendererProps_2 as RendererProps, + Renderer_2 as Renderer, + renderable, + SourceInput_3 as SourceInput, + Source_3 as Source + } +} + +declare namespace Video { + export { + Backend, + DecoderInput, + DecoderProps, + Stats, + Decoder, + Visible, + RendererInput, + RendererProps, + Renderer, + Supported, + Target, + SourceInput, + Source + } +} + +type Visible = "never" | "always" | (string & {}); + + +``` diff --git a/js/watch/api/index.api.md b/js/watch/api/index.api.md new file mode 100644 index 00000000000..e56b2861b01 --- /dev/null +++ b/js/watch/api/index.api.md @@ -0,0 +1,480 @@ +## API Report File for "@moq/watch" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { Backend } from '@moq/video'; +import { BufferedRange } from '@moq/hang/container'; +import { BufferedRanges } from '@moq/hang/container'; +import * as Catalog from '@moq/hang/catalog'; +import * as Clock from '@moq/clock'; +import * as Container from '@moq/hang/container'; +import { Getter } from '@moq/signals'; +import * as Hang from '@moq/hang'; +import { Inputs } from '@moq/signals'; +import { Milli } from '@moq/clock'; +import * as Net from '@moq/net'; +import { Readonlys } from '@moq/signals'; +import { Signal } from '@moq/signals'; +import * as Signals from '@moq/signals'; +import * as Video_2 from '@moq/video'; + +export type Arrival = { + kind: "frame"; + timestamp: Milli; + arrival: Milli; + late: boolean; +} +/** +* Media after an earlier frame never reached the decoder: a latency skip or a hole. The span is +* an upper bound, as on the container read's gap. +*/ +| { + kind: "gap"; + timestamp: Milli; + duration: Milli; +}; + +export class Arrivals implements AsyncIterable { + [Symbol.asyncIterator](): AsyncIterator; + close(): void; + next(): Promise; +} + +export function assets(url: string | URL): void; + +declare namespace Audio_2 { + export { + DecoderInput, + DecoderProps, + Stats, + Decoder, + EmitterInput, + EmitterProps, + Emitter, + Target, + Supported, + SourceInput, + Source + } +} + +declare namespace Audio_3 { + export { + DecoderInput, + DecoderProps, + Stats, + Decoder, + EmitterInput, + EmitterProps, + Emitter, + Target, + Supported, + SourceInput, + Source + } +} + +export class Broadcast { + constructor(props?: Inputs); + close(): void; + readonly in: Readonlys; + readonly out: Readonlys; +} + +export type BroadcastInput = { + origin: Getter; + enabled: Getter; + name: Getter; + announced: Getter; + catalogFormat: Getter; + catalog: Getter; +}; + +type BroadcastOutput = { + status: Signal; + active: Signal; + error: Signal; + catalog: Signal; +}; + +export { BufferedRange } + +export { BufferedRanges } + +export const CATALOG_FORMATS: readonly ["hang", "msf", "hangz", "manual"]; + +export type CatalogFormat = (typeof CATALOG_FORMATS)[number]; + +export { Clock } + +class Decoder { + constructor(props: DecoderProps); + arrivals(): Arrivals; + close(): void; + readonly in: Readonlys; + readonly out: Readonlys; + reset(): void; + readonly source: Source; + static supported: typeof supported; + readonly sync: Sync; +} + +class Decoder_2 { + constructor(props: DecoderProps_2); + close(): void; + readonly in: Readonlys; + readonly out: Readonlys; + readonly source: Source_3; + static supported: typeof supported_2; + readonly sync: Sync; +} + +type DecoderInput = { + enabled: Getter; +}; + +type DecoderInput_2 = { + enabled: Getter; +}; + +type DecoderOutput = { + error: Signal; + context: Signal; + root: Signal; + sampleRate: Signal; + stats: Signal; + timestamp: Signal; + stalled: Signal; + buffered: Signal; +}; + +type DecoderOutput_2 = { + error: Signal; + frame: Signal; + interlaced: Signal; + timestamp: Signal; + display: Signal<{ + width: number; + height: number; + } | undefined>; + stalled: Signal; + stats: Signal; + jitter: Signal; + buffered: Signal; +}; + +type DecoderProps = Inputs & { + source: Source; + sync: Sync; +}; + +type DecoderProps_2 = Inputs & { + source: Source_3; + sync: Sync; +}; + +export type Delay = "instant" | "auto" | Milli; + +class Emitter { + constructor(props: EmitterProps); + close(): void; + readonly in: Readonlys; + readonly out: Readonlys; + readonly source: Decoder; +} + +type EmitterInput = { + volume: Getter; + muted: Getter; + paused: Getter; +}; + +type EmitterOutput = { + enabled: Signal; +}; + +type EmitterProps = Inputs & { + source: Decoder; +}; + +export { Hang } + +type Kind = "video" | "audio" | "text"; + +export { Net } + +export class Player { + constructor(props?: PlayerProps); + readonly audio: Audio_3.Decoder; + readonly broadcast: Broadcast; + close(): void; + readonly emitter: Audio_3.Emitter; + readonly in: Readonlys> & { + readonly [K in Kind]: Readonlys; + }; + readonly renderer: Video_3.Renderer; + reset(): void; + readonly sync: Sync; + readonly text: Text_3.Source; + readonly textRenderer: Text_3.Renderer; + readonly video: Video_3.Decoder; +} + +export type PlayerInput = { + origin: Getter; + name: Getter; + enabled: Getter; + announced: Getter; + catalogFormat: Getter; + catalog: Getter; + probe: Getter; + paused: Getter; + delay: Getter; + buffer: Getter; + video: { + target: Getter; + canvas: Getter; + visible: Getter; + backend: Getter; + }; + audio: { + target: Getter; + volume: Getter; + muted: Getter; + }; + text: { + target: Getter; + container: Getter; + }; +}; + +export type PlayerProps = Inputs> & { + [K in Kind]?: Inputs; +}; + +function renderable(config: Catalog.TextConfig): boolean; + +class Renderer { + constructor(props: RendererProps); + close(): void; + readonly in: Readonlys; + readonly source: Source_2; + readonly sync: Sync; +} + +class Renderer_2 { + constructor(props: RendererProps_2); + close(): void; + readonly decoder: Decoder_2; + readonly in: Readonlys; + readonly out: Readonlys<{ + frame: Getter; + timestamp: Getter; + visible: Getter; + error: Getter; + }>; +} + +type RendererInput = { + container: Getter; + enabled: Getter; +}; + +type RendererInput_2 = { + canvas: Getter; + visible: Getter; + backend: Getter; +}; + +type RendererProps = Inputs & { + source: Source_2; + sync: Sync; +}; + +type RendererProps_2 = Inputs & { + decoder: Decoder_2; +}; + +export { Signals } + +class Source { + constructor(props?: Inputs); + close(): void; + readonly in: Readonlys; + readonly out: Readonlys; +} + +class Source_2 { + constructor(props?: Inputs); + close(): void; + readonly in: Readonlys; + readonly out: Readonlys; +} + +class Source_3 { + constructor(props?: Inputs); + close(): void; + readonly in: Readonlys; + readonly out: Readonlys; +} + +type SourceInput = { + broadcast: Getter; + target: Getter; + supported: Getter; +}; + +type SourceInput_2 = { + broadcast: Getter; + target: Getter; +}; + +type SourceInput_3 = { + broadcast: Getter; + target: Getter; + supported: Getter; + probe: Getter; +}; + +type SourceOutput = { + catalog: Signal; + available: Signal>; + track: Signal; + config: Signal; + jitter: Signal; +}; + +type SourceOutput_2 = { + catalog: Signal; + available: Signal>; + track: Signal; + config: Signal; +}; + +type SourceOutput_3 = { + catalog: Signal; + available: Signal>; + error: Signal; + track: Signal; + config: Signal; +}; + +interface Stats { + bytesReceived: number; + underruns: number; +} + +interface Stats_2 { + bytesReceived: number; + frameCount: number; +} + +type Status = "offline" | "loading" | "live" | "error" | "unsupported"; + +type Supported = (config: Catalog.AudioConfig) => Promise; + +function supported(config: Catalog.AudioConfig): Promise; + +type Supported_2 = (config: Catalog.VideoConfig) => Promise; + +function supported_2(config: Catalog.VideoConfig): Promise; + +export class Sync { + constructor(props?: Inputs); + close(): void; + readonly in: Readonlys; + now(): Milli | undefined; + readonly out: Readonlys; + reset(): void; +} + +export type SyncInput = { + delay: Getter; + buffer: Getter; +}; + +type SyncOutput = { + instant: Signal; + reference: Signal; + delay: Signal; + timestamp: Signal; + buffered: Signal; + maxDelay: Signal; +}; + +type Target = { + name?: string; +}; + +type Target_2 = { + name?: string; + pixels?: number; + width?: number; + height?: number; + bitrate?: number; +}; + +declare namespace Text_2 { + export { + RendererInput, + RendererProps, + Renderer, + renderable, + SourceInput_2 as SourceInput, + Source_2 as Source + } +} + +declare namespace Text_3 { + export { + RendererInput, + RendererProps, + Renderer, + renderable, + SourceInput_2 as SourceInput, + Source_2 as Source + } +} + +declare namespace Video { + export { + Backend, + DecoderInput_2 as DecoderInput, + DecoderProps_2 as DecoderProps, + Stats_2 as Stats, + Decoder_2 as Decoder, + Visible, + RendererInput_2 as RendererInput, + RendererProps_2 as RendererProps, + Renderer_2 as Renderer, + Supported_2 as Supported, + Target_2 as Target, + SourceInput_3 as SourceInput, + Source_3 as Source + } +} + +declare namespace Video_3 { + export { + Backend, + DecoderInput_2 as DecoderInput, + DecoderProps_2 as DecoderProps, + Stats_2 as Stats, + Decoder_2 as Decoder, + Visible, + RendererInput_2 as RendererInput, + RendererProps_2 as RendererProps, + Renderer_2 as Renderer, + Supported_2 as Supported, + Target_2 as Target, + SourceInput_3 as SourceInput, + Source_3 as Source + } +} + +type Visible = "never" | "always" | (string & {}); + + +``` diff --git a/js/watch/api/support-element.api.md b/js/watch/api/support-element.api.md new file mode 100644 index 00000000000..a9d8b3df7b7 --- /dev/null +++ b/js/watch/api/support-element.api.md @@ -0,0 +1,19 @@ +## API Report File for "@moq/watch" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { Report as Report_2 } from '@moq/ui'; +import { Show } from '@moq/ui'; +import { Support } from '@moq/ui'; + +class MoqWatchSupport extends Support { + protected detect(): Promise; +} +export default MoqWatchSupport; + +export { Show } + + +``` diff --git a/js/watch/api/support.api.md b/js/watch/api/support.api.md new file mode 100644 index 00000000000..44752b7d909 --- /dev/null +++ b/js/watch/api/support.api.md @@ -0,0 +1,43 @@ +## API Report File for "@moq/watch" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +type Audio_2 = { + aac: Level; + opus: Level; +}; +export { Audio_2 as Audio } + +export type Codec = { + hardware?: boolean; + software: boolean; +}; + +export type Full = { + webtransport: Level; + audio: { + decoding: Audio_2; + render: boolean; + }; + video: { + decoding: Video | undefined; + render: boolean; + }; +}; + +export function isSupported(): Promise; + +export type Level = "full" | "partial" | "none"; + +export type Video = { + h264: Codec; + h265: Codec; + vp8: Codec; + vp9: Codec; + av1: Codec; +}; + + +``` diff --git a/js/watch/api/ui.api.md b/js/watch/api/ui.api.md new file mode 100644 index 00000000000..b98b4dab9e2 --- /dev/null +++ b/js/watch/api/ui.api.md @@ -0,0 +1,15 @@ +## API Report File for "@moq/watch" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +class MoqWatchUi extends HTMLElement { + constructor(); + connectedCallback(): void; + disconnectedCallback(): void; +} +export default MoqWatchUi; + + +``` diff --git a/justfile b/justfile index e7c51037ea6..42a7e29008f 100644 --- a/justfile +++ b/justfile @@ -114,6 +114,12 @@ ci $BASE="": gate: just ci --all +# Diff every published API against its last release: `just api-diff [--deny] [rust|js|ffi]...`. +# `--deny` fails on any break, as backports into `release` must. +[positional-arguments] +api-diff *args: + sh/api-diff/run.sh "$@" + # Report what CI selects before installing the dev shell or build caches. ci-select $BASE="": sh/dispatch.sh ci "$BASE" --query diff --git a/package.json b/package.json index 83ed3dcb927..7a43fd98ed2 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "devDependencies": { "@babel/parser": "^8.0.7", "@biomejs/biome": "^2.5.15", + "@microsoft/api-extractor": "7.59.4", "concurrently": "^10.0.6", "markdown-extensions": "^2.0.0", "publint": "^0.3.25", diff --git a/quest/m1/README.md b/quest/m1/README.md index ea892bbbde5..f58a13da0fd 100644 --- a/quest/m1/README.md +++ b/quest/m1/README.md @@ -151,7 +151,6 @@ Catalog HLS field. - [Main is no slower than release](/quest/m1/release-perf/README.md) - every benchmark where main is slower than release is fixed or accepted with a reason, checked by a final paired run before the cut - [Drop announce="never"](/quest/m1/publish-announce-never.md) - `@moq/publish` offers only announce modes a watcher can reach - [Drop unused OBS outputs](/quest/m1/obs-output-variants.md) - the plugin registers only `moq_output`, so the broken audio-only variant is gone -- [API-diff check](/quest/m1/api-diff.md) - a recipe diffs every published package's API against its last release, run on PRs into release and against main before the cut - [API Extractor checks](/quest/m1/api-extractor-checks.md) - API Extractor fails a PR on a forgotten export, an unresolved declaration, or an undocumented export, replacing the hand-rolled `.d.ts` checkers - [Generated JS API reference](/quest/m1/js-api-reference.md) - the doc site renders an API reference for every `@moq/*` package from API Extractor's doc model - [IETF lazy discovery](/quest/m1/ietf-lazy-discovery.md) - JS moq-transport sessions never hold overlapping SUBSCRIBE_NAMESPACE requests at a peer that refuses them diff --git a/quest/m1/api-audit/README.md b/quest/m1/api-audit/README.md index 5d781658438..b769c05cb39 100644 --- a/quest/m1/api-audit/README.md +++ b/quest/m1/api-audit/README.md @@ -79,5 +79,4 @@ Rejected in planning: ## Related -- [API-diff check on release PRs](/quest/m1/api-diff.md) - the backstop that catches breaks this epic misses - [Main is no slower than release](/quest/m1/release-perf/README.md) - the other release-readiness check diff --git a/quest/m1/api-diff.md b/quest/m1/api-diff.md deleted file mode 100644 index 2d8483b59c0..00000000000 --- a/quest/m1/api-diff.md +++ /dev/null @@ -1,44 +0,0 @@ -# [L] API-diff check on release PRs - -## Goal - -A `just` recipe diffs each published package's public API against its last -published version, and every PR into `release` runs it. A backport fails on -any break; the breaking cut PR reports the diff for the -[migration audit](/quest/m2/release/migrate-audit.md). - -## Plan - -Decided 2026-10-16 (maintainer interview), split out of the migration audit -and moved to m1 on 2026-10-22 (maintainer, from an external API audit) so -the report runs locally against `main` while m1's breaks are still landing, -instead of first appearing at the cut: - -- Commit `!` markers undercount: a 2026-10-16 sample estimated 12-15 - unmarked breaks on top of 87 marked ones, a floor since signature-only - changes escape the heuristic. This check is the backstop; PRs into `main` - get no CI check. -- Runs on PRs into `release` only: backports must keep the published API - (CONTRIBUTING), and the cut PR gets a full audit. -- Backports fail on any detected break. The cut PR only reports: Rust - versions are bumped by release-plz after the cut lands, so the diff cannot - gate on a version bump there. -- One `just` recipe, three backends: cargo-semver-checks for Rust crates, - emitted `.d.ts` API reports for `@moq/*` packages, and a `moq.h` plus - UniFFI interface diff for the bindings. Prefer maintained tools over - hand-rolled diffing. Wire it into the workflow that runs on PRs into - `release`. -- Baseline is the last published artifact, not a git tag: `@moq/*` and - `moq-rs` publish without tags. Rust compares against crates.io - (cargo-semver-checks' default), JS against the npm tarball's declarations, - and the FFI interfaces against the published `moq-ffi` crate and the last - released C archive's `moq.h`. -- Coverage: the report covers Rust crates, `@moq/*` declarations, and the - generated FFI interfaces. A break only in a hand-written binding wrapper - (`py/moq-rs`, `kt/moq`, `dart/moq`, `go/wrapper`, `swift`, `cpp/moq`, - `cpp/obs`) or a binary's flags, env vars, or config keys escapes it; the - migration audit reads those by hand. Per-language wrapper checks are out - of scope until a missed break shows they are needed. - -Run it against `main` when it lands and put the unmarked breaks it finds in -the PR description, so the migration audit covers them at the cut. diff --git a/quest/m1/api-extractor-checks.md b/quest/m1/api-extractor-checks.md index 0cd20afe74f..ae90218cd1a 100644 --- a/quest/m1/api-extractor-checks.md +++ b/quest/m1/api-extractor-checks.md @@ -12,11 +12,14 @@ item without a doc comment (`ae-undocumented`) fail the build. Decided 2026-10-23 (maintainer interview): -- Builds on the per-package API Extractor config and committed `.api.md` - reports that [the API-diff check](/quest/m1/api-diff.md) adds - ([moq-dev/moq#6477](https://github.com/moq-dev/moq/pull/6477)). One config - serves the reports, these checks, and the - [reference](/quest/m1/js-api-reference.md); do not add a second. +- Builds on the shared API Extractor config in `js/common/api.ts` and the + committed `.api.md` reports that + [moq-dev/moq#6477](https://github.com/moq-dev/moq/pull/6477) added. One + config serves the reports, these checks, and the + [reference](/quest/m1/js-api-reference.md); do not add a second. It + analyzes a copy of `dist/` with no `node_modules`, so a package's report + never depends on its dependencies being built, and silences every message + for now. - Keep only the rules API Extractor enforces. A `docs.ts` rule with no API Extractor equivalent is dropped, not kept in a reduced checker. - JSR reads `@module` blocks, so define `@module` in `tsdoc.json` instead of @@ -30,10 +33,6 @@ Decided 2026-10-23 (maintainer interview): and dropping an export's doc comment must each fail `just check`. - Rust is a non-goal: docs.rs and cargo-semver-checks cover it. -## Required - -- [API-diff check](/quest/m1/api-diff.md) - adds the shared config and committed reports these checks extend - ## Related - [Generated JS API reference](/quest/m1/js-api-reference.md) - renders the doc model from the same config diff --git a/quest/m2/release/api-review.md b/quest/m2/release/api-review.md index e07bf477094..7a023705dcf 100644 --- a/quest/m2/release/api-review.md +++ b/quest/m2/release/api-review.md @@ -18,7 +18,7 @@ Only `/quest-delete` ends the recurrence. Starts once m1 lands, so the APIs it reviews are the ones that ship; the cut waits for it. API shape is the maintainer's call (decided 2026-10-19), so this run changes no code. Inventory the diff against the last published version -by running the [API-diff check](/quest/m1/api-diff.md)'s recipe +by running `just api-diff` locally against `main`, since its CI report only appears on the cut PR, and hand diff the surfaces it cannot see. For each export that is awkward, judge it against AGENTS.md's Public API rules: names mirrored across languages, no @@ -31,4 +31,3 @@ moq-net exposes; this review judges the shape of what ships. ## Required - [Breaking release readiness](/quest/m1/README.md) - the release's code is final before it is reviewed -- [API-diff check](/quest/m1/api-diff.md) - the recipe that inventories every public API change diff --git a/quest/m2/release/migrate-audit.md b/quest/m2/release/migrate-audit.md index 061b5f1ba80..a008ca05c8f 100644 --- a/quest/m2/release/migrate-audit.md +++ b/quest/m2/release/migrate-audit.md @@ -3,7 +3,7 @@ ## Goal Before the breaking cut merges, every break it ships, including those in -surfaces the [API-diff check](/quest/m1/api-diff.md) cannot see, has its +surfaces `just api-diff` cannot see, has its `MIGRATE.md` entry, and each entry states the net change from the last published version. @@ -43,5 +43,4 @@ m1 quest on 2026-10-22. ## Required -- [API-diff check](/quest/m1/api-diff.md) - the report this audit reads - [Breaking release readiness](/quest/m1/README.md) - all breaking work and the MIGRATE.md convention have landed diff --git a/sh/api-diff/ffi.sh b/sh/api-diff/ffi.sh new file mode 100755 index 00000000000..ba96d493e78 --- /dev/null +++ b/sh/api-diff/ffi.sh @@ -0,0 +1,76 @@ +#!/usr/bin/env bash +# Write the FFI interfaces of the last release and of this checkout as headers, +# so sh/api-diff/run.sh can diff them. usage: sh/api-diff/ffi.sh +# +# - moq.h: the C header, from the newest `moq-c-v*` (formerly `libmoq-v*`) +# release archive, and from moq-c's build script here. +# - moq-ffi.hpp: the UniFFI surface every binding is generated from, rendered as +# the C++ header uniffi-bindgen-cpp writes for it, which declares each exported +# item with its full signature. The baseline comes from the newest `moq-ffi-v*` +# release's Linux library, which carries the UniFFI metadata. +# +# The preprocessor strips comments from both, so a doc edit is not a change. +# /surfaces.tsv lists each surface, its baseline version, and its file. +set -euo pipefail + +out=${1:?usage: sh/api-diff/ffi.sh } +cd "$(git rev-parse --show-toplevel)" +mkdir -p "$out/baseline" "$out/current" +work=$(mktemp -d) +trap 'rm -rf "$work"' EXIT + +# The newest release tag matching a pattern; `gh release list` sorts newest first. +latest() { + gh release list --repo moq-dev/moq --limit 1000 --json tagName --jq "[.[].tagName | select(test(\"$1\"))][0] // empty" +} + +# Strip comments without expanding includes or macros. Only GCC can: Clang has +# no -fpreprocessed, and is what `cc` and even `gcc` name on macOS. +gcc --version 2>/dev/null | grep -q 'Free Software Foundation' || { + echo "api-diff: the FFI diff needs GCC to strip header comments; run \`just api-diff rust js\` without it" >&2 + exit 1 +} +strip() { + gcc -x "$1" -fpreprocessed -dD -E -P -w "$2" -o "$3" +} + +c_tag=$(latest '^(moq-c|libmoq)-v') +ffi_tag=$(latest '^moq-ffi-v') +if [[ -z "$c_tag" || -z "$ffi_tag" ]]; then + echo "no moq-c or moq-ffi release found" >&2 + exit 1 +fi + +# The header is the same in every archive; take the Linux x86_64 one. +gh release download "$c_tag" --repo moq-dev/moq --pattern '*-x86_64-unknown-linux-gnu.tar.gz' --dir "$work/c" +tar -xzf "$work"/c/*.tar.gz -C "$work/c" --wildcards '*/include/moq.h' +strip c "$work"/c/*/include/moq.h "$out/baseline/moq.h" + +# moq-c's build script writes the header into its OUT_DIR, which `cargo check` runs. +c_out=$(cargo check --locked -p moq-c --message-format=json | + jq -r 'select(.reason == "build-script-executed") | select(.package_id | test("/moq-c#")) | .out_dir' | tail -1) +if [[ -z "$c_out" || ! -f "$c_out/include/moq.h" ]]; then + echo "cargo check -p moq-c wrote no moq.h" >&2 + exit 1 +fi +strip c "$c_out/include/moq.h" "$out/current/moq.h" + +# uniffi-bindgen-cpp reads the metadata from a library for any target, so the +# x86_64 release library works on any host. +gh release download "$ffi_tag" --repo moq-dev/moq --pattern '*-x86_64-unknown-linux-gnu-libmoq_ffi.so' --output "$work/libmoq_ffi.so" +lib=$(cargo build --locked -p moq-ffi --lib --message-format=json | + jq -r 'select(.reason == "compiler-artifact" and .target.name == "moq_ffi") | .filenames[] | select(test("\\.(so|dylib)$"))' | tail -1) +if [[ -z "$lib" ]]; then + echo "cargo build -p moq-ffi produced no shared library" >&2 + exit 1 +fi + +for side in baseline current; do + source=$work/libmoq_ffi.so + [[ "$side" == baseline ]] || source=$lib + uniffi-bindgen-cpp --library "$source" --config cpp/moq/uniffi.toml --out-dir "$work/cpp-$side" >&2 + # Named after the UniFFI namespace; the other headers are generator plumbing. + strip c++ "$work/cpp-$side/moq.hpp" "$out/$side/moq-ffi.hpp" +done + +printf 'moq.h\t%s\tmoq.h\nmoq-ffi (UniFFI)\t%s\tmoq-ffi.hpp\n' "${c_tag##*-v}" "${ffi_tag##*-v}" >"$out/surfaces.tsv" diff --git a/sh/api-diff/run.sh b/sh/api-diff/run.sh new file mode 100755 index 00000000000..1a795fde8a8 --- /dev/null +++ b/sh/api-diff/run.sh @@ -0,0 +1,270 @@ +#!/usr/bin/env bash +# Diff every published package's public API against its last release: Rust +# crates through cargo-semver-checks against crates.io, `@moq/*` packages +# through their committed API Extractor reports against `release`'s (or +# API_DIFF_BASE's), and the FFI interfaces (`moq.h` and moq-ffi's UniFFI +# surface) as headers against the released archives. Writes +# target/api-diff/report.md and prints it. +# +# usage: sh/api-diff/run.sh [--deny] [rust|js|ffi]... +# +# --deny exits 1 on any break, for backports into `release`. Without it the run +# only reports, as the cut PR does: release-plz bumps Rust versions after the cut +# lands, so a break there is expected and needs a MIGRATE.md entry instead. +# For JS and FFI, a removed or changed line is a break, and so is a line added +# inside an existing declaration; only new declarations are additions. +set -euo pipefail + +usage="usage: sh/api-diff/run.sh [--deny] [rust|js|ffi]..." +deny= +backends=() +for arg in "$@"; do + case "$arg" in + --deny) deny=1 ;; + rust | js | ffi) backends+=("$arg") ;; + *) + echo "$usage" >&2 + exit 2 + ;; + esac +done +((${#backends[@]})) || backends=(rust js ffi) + +cd "$(git rev-parse --show-toplevel)" +root=$PWD +out=$root/target/api-diff +base=${API_DIFF_BASE:-origin/release} +rm -rf "$out" +mkdir -p "$out" + +summary=$out/summary.md +details=$out/details.md +printf '| Surface | Baseline | Result |\n| --- | --- | --- |\n' >"$summary" +: >"$details" + +# Record one surface's row, and its diff when it changed. +row() { + local surface=$1 baseline=$2 result=$3 body=${4:-} lang=${5:-diff} + printf '| %s | %s | %s |\n' "$surface" "$baseline" "$result" >>"$summary" + [[ -n "$body" ]] || return 0 + printf '\n### %s\n\n%s%s\n%s\n%s\n' "$surface" '````' "$lang" "$body" '````' >>"$details" +} + +# Whether a full-context diff on stdin breaks the baseline: it removes a line, +# which includes changing one, or adds a line inside a declaration the baseline +# has, such as a required field on an input interface or a C struct, since a line +# diff cannot tell which of those break callers. A line's declaration is the +# nearest line above it indented less, so only whole new declarations are +# additions. +breaks() { + awk ' + /^(@@|\\)/ { next } + { mark = substr($0, 1, 1); line = substr($0, 2) } + mark == "-" { broke = 1; exit } + line ~ /^[[:space:]]*$/ { next } + { + match(line, /^[[:space:]]*/) + while (depth && indent[depth] >= RLENGTH) depth-- + if (mark == "+" && depth && parent[depth] == " ") { broke = 1; exit } + indent[++depth] = RLENGTH + parent[depth] = mark + } + END { exit !broke }' +} + +# Diff a baseline file against its current one, as a break, additions, or unchanged. +compare() { + local surface=$1 baseline=$2 old=$3 new=$4 body full + if [[ ! -f "$new" ]]; then + row "$surface" "$baseline" break "(removed)" + return + fi + if [[ ! -f "$old" ]]; then + row "$surface" "$baseline" new + return + fi + # Exit 1 means the files differ; anything above that is an error. + body=$(git diff --no-index --no-color --no-prefix -U3 "$old" "$new" | tail -n +5) || [[ $? == 1 ]] + # The whole file as context, so every added line has its declaration above it. + full=$(git diff --no-index --no-color -U"$(($(wc -l <"$old") + $(wc -l <"$new")))" "$old" "$new" | tail -n +5) || [[ $? == 1 ]] + if [[ -z "$body" ]]; then + row "$surface" "$baseline" unchanged + elif breaks <<<"$full"; then + row "$surface" "$baseline" break "$body" + else + row "$surface" "$baseline" additions "$body" + fi +} + +# cargo-semver-checks over every published library crate, against its newest +# crates.io release, with every feature on. `--release-type minor` holds every +# crate to "no breaking change" whatever its version says, since the versions +# are bumped only after a cut. +# +# Both sides are documented as rustdoc JSON in one build each, sharing their +# dependencies: cargo-semver-checks would otherwise build each crate, baseline +# and current, in a workspace of its own and compile the dependencies again. +rust() { + local name kinds lib id path index version features status log target + local crates=() libs=() versions=() current=() baseline=() + local -A released=() + local manifest=$out/rust/baseline/Cargo.toml + mkdir -p "$out/rust/baseline/src" + : >"$out/rust/baseline/src/lib.rs" + # Its own workspace, so the repository's does not claim it. + printf '[package]\nname = "api-diff-baseline"\nversion = "0.0.0"\nedition = "2024"\npublish = false\n\n[workspace]\n\n[dependencies]\n' >"$manifest" + + # Each metadata query is captured before it is read, since a process + # substitution's failure would not stop the run and would leave crates unchecked. + local packages + packages=$(cargo metadata --locked --no-deps --format-version 1 | + jq -r '.packages[] | select(.publish != []) | + "\(.name) \([.targets[].kind[]] | unique | join(",")) \([.targets[] | select(.kind | index("lib") or index("rlib")) | .name][0] // "-") \(.id)"') + while read -r name kinds lib id; do + # A binary or a C library has no Rust API; moq-c and moq-ffi are diffed as FFI. + [[ ",$kinds," == *,lib,* || ",$kinds," == *,rlib,* ]] || continue + # The sparse index shards names by length: 3/k/kio, ha/ng/hang. + case ${#name} in + 1 | 2) path=${#name}/$name ;; + 3) path=3/${name:0:1}/$name ;; + *) path=${name:0:2}/${name:2:2}/$name ;; + esac + index=$out/rust/$name.index + status=$(curl -sS -o "$index" -w '%{http_code}' "https://index.crates.io/$path") + case "$status" in + 200) ;; + 404) + row "$name" unpublished new + continue + ;; + *) + echo "crates.io index returned $status for $name" >&2 + exit 1 + ;; + esac + # The highest release that is neither yanked nor a pre-release, and its features. + version=$(jq -rs '[.[] | select((.yanked | not) and (.vers | contains("-") | not))] + | max_by(.vers | split(".") | map(tonumber)) | .vers' "$index") + features=$(jq -cs --arg v "$version" '.[] | select(.vers == $v) | (.features // {}) + (.features2 // {}) | keys' "$index") + printf '%s = { version = "=%s", features = %s }\n' "$name" "$version" "$features" >>"$manifest" + crates+=("$name") + libs+=("$lib") + versions+=("$version") + current+=(-p "$id") + done <<<"$packages" + + # The baseline resolves its own lockfile, as a consumer of those releases + # would. A release without a library, or with another name for it, shows here. + packages=$(cargo metadata --manifest-path "$manifest" --format-version 1 | + jq -r '.packages[] | select(.source != null) | + "\(.name) \(.version) \([.targets[] | select(.kind | index("lib") or index("rlib")) | .name][0] // "-")"') + while read -r name version lib; do + released["$name $version"]=$lib + done <<<"$packages" + for i in "${!crates[@]}"; do + if [[ "${released["${crates[$i]} ${versions[$i]}"]:--}" == - ]]; then + row "${crates[$i]}" "${versions[$i]} (no library)" new + unset "crates[$i]" + else + baseline+=(-p "${crates[$i]}@${versions[$i]}") + fi + done + + export RUSTC_BOOTSTRAP=1 RUSTDOCFLAGS="-Z unstable-options --output-format json" + target=$(cargo metadata --locked --no-deps --format-version 1 | jq -r .target_directory) + cargo doc --locked --no-deps --all-features "${current[@]}" + CARGO_TARGET_DIR=$target/api-diff-baseline cargo doc --manifest-path "$manifest" --no-deps "${baseline[@]}" + unset RUSTC_BOOTSTRAP RUSTDOCFLAGS + + for i in "${!crates[@]}"; do + name=${crates[$i]} + lib=${released["$name ${versions[$i]}"]} + log=$out/rust/$name.log + status=0 + cargo semver-checks check-release --color never --release-type minor -p "$name" \ + --baseline-rustdoc "$target/api-diff-baseline/doc/${lib//-/_}.json" \ + --current-rustdoc "$target/doc/${libs[$i]//-/_}.json" >"$log" 2>&1 || status=$? + case "$status" in + 0) row "$name" "${versions[$i]}" unchanged ;; + # Keep each failed lint's title and the items it failed on, with + # paths relative to the checkout or the crates.io source. + 100) + row "$name" "${versions[$i]}" break "$(grep -vE '^ *(Parsing|Parsed|Checked|Finished) ' "$log" | + sed -E "/^Description:$/,/^ +impl: /d; s|$root/||g; s|[^ ]*/registry/src/[^/]+/||g")" text + ;; + *) + cat "$log" >&2 + echo "cargo semver-checks failed on $name with exit code $status" >&2 + exit 1 + ;; + esac + done +} + +# Each published `@moq/*` package's committed API Extractor reports against the +# base branch's. The build checks the reports against the code on every PR, so +# neither side is rebuilt here. +js() { + git rev-parse --verify --quiet "$base^{commit}" >/dev/null || { + echo "api-diff: $base does not exist; fetch it or set API_DIFF_BASE" >&2 + exit 1 + } + local manifest dir name version file entry surface + for manifest in js/*/package.json; do + jq -e .scripts.release "$manifest" >/dev/null || continue + dir=${manifest%/package.json} + name=$(jq -r .name "$manifest") + version=$(git show "$base:$manifest" 2>/dev/null | jq -r .version) || version=- + mkdir -p "$out/js/$name" + while read -r file; do + git show "$base:$dir/api/$file" >"$out/js/$name/$file" + done < <(git ls-tree --name-only "$base" "$dir/api/" | sed 's|.*/||') + while read -r file; do + entry=${file%.api.md} + surface=$name/$entry + [[ "$entry" != index ]] || surface=$name + compare "$surface" "$version" "$out/js/$name/$file" "$dir/api/$file" + done < <(find "$out/js/$name" "$dir/api" -name '*.api.md' -printf '%f\n' 2>/dev/null | sort -u) + done +} + +ffi() { + sh/api-diff/ffi.sh "$out/ffi" + local surface baseline file + while IFS=$'\t' read -r surface baseline file; do + compare "$surface" "$baseline" "$out/ffi/baseline/$file" "$out/ffi/current/$file" + done <"$out/ffi/surfaces.tsv" +} + +for backend in "${backends[@]}"; do + echo "api-diff: $backend" >&2 + "$backend" +done + +{ + echo "# Public API diff" + echo + echo "Each surface against its last published release. A break needs a MIGRATE.md entry; a backport must have none." + echo + cat "$summary" + if [[ -s "$details" ]]; then + echo + echo "## Changes" + cat "$details" + fi +} >"$out/report.md" +cat "$out/report.md" + +if [[ -n "${GITHUB_STEP_SUMMARY:-}" ]]; then + # The job summary holds 1 MiB; a cut's full report can exceed it. + if (($(wc -c <"$out/report.md") < 1000000)); then + cat "$out/report.md" >>"$GITHUB_STEP_SUMMARY" + else + { cat "$summary" && echo && echo "The full report is in the api-diff artifact."; } >>"$GITHUB_STEP_SUMMARY" + fi +fi + +if [[ -n "$deny" ]] && grep -q '| break |$' "$summary"; then + echo "api-diff: a published API changed; backports must keep it" >&2 + exit 1 +fi diff --git a/sh/dispatch.sh b/sh/dispatch.sh index 8fd3e3f106f..74ed2c15271 100755 --- a/sh/dispatch.sh +++ b/sh/dispatch.sh @@ -311,6 +311,7 @@ step() { test:py) just py test ;; test:gh) just gh test ;; fix:rs) just rs fix-changed "$rs_list" ;; + fix:js) just js fix "$js_list" ;; fix:markdown) bun install sh/markdown.sh fix diff --git a/sh/gh/queue.test.ts b/sh/gh/queue.test.ts index 1dea03014dd..1cbb943fe55 100644 --- a/sh/gh/queue.test.ts +++ b/sh/gh/queue.test.ts @@ -69,6 +69,7 @@ for (const [id, job] of calls) { // Every workflow that used to run on release PRs blocks a release now. assert.deepEqual(calls.map(([id]) => id).sort(), [ "android", + "api-diff", "audio-quality", "cpp", "features",